Merge branch 'upstream' into debian
authorBdale Garbee <bdale@gag.com>
Sun, 16 Sep 2012 22:28:51 +0000 (16:28 -0600)
committerBdale Garbee <bdale@gag.com>
Sun, 16 Sep 2012 22:28:51 +0000 (16:28 -0600)
1658 files changed:
android-libraries/ActionBarSherlock/.classpath [new file with mode: 0644]
android-libraries/ActionBarSherlock/.project [new file with mode: 0644]
android-libraries/ActionBarSherlock/AndroidManifest.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/actionbarsherlock.jar [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$Implementation.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnActionModeFinishedListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnActionModeStartedListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnCreateOptionsMenuListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnCreatePanelMenuListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnMenuItemSelectedListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnOptionsItemSelectedListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnPrepareOptionsMenuListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnPreparePanelListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/BuildConfig.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$attr.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$bool.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$color.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$dimen.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$drawable.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$id.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$integer.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$layout.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$string.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$style.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$styleable.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$LayoutParams.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$OnMenuVisibilityListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$OnNavigationListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$Tab.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$TabListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockActivity.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockDialogFragment.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockExpandableListActivity.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockFragment.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockFragmentActivity.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockListActivity.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockListFragment.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockPreferenceActivity.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat$ActionModeCallbackWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeCallbackWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ResourcesCompat.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$2.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$ActionModeImpl.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$TabImpl.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarWrapper$TabWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Animator$AnimatorListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$AnimatorSetListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Builder.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Dependency.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$DependencyListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Node.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$FloatKeyframe.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$IntKeyframe.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$ObjectKeyframe.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder$FloatPropertyValuesHolder.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder$IntPropertyValuesHolder.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$2.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$3.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$4.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$5.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$AnimationHandler.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$AnimatorUpdateListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/ActionProviderWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/StandaloneActionMode.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenu.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItem.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$ActionButtonSubmenu.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$HasPermanentMenuKey.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OpenOverflowRunnable.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OverflowMenuButton.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OverflowPopup.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$PopupPresenterCallback.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$SavedState$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$SavedState.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView$ActionMenuChildView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView$LayoutParams.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ListMenuItemView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder$Callback.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder$ItemInvoker.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemImpl.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper$ExpandedIndexObserver.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper$MenuAdapter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPresenter$Callback.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPresenter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuView$ItemView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView$VisibilityAnimListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContainer.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContextView$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContextView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$2.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$3.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$ExpandedActionViewMenuPresenter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$HomeView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$SavedState$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$SavedState.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/CapitalizingButton.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/CapitalizingTextView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$RecycleBin.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$SavedState$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$SavedState.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$AdapterContextMenuInfo.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$AdapterDataSetObserver.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$OnItemLongClickListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$OnItemSelectedListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$SelectionNotifier.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsLinearLayout.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$DropDownListView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$ListSelectorHider.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupDataSetObserver.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupScrollListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupTouchInterceptor.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$ResizePopupRunnable.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$AccessibilityEventSender.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$RefreshProgressRunnable.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$SavedState$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$SavedState.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropDownAdapter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropdownPopup$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropdownPopup.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$SpinnerPopup.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabAdapter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabClickListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$VisibilityAnimListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionMode$Callback.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionMode.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionProvider$SubUiVisibilityListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionProvider.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/CollapsibleActionView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Menu.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater$InflatedOnMenuItemClickListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater$MenuState.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem$OnActionExpandListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem$OnMenuItemClickListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/SubMenu.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Window$Callback.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Window.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivityChooserModelClient.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivityResolveInfo.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivitySorter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$DefaultSorter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoricalRecord.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryLoader$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryLoader.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryPersister.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$OnChooseActivityListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$SerialExecutor$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$SerialExecutor.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$1.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$2.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$3.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$ActivityChooserViewAdapter.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$Callbacks.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$SetActivated.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$OnShareTargetSelectedListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$ShareAcitivityChooserModelPolicy.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider.class [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/jarlist.cache [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__dialog_full_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_ab_back_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_cab_done_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_share_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_activated_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_divider_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_divider_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_longpressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_selector_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_selector_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_bg_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_primary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_48_inner_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_48_outer_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_unselected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__dialog_full_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_ab_back_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_cab_done_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_share_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_activated_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_divider_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_divider_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_longpressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_selector_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_selector_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_bg_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_primary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_48_inner_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_48_outer_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_activated_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_divider_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_longpressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_48_inner_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_48_outer_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/gen/com/actionbarsherlock/BuildConfig.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/gen/com/actionbarsherlock/R.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/libs/android-support-v4.jar [new file with mode: 0644]
android-libraries/ActionBarSherlock/proguard-project.txt [new file with mode: 0644]
android-libraries/ActionBarSherlock/project.properties [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/color/abs__primary_text_disable_only_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/color/abs__primary_text_disable_only_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/color/abs__primary_text_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/color/abs__primary_text_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__dialog_full_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_ab_back_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_cab_done_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_share_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_activated_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_divider_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_divider_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_longpressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_selector_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_selector_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_bg_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_primary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_48_inner_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_48_outer_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_unselected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__dialog_full_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_ab_back_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_cab_done_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_share_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_activated_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_divider_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_divider_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_longpressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_selector_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_selector_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_bg_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_primary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_48_inner_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_48_outer_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-v11/abs__progress_medium_holo.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_activated_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_divider_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_longpressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_48_inner_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_48_outer_holo.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable-xhdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__activated_background_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__activated_background_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__btn_cab_done_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__btn_cab_done_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__ic_menu_moreoverflow_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__ic_menu_moreoverflow_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__item_background_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__item_background_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_background_transition_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_background_transition_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__progress_horizontal_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__progress_horizontal_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__progress_medium_holo.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__spinner_ab_holo_dark.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__spinner_ab_holo_light.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/drawable/abs__tab_indicator_ab_holo.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout-large/abs__action_mode_close_item.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout-v14/sherlock_spinner_dropdown_item.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout-v14/sherlock_spinner_item.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout-xlarge/abs__screen_action_bar.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout-xlarge/abs__screen_action_bar_overlay.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__action_bar_home.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__action_bar_tab.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__action_bar_tab_bar_view.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__action_bar_title_item.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__action_menu_item_layout.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__action_menu_layout.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__action_mode_bar.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__action_mode_close_item.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__activity_chooser_view.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__activity_chooser_view_list_item.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__dialog_title_holo.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_checkbox.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_icon.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_layout.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_radio.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__popup_menu_item_layout.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__screen_action_bar.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__screen_action_bar_overlay.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__screen_simple.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/abs__screen_simple_overlay_action_mode.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/main.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/sherlock_spinner_dropdown_item.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/layout/sherlock_spinner_item.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-land/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-large-hdpi-1024x600/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-large-land-hdpi-1024x600/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-large-land-mdpi-1024x600/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-large-mdpi-1024x600/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-large/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-sw600dp/abs__bools.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-sw600dp/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-v11/abs__themes.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-v14/abs__styles.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-v14/abs__themes.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-w360dp/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-w480dp/abs__bools.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-w480dp/abs__config.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-w500dp/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-w600dp/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values-xlarge/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__attrs.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__bools.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__colors.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__config.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__dimens.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__ids.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__strings.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__styles.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/abs__themes.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/res/values/strings.xml [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/android/support/v4/app/_ActionBarSherlockTrojanHorse.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/ActionBarSherlock.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/ActionBar.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockActivity.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockDialogFragment.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockExpandableListActivity.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockFragment.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockFragmentActivity.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockListActivity.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockListFragment.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockPreferenceActivity.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ResourcesCompat.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/ActionProviderWrapper.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/StandaloneActionMode.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenu.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuItem.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ListMenuItemView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuBuilder.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemImpl.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuPresenter.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuWrapper.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/AbsActionBarView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarContainer.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/CapitalizingButton.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsAbsSpinner.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsProgressBar.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsSpinner.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/ActionMode.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/ActionProvider.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/CollapsibleActionView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/Menu.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/MenuInflater.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/MenuItem.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/SubMenu.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/Window.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ActivityChooserModel.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java [new file with mode: 0644]
android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ShareActionProvider.java [new file with mode: 0644]
android-libraries/TreeViewList/.classpath [new file with mode: 0644]
android-libraries/TreeViewList/.project [new file with mode: 0644]
android-libraries/TreeViewList/AndroidManifest.xml [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/AbstractTreeViewAdapter$1.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/AbstractTreeViewAdapter.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/BuildConfig.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/InMemoryTreeNode.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/InMemoryTreeStateManager.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/NodeAlreadyInTreeException.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/NodeNotInTreeException.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$attr.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$drawable.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$id.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$layout.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$style.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$styleable.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeBuilder.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeConfigurationException.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeNodeInfo.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeStateManager.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeViewList$1.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeViewList.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/overview.html [new file with mode: 0644]
android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/package-info.class [new file with mode: 0644]
android-libraries/TreeViewList/bin/jarlist.cache [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-hdpi/collapsed.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-hdpi/expanded.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-ldpi/collapsed.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-ldpi/expanded.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-mdpi/collapsed.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-mdpi/expanded.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable/list_selector_background_disabled.9.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable/list_selector_background_focus.9.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable/list_selector_background_longpress.9.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/res/drawable/list_selector_background_pressed.9.png [new file with mode: 0644]
android-libraries/TreeViewList/bin/treeviewlist.jar [new file with mode: 0644]
android-libraries/TreeViewList/gen/pl/polidea/treeview/BuildConfig.java [new file with mode: 0644]
android-libraries/TreeViewList/gen/pl/polidea/treeview/R.java [new file with mode: 0644]
android-libraries/TreeViewList/proguard.cfg [new file with mode: 0644]
android-libraries/TreeViewList/project.properties [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-hdpi/collapsed.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-hdpi/expanded.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-ldpi/collapsed.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-ldpi/expanded.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-mdpi/collapsed.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-mdpi/expanded.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable/divider.xml [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable/list_selector_background.xml [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable/list_selector_background_disabled.9.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable/list_selector_background_focus.9.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable/list_selector_background_longpress.9.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable/list_selector_background_pressed.9.png [new file with mode: 0644]
android-libraries/TreeViewList/res/drawable/list_selector_background_transition.xml [new file with mode: 0644]
android-libraries/TreeViewList/res/layout/tree_list_item_wrapper.xml [new file with mode: 0644]
android-libraries/TreeViewList/res/values/attrs.xml [new file with mode: 0644]
android-libraries/TreeViewList/res/values/styles.xml [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/AbstractTreeViewAdapter.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/InMemoryTreeNode.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/InMemoryTreeStateManager.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/NodeAlreadyInTreeException.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/NodeNotInTreeException.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/TreeBuilder.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/TreeConfigurationException.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/TreeNodeInfo.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/TreeStateManager.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/TreeViewList.java [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/overview.html [new file with mode: 0644]
android-libraries/TreeViewList/src/pl/polidea/treeview/package-info.java [new file with mode: 0644]
android-libraries/achartengine/.classpath [new file with mode: 0644]
android-libraries/achartengine/.project [new file with mode: 0644]
android-libraries/achartengine/AndroidManifest.xml [new file with mode: 0644]
android-libraries/achartengine/extra/LICENSE-2.0.txt [new file with mode: 0644]
android-libraries/achartengine/project.properties [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/ChartFactory.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/GraphicalActivity.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/GraphicalView.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/ITouchHandler.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/TouchHandler.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/TouchHandlerOld.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/AbstractChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/BarChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/BubbleChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/ClickableArea.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/CombinedXYChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/CubicLineChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/DialChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/DoughnutChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/LineChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/PieChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/PieMapper.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/PieSegment.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/PointStyle.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/RangeBarChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/RangeStackedBarChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/RoundChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/ScatterChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/TimeChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/XYChart.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/chart/package.html [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/image/zoom-1.png [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/image/zoom_in.png [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/image/zoom_out.png [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/CategorySeries.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/MultipleCategorySeries.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/Point.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/RangeCategorySeries.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/SeriesSelection.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/TimeSeries.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/XYMultipleSeriesDataset.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/XYSeries.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/XYValueSeries.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/model/package.html [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/package.html [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/renderer/BasicStroke.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/renderer/DefaultRenderer.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/renderer/DialRenderer.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/renderer/SimpleSeriesRenderer.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/renderer/XYMultipleSeriesRenderer.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/renderer/XYSeriesRenderer.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/renderer/package.html [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/tools/AbstractTool.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/tools/FitZoom.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/tools/Pan.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/tools/PanListener.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/tools/Zoom.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/tools/ZoomEvent.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/tools/ZoomListener.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/util/IndexXYMap.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/util/MathHelper.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/util/XYEntry.java [new file with mode: 0644]
android-libraries/achartengine/src/org/achartengine/util/package.html [new file with mode: 0644]
android/.classpath
android/AndroidManifest.xml
android/project.properties
android/res/drawable-hdpi/actionbar_shadow.9.png [deleted file]
android/res/drawable-hdpi/collapsed.png [deleted file]
android/res/drawable-hdpi/expanded.png [deleted file]
android/res/drawable-hdpi/ic_menu_add.png [new file with mode: 0644]
android/res/drawable-hdpi/ic_menu_archive.png [new file with mode: 0644]
android/res/drawable-hdpi/ic_menu_info_details.png [new file with mode: 0644]
android/res/drawable-hdpi/ic_menu_preferences.png [new file with mode: 0644]
android/res/drawable-hdpi/ic_menu_save.png [new file with mode: 0644]
android/res/drawable-hdpi/ic_menu_search.png [new file with mode: 0644]
android/res/drawable-hdpi/or_launcher.png [new file with mode: 0644]
android/res/drawable-ldpi/collapsed.png [deleted file]
android/res/drawable-ldpi/expanded.png [deleted file]
android/res/drawable-ldpi/ic_menu_add.png [new file with mode: 0644]
android/res/drawable-ldpi/ic_menu_archive.png [new file with mode: 0644]
android/res/drawable-ldpi/ic_menu_info_details.png [new file with mode: 0644]
android/res/drawable-ldpi/ic_menu_preferences.png [new file with mode: 0644]
android/res/drawable-ldpi/ic_menu_save.png [new file with mode: 0644]
android/res/drawable-ldpi/ic_menu_search.png [new file with mode: 0644]
android/res/drawable-ldpi/or_launcher.png [new file with mode: 0644]
android/res/drawable-mdpi/actionbar_shadow.9.png [deleted file]
android/res/drawable-mdpi/collapsed.png [deleted file]
android/res/drawable-mdpi/expanded.png [deleted file]
android/res/drawable-mdpi/ic_home_carat.png [deleted file]
android/res/drawable-mdpi/ic_menu_add.png [new file with mode: 0644]
android/res/drawable-mdpi/ic_menu_archive.png [new file with mode: 0644]
android/res/drawable-mdpi/ic_menu_info_details.png [new file with mode: 0644]
android/res/drawable-mdpi/ic_menu_preferences.png [new file with mode: 0644]
android/res/drawable-mdpi/ic_menu_save.png [new file with mode: 0644]
android/res/drawable-mdpi/ic_menu_search.png [new file with mode: 0644]
android/res/drawable-mdpi/or_launcher.png
android/res/drawable-xhdpi/actionbar_shadow.9.png [deleted file]
android/res/drawable-xhdpi/ic_menu_add.png [new file with mode: 0644]
android/res/drawable-xhdpi/ic_menu_archive.png [new file with mode: 0644]
android/res/drawable-xhdpi/ic_menu_info_details.png [new file with mode: 0644]
android/res/drawable-xhdpi/ic_menu_preferences.png [new file with mode: 0644]
android/res/drawable-xhdpi/ic_menu_save.png [new file with mode: 0644]
android/res/drawable-xhdpi/ic_menu_search.png [new file with mode: 0644]
android/res/drawable-xhdpi/or_launcher.png
android/res/drawable/actionbar_compat_item.xml [deleted file]
android/res/drawable/actionbar_compat_item_focused.xml [deleted file]
android/res/drawable/actionbar_compat_item_pressed.xml [deleted file]
android/res/drawable/divider.xml [deleted file]
android/res/drawable/home_item.xml [deleted file]
android/res/drawable/ic_menu_preferences.png [deleted file]
android/res/drawable/list_selector_background.xml [deleted file]
android/res/drawable/list_selector_background_disabled.9.png [deleted file]
android/res/drawable/list_selector_background_focus.9.png [deleted file]
android/res/drawable/list_selector_background_longpress.9.png [deleted file]
android/res/drawable/list_selector_background_pressed.9.png [deleted file]
android/res/drawable/list_selector_background_transition.xml [deleted file]
android/res/drawable/simulation_state.xml [new file with mode: 0644]
android/res/drawable/simulation_state_green.xml [new file with mode: 0644]
android/res/drawable/simulation_state_red.xml [new file with mode: 0644]
android/res/drawable/simulation_state_yellow.xml [new file with mode: 0644]
android/res/layout-land/simulation_event_item.xml [new file with mode: 0644]
android/res/layout-large-land/motorbrowser.xml [new file with mode: 0644]
android/res/layout-large-land/openrocketviewer.xml [new file with mode: 0644]
android/res/layout-v11/actionbar_indeterminate_progress.xml [deleted file]
android/res/layout-xlarge-land/motorbrowser.xml [deleted file]
android/res/layout-xlarge-land/openrocketviewer.xml [deleted file]
android/res/layout/actionbar_compat.xml [deleted file]
android/res/layout/component_list_item.xml
android/res/layout/filebrowser_list_item.xml
android/res/layout/main.xml
android/res/layout/motor_config_delay_dialog.xml [new file with mode: 0644]
android/res/layout/motor_config_item.xml [new file with mode: 0644]
android/res/layout/motor_list_dialog.xml [new file with mode: 0644]
android/res/layout/rocket_configurations.xml [new file with mode: 0644]
android/res/layout/rocket_overview.xml
android/res/layout/simple_spinner_item.xml [deleted file]
android/res/layout/simulation_condition_dialog.xml [new file with mode: 0644]
android/res/layout/simulation_event_dialog.xml
android/res/layout/simulation_event_item.xml [new file with mode: 0644]
android/res/layout/simulation_list_item.xml [new file with mode: 0644]
android/res/layout/simulation_plot_config_dialog.xml [new file with mode: 0644]
android/res/layout/simulation_plot_config_event_list_item.xml [new file with mode: 0644]
android/res/layout/simulation_series_dialog.xml [deleted file]
android/res/layout/tcqueryform.xml
android/res/layout/tree_list_item_wrapper.xml [deleted file]
android/res/menu/main_menu.xml
android/res/menu/motor_browser_option_menu.xml
android/res/menu/rocket_viewer_configurations_option_menu.xml [new file with mode: 0644]
android/res/menu/rocket_viewer_option_menu.xml
android/res/menu/rocket_viewer_simulation_option_menu.xml [new file with mode: 0644]
android/res/menu/simulation_option_menu.xml
android/res/values-fr/strings.xml [new file with mode: 0644]
android/res/values-v11/styles.xml
android/res/values-v13/styles.xml [deleted file]
android/res/values/actionbar_attrs.xml [deleted file]
android/res/values/actionbar_colors.xml [deleted file]
android/res/values/actionbar_dimens.xml [deleted file]
android/res/values/actionbar_ids.xml [deleted file]
android/res/values/actionbar_styles.xml [deleted file]
android/res/values/attrs.xml [deleted file]
android/res/values/pref_strings.xml
android/res/values/simulation_states.xml [new file with mode: 0644]
android/res/values/strings.xml
android/res/values/styles.xml
android/res/xml/preferences.xml
android/src/build.properties [new file with mode: 0644]
android/src/net/sf/openrocket/android/ActivityHelpers.java
android/src/net/sf/openrocket/android/Application.java
android/src/net/sf/openrocket/android/CurrentRocket.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/CurrentRocketHolder.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/Main.java
android/src/net/sf/openrocket/android/MotorDatabaseAdapter.java
android/src/net/sf/openrocket/android/PreferencesActivity.java
android/src/net/sf/openrocket/android/PreferencesAdapter.java
android/src/net/sf/openrocket/android/actionbarcompat/ActionBarActivity.java [deleted file]
android/src/net/sf/openrocket/android/actionbarcompat/ActionBarFragmentActivity.java [deleted file]
android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelper.java [deleted file]
android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperBase.java [deleted file]
android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperHoneycomb.java [deleted file]
android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperICS.java [deleted file]
android/src/net/sf/openrocket/android/actionbarcompat/ActionBarListActivity.java [deleted file]
android/src/net/sf/openrocket/android/actionbarcompat/SimpleMenu.java [deleted file]
android/src/net/sf/openrocket/android/actionbarcompat/SimpleMenuItem.java [deleted file]
android/src/net/sf/openrocket/android/db/ConversionUtils.java
android/src/net/sf/openrocket/android/db/MotorDao.java
android/src/net/sf/openrocket/android/events/ChangeEventBroadcastReceiver.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/events/Events.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/filebrowser/SimpleFileBrowser.java
android/src/net/sf/openrocket/android/motor/BurnPlotFragment.java
android/src/net/sf/openrocket/android/motor/ExtendedThrustCurveMotor.java
android/src/net/sf/openrocket/android/motor/MotorBrowserActivity.java
android/src/net/sf/openrocket/android/motor/MotorDelayDialogFragment.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/motor/MotorDetailsFragment.java
android/src/net/sf/openrocket/android/motor/MotorListDialogFragment.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/motor/MotorListFragment.java
android/src/net/sf/openrocket/android/rocket/Component.java
android/src/net/sf/openrocket/android/rocket/Configurations.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/rocket/ErrorLoadingFileDialogFragment.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/rocket/MissingMotorDialogFragment.java
android/src/net/sf/openrocket/android/rocket/MotorConfigSpinner.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/rocket/OpenRocketLoaderActivity.java
android/src/net/sf/openrocket/android/rocket/OpenRocketLoaderFragment.java
android/src/net/sf/openrocket/android/rocket/OpenRocketSaverFragment.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/rocket/OpenRocketViewer.java
android/src/net/sf/openrocket/android/rocket/Overview.java
android/src/net/sf/openrocket/android/rocket/RocketComponentTreeAdapter.java
android/src/net/sf/openrocket/android/rocket/Simulations.java [deleted file]
android/src/net/sf/openrocket/android/rocket/WarningDialogFragment.java
android/src/net/sf/openrocket/android/simservice/SimulationService.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/simservice/SimulationTask.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/simulation/SimulationChart.java
android/src/net/sf/openrocket/android/simulation/SimulationEditFragment.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/simulation/SimulationEventsDialog.java
android/src/net/sf/openrocket/android/simulation/SimulationFragment.java [deleted file]
android/src/net/sf/openrocket/android/simulation/SimulationListItem.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/simulation/SimulationPlotConfigDialog.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/simulation/SimulationSeriesDialog.java [deleted file]
android/src/net/sf/openrocket/android/simulation/SimulationViewActivity.java
android/src/net/sf/openrocket/android/simulation/SimulationViewFragment.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/simulation/Simulations.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/thrustcurve/TCQueryAction.java
android/src/net/sf/openrocket/android/thrustcurve/TCQueryActivity.java
android/src/net/sf/openrocket/android/thrustcurve/ThrustCurveAPI.java
android/src/net/sf/openrocket/android/util/AndroidLogWrapper.java
android/src/net/sf/openrocket/android/util/ErrorDialogFragment.java
android/src/net/sf/openrocket/android/util/ExpandableListFragment.java
android/src/net/sf/openrocket/android/util/PersistentExpandableListView.java [new file with mode: 0644]
android/src/net/sf/openrocket/android/util/ProgressDialogFragment.java
android/src/pl/polidea/treeview/AbstractTreeViewAdapter.java [deleted file]
android/src/pl/polidea/treeview/InMemoryTreeNode.java [deleted file]
android/src/pl/polidea/treeview/InMemoryTreeStateManager.java [deleted file]
android/src/pl/polidea/treeview/NodeAlreadyInTreeException.java [deleted file]
android/src/pl/polidea/treeview/NodeNotInTreeException.java [deleted file]
android/src/pl/polidea/treeview/TreeBuilder.java [deleted file]
android/src/pl/polidea/treeview/TreeConfigurationException.java [deleted file]
android/src/pl/polidea/treeview/TreeNodeInfo.java [deleted file]
android/src/pl/polidea/treeview/TreeStateManager.java [deleted file]
android/src/pl/polidea/treeview/TreeViewList.java [deleted file]
android/src/pl/polidea/treeview/license.txt [deleted file]
android/src/pl/polidea/treeview/package-info.java [deleted file]
core/.classpath
core/ChangeLog
core/README.TXT
core/ReleaseNotes
core/build.xml
core/doc/properties.txt
core/doc/techdoc/figures/motors/staged [new file with mode: 0644]
core/doc/techdoc/figures/motors/staged. [deleted file]
core/fileformat.txt
core/lib-extra/ant-contrib-1.0b3.jar [new file with mode: 0644]
core/lib/OrangeExtensions-1.2.jar [new file with mode: 0644]
core/lib/jar-in-jar-loader.jar [new file with mode: 0644]
core/lib/jogl/gluegen-rt-natives-linux-amd64.jar [new file with mode: 0644]
core/lib/jogl/gluegen-rt-natives-linux-i586.jar [new file with mode: 0644]
core/lib/jogl/gluegen-rt-natives-macosx-universal.jar [new file with mode: 0644]
core/lib/jogl/gluegen-rt-natives-windows-amd64.jar [new file with mode: 0644]
core/lib/jogl/gluegen-rt-natives-windows-i586.jar [new file with mode: 0644]
core/lib/jogl/gluegen-rt.jar [new file with mode: 0644]
core/lib/jogl/jogl-all-natives-linux-amd64.jar [new file with mode: 0644]
core/lib/jogl/jogl-all-natives-linux-i586.jar [new file with mode: 0644]
core/lib/jogl/jogl-all-natives-macosx-universal.jar [new file with mode: 0644]
core/lib/jogl/jogl-all-natives-windows-amd64.jar [new file with mode: 0644]
core/lib/jogl/jogl-all-natives-windows-i586.jar [new file with mode: 0644]
core/lib/jogl/jogl.all.jar [new file with mode: 0644]
core/lib/jspf.core-1.0.2.jar [new file with mode: 0644]
core/lib/opencsv-2.3.jar [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bluetube/BTDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bluetube/MATERIAL.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bluetube/TCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bluetube/readme.txt [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/BHdata.csv [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/BTdata.csv [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/CRdata.csv [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/LLdata.csv [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/MATERIAL.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/NCdata.csv [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/TCdata.csv [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/TRdata.csv [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/bms/ebdata.csv [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/BTDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/EBDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/LLDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/MATERIAL.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/MODATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/NCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/PCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/TCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/estes/TRDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/BHDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/BTDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/CRDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/LLDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/MATERIAL.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/MODATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/NCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/PCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/giantleaprocketry/TCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/BHDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/BTDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/CFDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/CRDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/EBDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/FSDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/GRAPHS.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/LLDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/MATERIAL.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/MODATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/NCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/PCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/SLDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/STDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/TCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/publicmissiles/TRDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/BTDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/CRDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/EBDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/MATERIAL.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/NCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/PCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/STDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/TCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/quest/TRDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/BHDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/BTDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/CRDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/EBDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/LLDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/MATERIAL.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/NCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/PCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/STDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/TCDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/rocksim_components/semroc/TRDATA.CSV [new file with mode: 0644]
core/resources-src/datafiles/thrustcurves/Quest_D5_1.eng [new file with mode: 0644]
core/resources-src/datafiles/thrustcurves/Quest_Micro_Maxx_II.eng [new file with mode: 0644]
core/resources-src/datafiles/thrustcurves/README.txt
core/resources-src/pix/android-ic_launcher.xcf.gz [new file with mode: 0644]
core/resources/build.properties
core/resources/datafiles/examples/Preset Usage.ork [new file with mode: 0644]
core/resources/datafiles/examples/Roll-stabilized rocket.ork
core/resources/datafiles/presets/Estes.orc [new file with mode: 0644]
core/resources/datafiles/presets/Quest.orc [new file with mode: 0644]
core/resources/datafiles/presets/bluetube.orc [new file with mode: 0644]
core/resources/datafiles/presets/bms.orc [new file with mode: 0644]
core/resources/datafiles/presets/fliskits.orc [new file with mode: 0644]
core/resources/datafiles/presets/giantleaprocketry.orc [new file with mode: 0644]
core/resources/datafiles/presets/publicmissiles.orc [new file with mode: 0644]
core/resources/datafiles/presets/semroc.orc [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_H178.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_I327.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_I350.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_K1103.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_K456.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_L1040.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_L339.eng
core/resources/datafiles/thrustcurves/AeroTech_L339_1.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_L400.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_L900.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_M1075.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_M1305.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/AeroTech_M1780.eng
core/resources/datafiles/thrustcurves/AeroTech_M1780_1.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_E22.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_E31.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_F50.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_F51.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_G69_1.eng
core/resources/datafiles/thrustcurves/Cesaroni_G69_2.eng
core/resources/datafiles/thrustcurves/Cesaroni_G69_3.eng [deleted file]
core/resources/datafiles/thrustcurves/Cesaroni_I165.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_J316.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_J316.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_J425.eng
core/resources/datafiles/thrustcurves/Cesaroni_J425.rse [deleted file]
core/resources/datafiles/thrustcurves/Cesaroni_J453.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_K2000.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_K580.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_K650.rse
core/resources/datafiles/thrustcurves/Cesaroni_K650_1.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_K661.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_K735.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_K935.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_L1050.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_L1350.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_L3200.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_L645.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_L805.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_L910.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_M2245.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_M2245.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_N2540.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Cesaroni_O25000.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Estes_E12.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Estes_E30.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Estes_F26.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Estes_F50.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Estes_G40.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Estes_G40_1.eng [new file with mode: 0644]
core/resources/datafiles/thrustcurves/GR_M1025.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/GR_M1465.rse [new file with mode: 0644]
core/resources/datafiles/thrustcurves/Quest_D5_1.eng
core/resources/datafiles/thrustcurves/Quest_Micro_Maxx_II.eng [new file with mode: 0644]
core/resources/dejavu-font/DejaVuSerif.ttf [new file with mode: 0644]
core/resources/dejavu-font/LICENSE [new file with mode: 0644]
core/resources/dejavu-font/README [new file with mode: 0644]
core/resources/l10n/messages.properties
core/resources/l10n/messages_cs.properties [new file with mode: 0644]
core/resources/l10n/messages_de.properties
core/resources/l10n/messages_es.properties
core/resources/l10n/messages_fr.properties
core/resources/l10n/messages_it.properties
core/resources/l10n/messages_pl.properties [new file with mode: 0644]
core/resources/l10n/messages_ru.properties
core/resources/l10n/rename.sh [new file with mode: 0755]
core/resources/pix/icons/copyright.txt
core/resources/pix/icons/down.png [new file with mode: 0644]
core/resources/pix/icons/pencil.png [new file with mode: 0644]
core/resources/pix/icons/star_gold.png [new file with mode: 0644]
core/resources/pix/icons/star_silver.png [new file with mode: 0644]
core/resources/pix/icons/up.png [new file with mode: 0644]
core/run.sh
core/src/de/congrace/exp4j/AbstractExpression.java [new file with mode: 0644]
core/src/de/congrace/exp4j/Calculable.java [new file with mode: 0644]
core/src/de/congrace/exp4j/CalculationToken.java [new file with mode: 0644]
core/src/de/congrace/exp4j/CommandlineInterpreter.java [new file with mode: 0644]
core/src/de/congrace/exp4j/CustomFunction.java [new file with mode: 0644]
core/src/de/congrace/exp4j/Example.java [new file with mode: 0644]
core/src/de/congrace/exp4j/ExpressionBuilder.java [new file with mode: 0644]
core/src/de/congrace/exp4j/FunctionSeparatorToken.java [new file with mode: 0644]
core/src/de/congrace/exp4j/FunctionToken.java [new file with mode: 0644]
core/src/de/congrace/exp4j/InfixTranslator.java [new file with mode: 0644]
core/src/de/congrace/exp4j/InvalidCustomFunctionException.java [new file with mode: 0644]
core/src/de/congrace/exp4j/NumberToken.java [new file with mode: 0644]
core/src/de/congrace/exp4j/OperatorToken.java [new file with mode: 0644]
core/src/de/congrace/exp4j/ParenthesisToken.java [new file with mode: 0644]
core/src/de/congrace/exp4j/PostfixExpression.java [new file with mode: 0644]
core/src/de/congrace/exp4j/Token.java [new file with mode: 0644]
core/src/de/congrace/exp4j/Tokenizer.java [new file with mode: 0644]
core/src/de/congrace/exp4j/UnknownFunctionException.java [new file with mode: 0644]
core/src/de/congrace/exp4j/UnparsableExpressionException.java [new file with mode: 0644]
core/src/de/congrace/exp4j/Variable.java [new file with mode: 0644]
core/src/de/congrace/exp4j/VariableSet.java [new file with mode: 0644]
core/src/de/congrace/exp4j/VariableToken.java [new file with mode: 0644]
core/src/net/sf/openrocket/aerodynamics/Warning.java
core/src/net/sf/openrocket/aerodynamics/barrowman/FinSetCalc.java
core/src/net/sf/openrocket/aerodynamics/barrowman/SymmetricComponentCalc.java
core/src/net/sf/openrocket/arch/SystemInfo.java
core/src/net/sf/openrocket/communication/UpdateInfoRetriever.java
core/src/net/sf/openrocket/database/ComponentPresetDao.java [new file with mode: 0644]
core/src/net/sf/openrocket/database/ComponentPresetDatabase.java [new file with mode: 0644]
core/src/net/sf/openrocket/database/Database.java
core/src/net/sf/openrocket/database/Databases.java
core/src/net/sf/openrocket/database/ThrustCurveMotorSetDatabase.java
core/src/net/sf/openrocket/document/OpenRocketDocument.java
core/src/net/sf/openrocket/document/Simulation.java
core/src/net/sf/openrocket/file/GeneralRocketLoader.java
core/src/net/sf/openrocket/file/iterator/ZipDirectoryIterator.java
core/src/net/sf/openrocket/file/motor/AbstractMotorLoader.java
core/src/net/sf/openrocket/file/motor/MotorLoaderHelper.java
core/src/net/sf/openrocket/file/openrocket/OpenRocketSaver.java
core/src/net/sf/openrocket/file/openrocket/importt/OpenRocketLoader.java
core/src/net/sf/openrocket/file/openrocket/savers/ExternalComponentSaver.java
core/src/net/sf/openrocket/file/openrocket/savers/FinSetSaver.java
core/src/net/sf/openrocket/file/openrocket/savers/RecoveryDeviceSaver.java
core/src/net/sf/openrocket/file/openrocket/savers/RocketComponentSaver.java
core/src/net/sf/openrocket/file/openrocket/savers/RocketSaver.java
core/src/net/sf/openrocket/file/openrocket/savers/StageSaver.java
core/src/net/sf/openrocket/file/openrocket/savers/TransitionSaver.java
core/src/net/sf/openrocket/file/rocksim/RocksimCommonConstants.java
core/src/net/sf/openrocket/file/rocksim/RocksimNoseConeCode.java
core/src/net/sf/openrocket/file/rocksim/export/RocksimSaver.java
core/src/net/sf/openrocket/file/rocksim/importt/BaseHandler.java
core/src/net/sf/openrocket/file/rocksim/importt/FinSetHandler.java
core/src/net/sf/openrocket/file/rocksim/importt/MassObjectHandler.java
core/src/net/sf/openrocket/file/rocksim/importt/TransitionHandler.java
core/src/net/sf/openrocket/file/simplesax/DelegatorHandler.java
core/src/net/sf/openrocket/file/simplesax/SimpleSAX.java
core/src/net/sf/openrocket/gui/SpinnerEditor.java
core/src/net/sf/openrocket/gui/adaptors/Column.java
core/src/net/sf/openrocket/gui/adaptors/ColumnTableModel.java
core/src/net/sf/openrocket/gui/adaptors/DoubleModel.java
core/src/net/sf/openrocket/gui/adaptors/MaterialModel.java
core/src/net/sf/openrocket/gui/adaptors/PresetModel.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/components/StarCheckBox.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/components/StyledLabel.java
core/src/net/sf/openrocket/gui/configdialog/BodyTubeConfig.java
core/src/net/sf/openrocket/gui/configdialog/EllipticalFinSetConfig.java
core/src/net/sf/openrocket/gui/configdialog/FreeformFinSetConfig.java
core/src/net/sf/openrocket/gui/configdialog/LaunchLugConfig.java
core/src/net/sf/openrocket/gui/configdialog/MassComponentConfig.java
core/src/net/sf/openrocket/gui/configdialog/MotorConfig.java
core/src/net/sf/openrocket/gui/configdialog/NoseConeConfig.java
core/src/net/sf/openrocket/gui/configdialog/ParachuteConfig.java
core/src/net/sf/openrocket/gui/configdialog/RingComponentConfig.java
core/src/net/sf/openrocket/gui/configdialog/RocketComponentConfig.java
core/src/net/sf/openrocket/gui/configdialog/StreamerConfig.java
core/src/net/sf/openrocket/gui/configdialog/TrapezoidFinSetConfig.java
core/src/net/sf/openrocket/gui/customexpression/CustomExpressionDialog.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/customexpression/CustomExpressionPanel.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/customexpression/ExpressionBuilderDialog.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/customexpression/OperatorSelector.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/customexpression/OperatorTableModel.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/customexpression/VariableSelector.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/customexpression/VariableTableModel.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/dialogs/AboutDialog.java
core/src/net/sf/openrocket/gui/dialogs/ComponentAnalysisDialog.java
core/src/net/sf/openrocket/gui/dialogs/CustomMaterialDialog.java
core/src/net/sf/openrocket/gui/dialogs/EditMotorConfigurationDialog.java
core/src/net/sf/openrocket/gui/dialogs/PrintDialog.java
core/src/net/sf/openrocket/gui/dialogs/motor/MotorChooserDialog.java
core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorColumns.java
core/src/net/sf/openrocket/gui/dialogs/motor/thrustcurve/ThrustCurveMotorSelectionPanel.java
core/src/net/sf/openrocket/gui/dialogs/optimization/GeneralOptimizationDialog.java
core/src/net/sf/openrocket/gui/dialogs/optimization/SimulationModifierTree.java
core/src/net/sf/openrocket/gui/dialogs/preferences/PreferencesDialog.java
core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetChooserDialog.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetRowFilter.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetTable.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetTableColumn.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/dialogs/preset/XTableColumnModel.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/figure3d/ComponentRenderer.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/figure3d/MassObjectRenderer.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/figure3d/Quick3dMain.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/figure3d/TransitionRenderer.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/main/BasicFrame.java
core/src/net/sf/openrocket/gui/main/MRUDesignFile.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/main/SimulationEditDialog.java
core/src/net/sf/openrocket/gui/main/SimulationPanel.java
core/src/net/sf/openrocket/gui/main/SimulationRunDialog.java
core/src/net/sf/openrocket/gui/main/componenttree/ComponentTreeRenderer.java
core/src/net/sf/openrocket/gui/plot/PlotConfiguration.java
core/src/net/sf/openrocket/gui/plot/SimulationPlotDialog.java
core/src/net/sf/openrocket/gui/plot/SimulationPlotPanel.java
core/src/net/sf/openrocket/gui/plugin/DoSomethingPlugin.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/plugin/OpenRocketSwingMenuPlugin.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/plugin/SwingMenuPlugin.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/preset/ButtonColumn.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/preset/ComponentPresetEditor.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/preset/DeselectableComboBox.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/preset/ImagePreviewPanel.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/preset/MaterialModel.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/preset/PresetEditorDialog.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/preset/PresetResultListener.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/print/AbstractPrintable.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/print/AbstractPrintableTransition.java [deleted file]
core/src/net/sf/openrocket/gui/print/DesignReport.java
core/src/net/sf/openrocket/gui/print/FinMarkingGuide.java
core/src/net/sf/openrocket/gui/print/ITextHelper.java
core/src/net/sf/openrocket/gui/print/OpenRocketPrintable.java
core/src/net/sf/openrocket/gui/print/PaperSize.java
core/src/net/sf/openrocket/gui/print/PrintController.java
core/src/net/sf/openrocket/gui/print/PrintFigure.java
core/src/net/sf/openrocket/gui/print/PrintUnit.java
core/src/net/sf/openrocket/gui/print/PrintUtilities.java
core/src/net/sf/openrocket/gui/print/PrintableCenteringRing.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/print/PrintableComponent.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/print/PrintableFinSet.java
core/src/net/sf/openrocket/gui/print/PrintableNoseCone.java
core/src/net/sf/openrocket/gui/print/PrintableTransition.java
core/src/net/sf/openrocket/gui/print/components/Rule.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/print/visitor/CenteringRingStrategy.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/print/visitor/FinSetPrintStrategy.java
core/src/net/sf/openrocket/gui/print/visitor/PageFitPrintStrategy.java [new file with mode: 0644]
core/src/net/sf/openrocket/gui/print/visitor/PartsDetailVisitorStrategy.java
core/src/net/sf/openrocket/gui/print/visitor/TransitionStrategy.java
core/src/net/sf/openrocket/gui/scalefigure/FinPointFigure.java
core/src/net/sf/openrocket/gui/scalefigure/RocketFigure.java
core/src/net/sf/openrocket/gui/scalefigure/RocketPanel.java
core/src/net/sf/openrocket/gui/scalefigure/ScaleSelector.java
core/src/net/sf/openrocket/gui/util/CustomFinImporter.java
core/src/net/sf/openrocket/gui/util/FileHelper.java
core/src/net/sf/openrocket/gui/util/GUIUtil.java
core/src/net/sf/openrocket/gui/util/Icons.java
core/src/net/sf/openrocket/gui/util/SimpleFileFilter.java
core/src/net/sf/openrocket/gui/util/SwingPreferences.java
core/src/net/sf/openrocket/l10n/ClassBasedTranslator.java
core/src/net/sf/openrocket/l10n/DebugTranslator.java
core/src/net/sf/openrocket/l10n/ExceptionSuppressingTranslator.java
core/src/net/sf/openrocket/l10n/L10N.java
core/src/net/sf/openrocket/l10n/ResourceBundleTranslator.java
core/src/net/sf/openrocket/l10n/Translator.java
core/src/net/sf/openrocket/logging/LogLevel.java
core/src/net/sf/openrocket/masscalc/BasicMassCalculator.java
core/src/net/sf/openrocket/masscalc/MassCalculator.java
core/src/net/sf/openrocket/material/Material.java
core/src/net/sf/openrocket/models/atmosphere/ExtendedISAModel.java
core/src/net/sf/openrocket/motor/Manufacturer.java
core/src/net/sf/openrocket/motor/MotorInstance.java
core/src/net/sf/openrocket/motor/ThrustCurveMotor.java
core/src/net/sf/openrocket/optimization/rocketoptimization/modifiers/GenericModifier.java
core/src/net/sf/openrocket/optimization/services/DefaultSimulationModifierService.java
core/src/net/sf/openrocket/optimization/services/OptimizationServiceHelper.java
core/src/net/sf/openrocket/plugin/Configurable.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/SwingConfigurator.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/example/AirStartSimulationExtension.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/example/ExampleMain.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/example/ExamplePlugin.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/example/ExamplePluginInterface.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/example/ExampleService.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/example/ExampleSingletonPlugin.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/example/OpenRocketSimulationListener.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/example/stuff.txt [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/framework/AbstractService.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/framework/JSPFPluginFactory.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/framework/PluginFactory.java [new file with mode: 0644]
core/src/net/sf/openrocket/plugin/framework/Service.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/ComponentPreset.java
core/src/net/sf/openrocket/preset/ComponentPresetFactory.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/InvalidComponentPresetException.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/TypedKey.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/TypedPropertyMap.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/BaseColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/BaseComponentLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/BaseUnitColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/BodyTubeLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/BulkHeadLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/CenteringRingLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/DoubleColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/DoubleUnitColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/EngineBlockLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/IntegerColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/LaunchLugLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/LineMaterialColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/ManufacturerColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/MassColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/MaterialColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/MaterialHolder.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/MaterialLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/NoseConeLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/ParachuteLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/RocksimComponentFileColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/RocksimComponentFileLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/RocksimComponentFileTranslator.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/RocksimComponentFileType.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/ShapeColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/StreamerLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/StringColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/SurfaceMaterialColumnParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/TransitionLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/loader/TubeCouplerLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/BaseComponentDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/BodyTubeDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/BulkHeadDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/CenteringRingDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/EngineBlockDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/LaunchLugDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/MaterialDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/MaterialTypeDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/NoseConeDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/OpenRocketComponentDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/OpenRocketComponentLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/OpenRocketComponentSaver.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/ParachuteDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/ShapeDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/StreamerDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/TransitionDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/preset/xml/TubeCouplerDTO.java [new file with mode: 0644]
core/src/net/sf/openrocket/rocketcomponent/BodyComponent.java
core/src/net/sf/openrocket/rocketcomponent/BodyTube.java
core/src/net/sf/openrocket/rocketcomponent/Bulkhead.java
core/src/net/sf/openrocket/rocketcomponent/CenteringRing.java
core/src/net/sf/openrocket/rocketcomponent/EngineBlock.java
core/src/net/sf/openrocket/rocketcomponent/ExternalComponent.java
core/src/net/sf/openrocket/rocketcomponent/FinSet.java
core/src/net/sf/openrocket/rocketcomponent/FreeformFinSet.java
core/src/net/sf/openrocket/rocketcomponent/InnerTube.java
core/src/net/sf/openrocket/rocketcomponent/LaunchLug.java
core/src/net/sf/openrocket/rocketcomponent/MassComponent.java
core/src/net/sf/openrocket/rocketcomponent/NoseCone.java
core/src/net/sf/openrocket/rocketcomponent/Parachute.java
core/src/net/sf/openrocket/rocketcomponent/RadiusRingComponent.java
core/src/net/sf/openrocket/rocketcomponent/RecoveryDevice.java
core/src/net/sf/openrocket/rocketcomponent/Rocket.java
core/src/net/sf/openrocket/rocketcomponent/RocketComponent.java
core/src/net/sf/openrocket/rocketcomponent/Sleeve.java
core/src/net/sf/openrocket/rocketcomponent/Streamer.java
core/src/net/sf/openrocket/rocketcomponent/StructuralComponent.java
core/src/net/sf/openrocket/rocketcomponent/SymmetricComponent.java
core/src/net/sf/openrocket/rocketcomponent/ThicknessRingComponent.java
core/src/net/sf/openrocket/rocketcomponent/Transition.java
core/src/net/sf/openrocket/rocketcomponent/TubeCoupler.java
core/src/net/sf/openrocket/simulation/AbstractSimulationStepper.java
core/src/net/sf/openrocket/simulation/BasicEventSimulationEngine.java
core/src/net/sf/openrocket/simulation/BasicLandingStepper.java
core/src/net/sf/openrocket/simulation/FlightDataBranch.java
core/src/net/sf/openrocket/simulation/FlightDataType.java
core/src/net/sf/openrocket/simulation/MassData.java
core/src/net/sf/openrocket/simulation/RK4SimulationStepper.java
core/src/net/sf/openrocket/simulation/SimulationConditions.java
core/src/net/sf/openrocket/simulation/SimulationOptions.java
core/src/net/sf/openrocket/simulation/customexpression/CustomExpression.java [new file with mode: 0644]
core/src/net/sf/openrocket/simulation/customexpression/CustomExpressionSimulationListener.java [new file with mode: 0644]
core/src/net/sf/openrocket/simulation/customexpression/Functions.java [new file with mode: 0644]
core/src/net/sf/openrocket/simulation/customexpression/IndexExpression.java [new file with mode: 0644]
core/src/net/sf/openrocket/simulation/customexpression/RangeExpression.java [new file with mode: 0644]
core/src/net/sf/openrocket/simulation/listeners/AbstractSimulationListener.java
core/src/net/sf/openrocket/simulation/listeners/SimulationComputationListener.java
core/src/net/sf/openrocket/simulation/listeners/SimulationEventListener.java
core/src/net/sf/openrocket/simulation/listeners/SimulationListener.java
core/src/net/sf/openrocket/simulation/listeners/example/DampingMoment.java [new file with mode: 0644]
core/src/net/sf/openrocket/simulation/listeners/example/RollControlListener.java
core/src/net/sf/openrocket/startup/Application.java
core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java [new file with mode: 0644]
core/src/net/sf/openrocket/startup/ConcurrentLoadingThrustCurveMotorSetDatabase.java [new file with mode: 0644]
core/src/net/sf/openrocket/startup/OSXStartup.java [new file with mode: 0644]
core/src/net/sf/openrocket/startup/Preferences.java
core/src/net/sf/openrocket/startup/Startup.java
core/src/net/sf/openrocket/startup/Startup2.java
core/src/net/sf/openrocket/startup/VersionHelper.java
core/src/net/sf/openrocket/unit/FixedUnitGroup.java [new file with mode: 0644]
core/src/net/sf/openrocket/unit/FractionalUnit.java [new file with mode: 0644]
core/src/net/sf/openrocket/unit/Unit.java
core/src/net/sf/openrocket/unit/UnitGroup.java
core/src/net/sf/openrocket/util/AlphanumComparator.java [new file with mode: 0644]
core/src/net/sf/openrocket/util/ArrayUtils.java [new file with mode: 0644]
core/src/net/sf/openrocket/util/Base64.java
core/src/net/sf/openrocket/util/BuildProperties.java
core/src/net/sf/openrocket/util/Chars.java
core/src/net/sf/openrocket/util/Coordinate.java
core/src/net/sf/openrocket/util/ExpressionParser.java [new file with mode: 0644]
core/src/net/sf/openrocket/util/GeodeticComputationStrategy.java
core/src/net/sf/openrocket/util/InvalidExpressionException.java [new file with mode: 0644]
core/src/net/sf/openrocket/util/JarUtil.java
core/src/net/sf/openrocket/util/LinearInterpolator.java
core/src/net/sf/openrocket/util/MathUtil.java
core/src/net/sf/openrocket/util/PolyInterpolator.java
core/src/net/sf/openrocket/util/Quaternion.java
core/src/net/sf/openrocket/util/SimpleStack.java [new file with mode: 0644]
core/src/net/sf/openrocket/util/TestRockets.java
core/src/net/sf/openrocket/util/TextUtil.java
core/src/net/sf/openrocket/util/Transformation.java
core/src/net/sf/openrocket/util/enums/EnumConversion.java [new file with mode: 0644]
core/src/net/sf/openrocket/util/enums/EnumName.java [new file with mode: 0644]
core/src/net/sf/openrocket/utils/L10NGenerator.java [new file with mode: 0644]
core/test/net/sf/openrocket/communication/HttpURLConnectionMock.java
core/test/net/sf/openrocket/gui/print/PrintUnitTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/l10n/TestDebugTranslator.java [new file with mode: 0644]
core/test/net/sf/openrocket/l10n/TestL10N.java [new file with mode: 0644]
core/test/net/sf/openrocket/l10n/TestResourceBundleTranslator.java
core/test/net/sf/openrocket/motor/ManufacturerTest.java
core/test/net/sf/openrocket/preset/BodyTubeComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/BodyTubePresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/BulkHeadComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/BulkHeadPresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/CenteringRingComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/CenteringRingPresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/EngineBlockComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/EngineBlockPresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/LaunchLugComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/LaunchLugPresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/NoseConeComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/NoseConePresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/ParachutePresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/ParachuterComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/PresetAssertHelper.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/StreamerComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/StreamerPresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/TransitionComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/TransitionPresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/TubeCouplerComponentTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/TubeCouplerPresetTests.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/xml/BaseComponentDTOTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/preset/xml/OpenRocketComponentSaverTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/rocketcomponent/ComponentCompare.java
core/test/net/sf/openrocket/rocketcomponent/ComponentCompareTest.java
core/test/net/sf/openrocket/rocketcomponent/FinSetTest.java
core/test/net/sf/openrocket/rocketcomponent/SymmetricComponentVolumeTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/simulation/customexpression/TestExpressions.java [new file with mode: 0644]
core/test/net/sf/openrocket/unit/FractionalUnitTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/unit/UnitToStringTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/util/ArrayUtilsTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/util/Base64Test.java [new file with mode: 0644]
core/test/net/sf/openrocket/util/ExpressionParserTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/util/LinearInterpolatorTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/util/MathUtilTest.java
core/test/net/sf/openrocket/util/PolyInterpolatorTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/util/QuaternionTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/util/SimpleStackTest.java [new file with mode: 0644]
core/test/net/sf/openrocket/util/TextUtilTest.java
core/test/net/sf/openrocket/util/TransformationTest.java [new file with mode: 0644]
core/web/html/actions/updates.php
core/web/html/download.html
core/web/html/index.html
core/web/htp/download.htp
core/web/htp/htp.def
core/web/htp/news.htp

diff --git a/android-libraries/ActionBarSherlock/.classpath b/android-libraries/ActionBarSherlock/.classpath
new file mode 100644 (file)
index 0000000..8531be1
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="src" path="gen"/>\r
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>\r
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
+       <classpathentry kind="lib" path="libs/android-support-v4.jar"/>\r
+       <classpathentry kind="output" path="bin/classes"/>\r
+</classpath>\r
diff --git a/android-libraries/ActionBarSherlock/.project b/android-libraries/ActionBarSherlock/.project
new file mode 100644 (file)
index 0000000..cbcf5a2
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>ActionBarSherlock</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/android-libraries/ActionBarSherlock/AndroidManifest.xml b/android-libraries/ActionBarSherlock/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..c4a75f3
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="90" android:versionName="4.1.0" package="com.actionbarsherlock">
+
+    <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="15"/>
+
+</manifest>
diff --git a/android-libraries/ActionBarSherlock/bin/actionbarsherlock.jar b/android-libraries/ActionBarSherlock/bin/actionbarsherlock.jar
new file mode 100644 (file)
index 0000000..02f3667
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/actionbarsherlock.jar differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$Implementation.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$Implementation.class
new file mode 100644 (file)
index 0000000..07a0de9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$Implementation.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnActionModeFinishedListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnActionModeFinishedListener.class
new file mode 100644 (file)
index 0000000..ba2cfca
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnActionModeFinishedListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnActionModeStartedListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnActionModeStartedListener.class
new file mode 100644 (file)
index 0000000..3ccc3b1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnActionModeStartedListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnCreateOptionsMenuListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnCreateOptionsMenuListener.class
new file mode 100644 (file)
index 0000000..d0ffc34
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnCreateOptionsMenuListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnCreatePanelMenuListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnCreatePanelMenuListener.class
new file mode 100644 (file)
index 0000000..7bf337c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnCreatePanelMenuListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnMenuItemSelectedListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnMenuItemSelectedListener.class
new file mode 100644 (file)
index 0000000..03609bb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnMenuItemSelectedListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnOptionsItemSelectedListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnOptionsItemSelectedListener.class
new file mode 100644 (file)
index 0000000..4076b48
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnOptionsItemSelectedListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnPrepareOptionsMenuListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnPrepareOptionsMenuListener.class
new file mode 100644 (file)
index 0000000..b9704c8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnPrepareOptionsMenuListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnPreparePanelListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnPreparePanelListener.class
new file mode 100644 (file)
index 0000000..4e02242
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock$OnPreparePanelListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock.class
new file mode 100644 (file)
index 0000000..3e4437f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/ActionBarSherlock.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/BuildConfig.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/BuildConfig.class
new file mode 100644 (file)
index 0000000..f3ea991
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/BuildConfig.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$attr.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$attr.class
new file mode 100644 (file)
index 0000000..79d19d6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$attr.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$bool.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$bool.class
new file mode 100644 (file)
index 0000000..a9853b1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$bool.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$color.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$color.class
new file mode 100644 (file)
index 0000000..92c994f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$color.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$dimen.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$dimen.class
new file mode 100644 (file)
index 0000000..1423fa8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$dimen.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$drawable.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$drawable.class
new file mode 100644 (file)
index 0000000..d1d77ad
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$drawable.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$id.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$id.class
new file mode 100644 (file)
index 0000000..cb66e60
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$id.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$integer.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$integer.class
new file mode 100644 (file)
index 0000000..2a1eb05
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$integer.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$layout.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$layout.class
new file mode 100644 (file)
index 0000000..2e28b63
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$layout.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$string.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$string.class
new file mode 100644 (file)
index 0000000..cf862a4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$string.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$style.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$style.class
new file mode 100644 (file)
index 0000000..b8c2a02
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$style.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$styleable.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$styleable.class
new file mode 100644 (file)
index 0000000..ce1bf2a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R$styleable.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R.class
new file mode 100644 (file)
index 0000000..a9c2420
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/R.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$LayoutParams.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$LayoutParams.class
new file mode 100644 (file)
index 0000000..19f2d71
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$LayoutParams.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$OnMenuVisibilityListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$OnMenuVisibilityListener.class
new file mode 100644 (file)
index 0000000..377c6cb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$OnMenuVisibilityListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$OnNavigationListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$OnNavigationListener.class
new file mode 100644 (file)
index 0000000..e7631ef
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$OnNavigationListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$Tab.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$Tab.class
new file mode 100644 (file)
index 0000000..2c612f7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$Tab.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$TabListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$TabListener.class
new file mode 100644 (file)
index 0000000..d3c8280
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar$TabListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar.class
new file mode 100644 (file)
index 0000000..95cae96
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/ActionBar.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockActivity.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockActivity.class
new file mode 100644 (file)
index 0000000..0e5cc23
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockActivity.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockDialogFragment.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockDialogFragment.class
new file mode 100644 (file)
index 0000000..b235aed
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockDialogFragment.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockExpandableListActivity.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockExpandableListActivity.class
new file mode 100644 (file)
index 0000000..3e60b01
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockExpandableListActivity.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockFragment.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockFragment.class
new file mode 100644 (file)
index 0000000..5fe7b56
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockFragment.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockFragmentActivity.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockFragmentActivity.class
new file mode 100644 (file)
index 0000000..e7f20aa
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockFragmentActivity.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockListActivity.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockListActivity.class
new file mode 100644 (file)
index 0000000..ccea588
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockListActivity.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockListFragment.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockListFragment.class
new file mode 100644 (file)
index 0000000..20d394d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockListFragment.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockPreferenceActivity.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockPreferenceActivity.class
new file mode 100644 (file)
index 0000000..d8af591
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/app/SherlockPreferenceActivity.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat$1.class
new file mode 100644 (file)
index 0000000..40b3c68
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat$ActionModeCallbackWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat$ActionModeCallbackWrapper.class
new file mode 100644 (file)
index 0000000..2015aba
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat$ActionModeCallbackWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat.class
new file mode 100644 (file)
index 0000000..1d77c59
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockCompat.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeCallbackWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeCallbackWrapper.class
new file mode 100644 (file)
index 0000000..e0514eb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeCallbackWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeWrapper.class
new file mode 100644 (file)
index 0000000..8509992
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative$ActionModeWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative.class
new file mode 100644 (file)
index 0000000..4180bec
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ActionBarSherlockNative.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ResourcesCompat.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ResourcesCompat.class
new file mode 100644 (file)
index 0000000..453d4a2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/ResourcesCompat.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$1.class
new file mode 100644 (file)
index 0000000..2869fb1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$2.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$2.class
new file mode 100644 (file)
index 0000000..ceab0c4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$2.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$ActionModeImpl.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$ActionModeImpl.class
new file mode 100644 (file)
index 0000000..a49e051
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$ActionModeImpl.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$TabImpl.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$TabImpl.class
new file mode 100644 (file)
index 0000000..f0947b4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl$TabImpl.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl.class
new file mode 100644 (file)
index 0000000..eba5fc1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarImpl.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarWrapper$TabWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarWrapper$TabWrapper.class
new file mode 100644 (file)
index 0000000..0ce995a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarWrapper$TabWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarWrapper.class
new file mode 100644 (file)
index 0000000..686d2bb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/app/ActionBarWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Animator$AnimatorListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Animator$AnimatorListener.class
new file mode 100644 (file)
index 0000000..e47ad31
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Animator$AnimatorListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.class
new file mode 100644 (file)
index 0000000..281a452
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.class
new file mode 100644 (file)
index 0000000..ae4b865
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$1.class
new file mode 100644 (file)
index 0000000..aaedb90
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$AnimatorSetListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$AnimatorSetListener.class
new file mode 100644 (file)
index 0000000..d144adc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$AnimatorSetListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Builder.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Builder.class
new file mode 100644 (file)
index 0000000..5cbbc68
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Builder.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Dependency.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Dependency.class
new file mode 100644 (file)
index 0000000..5e07640
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Dependency.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$DependencyListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$DependencyListener.class
new file mode 100644 (file)
index 0000000..9f09b67
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$DependencyListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Node.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Node.class
new file mode 100644 (file)
index 0000000..f94b2b6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet$Node.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.class
new file mode 100644 (file)
index 0000000..7ffd50f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.class
new file mode 100644 (file)
index 0000000..2d950bc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.class
new file mode 100644 (file)
index 0000000..b3f70f8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.class
new file mode 100644 (file)
index 0000000..515af5d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.class
new file mode 100644 (file)
index 0000000..86bf0f6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$FloatKeyframe.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$FloatKeyframe.class
new file mode 100644 (file)
index 0000000..56d147a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$FloatKeyframe.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$IntKeyframe.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$IntKeyframe.class
new file mode 100644 (file)
index 0000000..aa36b75
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$IntKeyframe.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$ObjectKeyframe.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$ObjectKeyframe.class
new file mode 100644 (file)
index 0000000..6999514
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe$ObjectKeyframe.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.class
new file mode 100644 (file)
index 0000000..168f790
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.class
new file mode 100644 (file)
index 0000000..58317c4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.class
new file mode 100644 (file)
index 0000000..32cefbf
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder$FloatPropertyValuesHolder.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder$FloatPropertyValuesHolder.class
new file mode 100644 (file)
index 0000000..be6568f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder$FloatPropertyValuesHolder.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder$IntPropertyValuesHolder.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder$IntPropertyValuesHolder.class
new file mode 100644 (file)
index 0000000..4427b09
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder$IntPropertyValuesHolder.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.class
new file mode 100644 (file)
index 0000000..483a115
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.class
new file mode 100644 (file)
index 0000000..6b090a6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$1.class
new file mode 100644 (file)
index 0000000..6f04d6b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$2.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$2.class
new file mode 100644 (file)
index 0000000..c38e111
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$2.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$3.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$3.class
new file mode 100644 (file)
index 0000000..90b41d7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$3.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$4.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$4.class
new file mode 100644 (file)
index 0000000..fea2a58
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$4.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$5.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$5.class
new file mode 100644 (file)
index 0000000..7fad8e7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$5.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$AnimationHandler.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$AnimationHandler.class
new file mode 100644 (file)
index 0000000..a3b14cc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$AnimationHandler.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$AnimatorUpdateListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$AnimatorUpdateListener.class
new file mode 100644 (file)
index 0000000..b5bcde2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator$AnimatorUpdateListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.class
new file mode 100644 (file)
index 0000000..24581f1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.class
new file mode 100644 (file)
index 0000000..c05ca82
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.class
new file mode 100644 (file)
index 0000000..2838e4d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.class
new file mode 100644 (file)
index 0000000..664c61b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.class
new file mode 100644 (file)
index 0000000..46b2f34
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.class
new file mode 100644 (file)
index 0000000..747aa2b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/ActionProviderWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/ActionProviderWrapper.class
new file mode 100644 (file)
index 0000000..c7111d0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/ActionProviderWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/StandaloneActionMode.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/StandaloneActionMode.class
new file mode 100644 (file)
index 0000000..546d29f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/StandaloneActionMode.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.class
new file mode 100644 (file)
index 0000000..64f7c21
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.class
new file mode 100644 (file)
index 0000000..a0db78b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenu.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenu.class
new file mode 100644 (file)
index 0000000..984fbad
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenu.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItem.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItem.class
new file mode 100644 (file)
index 0000000..1b120bf
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItem.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.class
new file mode 100644 (file)
index 0000000..8d7071d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$ActionButtonSubmenu.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$ActionButtonSubmenu.class
new file mode 100644 (file)
index 0000000..728c15c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$ActionButtonSubmenu.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$HasPermanentMenuKey.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$HasPermanentMenuKey.class
new file mode 100644 (file)
index 0000000..061492e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$HasPermanentMenuKey.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OpenOverflowRunnable.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OpenOverflowRunnable.class
new file mode 100644 (file)
index 0000000..503b009
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OpenOverflowRunnable.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OverflowMenuButton.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OverflowMenuButton.class
new file mode 100644 (file)
index 0000000..4b31f64
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OverflowMenuButton.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OverflowPopup.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OverflowPopup.class
new file mode 100644 (file)
index 0000000..01507fb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$OverflowPopup.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$PopupPresenterCallback.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$PopupPresenterCallback.class
new file mode 100644 (file)
index 0000000..37d158d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$PopupPresenterCallback.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$SavedState$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$SavedState$1.class
new file mode 100644 (file)
index 0000000..5008ae8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$SavedState$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$SavedState.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$SavedState.class
new file mode 100644 (file)
index 0000000..115ca10
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter$SavedState.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.class
new file mode 100644 (file)
index 0000000..6dbc520
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView$ActionMenuChildView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView$ActionMenuChildView.class
new file mode 100644 (file)
index 0000000..bd4e448
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView$ActionMenuChildView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView$LayoutParams.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView$LayoutParams.class
new file mode 100644 (file)
index 0000000..50d67fc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView$LayoutParams.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView.class
new file mode 100644 (file)
index 0000000..a84ab5c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ActionMenuView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.class
new file mode 100644 (file)
index 0000000..b6f25ad
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ListMenuItemView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ListMenuItemView.class
new file mode 100644 (file)
index 0000000..c190507
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/ListMenuItemView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder$Callback.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder$Callback.class
new file mode 100644 (file)
index 0000000..48c1cb9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder$Callback.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder$ItemInvoker.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder$ItemInvoker.class
new file mode 100644 (file)
index 0000000..fd0e5d0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder$ItemInvoker.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder.class
new file mode 100644 (file)
index 0000000..9395c4d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuBuilder.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemImpl.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemImpl.class
new file mode 100644 (file)
index 0000000..4ecae95
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemImpl.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper$1.class
new file mode 100644 (file)
index 0000000..8dad182
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.class
new file mode 100644 (file)
index 0000000..72db404
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper$ExpandedIndexObserver.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper$ExpandedIndexObserver.class
new file mode 100644 (file)
index 0000000..2ce6f8c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper$ExpandedIndexObserver.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper$MenuAdapter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper$MenuAdapter.class
new file mode 100644 (file)
index 0000000..4a6e4c9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper$MenuAdapter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.class
new file mode 100644 (file)
index 0000000..ad6557a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPresenter$Callback.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPresenter$Callback.class
new file mode 100644 (file)
index 0000000..15e9b40
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPresenter$Callback.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPresenter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPresenter.class
new file mode 100644 (file)
index 0000000..c6ab90e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuPresenter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuView$ItemView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuView$ItemView.class
new file mode 100644 (file)
index 0000000..5f30df6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuView$ItemView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuView.class
new file mode 100644 (file)
index 0000000..fbf5f9a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuWrapper.class
new file mode 100644 (file)
index 0000000..aba5f4a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/MenuWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.class
new file mode 100644 (file)
index 0000000..e71c67d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.class
new file mode 100644 (file)
index 0000000..bda99e9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView$1.class
new file mode 100644 (file)
index 0000000..22b352b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView$VisibilityAnimListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView$VisibilityAnimListener.class
new file mode 100644 (file)
index 0000000..7360e62
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView$VisibilityAnimListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView.class
new file mode 100644 (file)
index 0000000..4f9e7ae
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/AbsActionBarView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContainer.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContainer.class
new file mode 100644 (file)
index 0000000..c4d56c5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContainer.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContextView$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContextView$1.class
new file mode 100644 (file)
index 0000000..b9e1590
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContextView$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContextView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContextView.class
new file mode 100644 (file)
index 0000000..a1ee08e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarContextView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$1.class
new file mode 100644 (file)
index 0000000..964edb3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$2.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$2.class
new file mode 100644 (file)
index 0000000..3a996ae
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$2.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$3.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$3.class
new file mode 100644 (file)
index 0000000..e8b210b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$3.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$ExpandedActionViewMenuPresenter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$ExpandedActionViewMenuPresenter.class
new file mode 100644 (file)
index 0000000..1922d89
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$ExpandedActionViewMenuPresenter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$HomeView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$HomeView.class
new file mode 100644 (file)
index 0000000..094326d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$HomeView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$SavedState$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$SavedState$1.class
new file mode 100644 (file)
index 0000000..a7ba80c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$SavedState$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$SavedState.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$SavedState.class
new file mode 100644 (file)
index 0000000..fb4c07b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView$SavedState.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView.class
new file mode 100644 (file)
index 0000000..0be7be6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ActionBarView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/CapitalizingButton.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/CapitalizingButton.class
new file mode 100644 (file)
index 0000000..1465ae4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/CapitalizingButton.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/CapitalizingTextView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/CapitalizingTextView.class
new file mode 100644 (file)
index 0000000..4b95130
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/CapitalizingTextView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.class
new file mode 100644 (file)
index 0000000..5d6d2e8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$RecycleBin.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$RecycleBin.class
new file mode 100644 (file)
index 0000000..bce3956
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$RecycleBin.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$SavedState$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$SavedState$1.class
new file mode 100644 (file)
index 0000000..b7f5fd4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$SavedState$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$SavedState.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$SavedState.class
new file mode 100644 (file)
index 0000000..4ab7e25
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner$SavedState.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner.class
new file mode 100644 (file)
index 0000000..3381ced
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAbsSpinner.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$AdapterContextMenuInfo.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$AdapterContextMenuInfo.class
new file mode 100644 (file)
index 0000000..70d41eb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$AdapterContextMenuInfo.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$AdapterDataSetObserver.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$AdapterDataSetObserver.class
new file mode 100644 (file)
index 0000000..27169b1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$AdapterDataSetObserver.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$OnItemLongClickListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$OnItemLongClickListener.class
new file mode 100644 (file)
index 0000000..de5845e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$OnItemLongClickListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$OnItemSelectedListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$OnItemSelectedListener.class
new file mode 100644 (file)
index 0000000..aa2f853
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$OnItemSelectedListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$SelectionNotifier.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$SelectionNotifier.class
new file mode 100644 (file)
index 0000000..ea5e114
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView$SelectionNotifier.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView.class
new file mode 100644 (file)
index 0000000..96c541a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsAdapterView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsLinearLayout.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsLinearLayout.class
new file mode 100644 (file)
index 0000000..6f20f85
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsLinearLayout.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$1.class
new file mode 100644 (file)
index 0000000..69efaa4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$DropDownListView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$DropDownListView.class
new file mode 100644 (file)
index 0000000..b272033
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$DropDownListView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$ListSelectorHider.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$ListSelectorHider.class
new file mode 100644 (file)
index 0000000..4a81a4c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$ListSelectorHider.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupDataSetObserver.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupDataSetObserver.class
new file mode 100644 (file)
index 0000000..ec726ae
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupDataSetObserver.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupScrollListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupScrollListener.class
new file mode 100644 (file)
index 0000000..13db214
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupScrollListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupTouchInterceptor.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupTouchInterceptor.class
new file mode 100644 (file)
index 0000000..cbdfee5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$PopupTouchInterceptor.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$ResizePopupRunnable.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$ResizePopupRunnable.class
new file mode 100644 (file)
index 0000000..77b6112
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow$ResizePopupRunnable.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow.class
new file mode 100644 (file)
index 0000000..cf7938f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsListPopupWindow.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$AccessibilityEventSender.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$AccessibilityEventSender.class
new file mode 100644 (file)
index 0000000..ca6f3b7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$AccessibilityEventSender.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$RefreshProgressRunnable.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$RefreshProgressRunnable.class
new file mode 100644 (file)
index 0000000..4fc92e7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$RefreshProgressRunnable.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$SavedState$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$SavedState$1.class
new file mode 100644 (file)
index 0000000..1ffe42b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$SavedState$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$SavedState.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$SavedState.class
new file mode 100644 (file)
index 0000000..344299f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar$SavedState.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar.class
new file mode 100644 (file)
index 0000000..1dfd7f3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsProgressBar.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropDownAdapter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropDownAdapter.class
new file mode 100644 (file)
index 0000000..464dd5b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropDownAdapter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropdownPopup$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropdownPopup$1.class
new file mode 100644 (file)
index 0000000..302265b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropdownPopup$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropdownPopup.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropdownPopup.class
new file mode 100644 (file)
index 0000000..5b64612
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$DropdownPopup.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$SpinnerPopup.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$SpinnerPopup.class
new file mode 100644 (file)
index 0000000..b4b1e9c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner$SpinnerPopup.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner.class
new file mode 100644 (file)
index 0000000..af41e52
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsSpinner.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsView.class
new file mode 100644 (file)
index 0000000..5f35824
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/IcsView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$1.class
new file mode 100644 (file)
index 0000000..65980f2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabAdapter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabAdapter.class
new file mode 100644 (file)
index 0000000..00dd304
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabAdapter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabClickListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabClickListener.class
new file mode 100644 (file)
index 0000000..71ff8a5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabClickListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabView.class
new file mode 100644 (file)
index 0000000..0910edf
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$TabView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$VisibilityAnimListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$VisibilityAnimListener.class
new file mode 100644 (file)
index 0000000..51d073d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView$VisibilityAnimListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.class
new file mode 100644 (file)
index 0000000..9553dff
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionMode$Callback.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionMode$Callback.class
new file mode 100644 (file)
index 0000000..c122c6d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionMode$Callback.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionMode.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionMode.class
new file mode 100644 (file)
index 0000000..cc64b67
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionMode.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionProvider$SubUiVisibilityListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionProvider$SubUiVisibilityListener.class
new file mode 100644 (file)
index 0000000..48f981a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionProvider$SubUiVisibilityListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionProvider.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionProvider.class
new file mode 100644 (file)
index 0000000..1699a0f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/ActionProvider.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/CollapsibleActionView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/CollapsibleActionView.class
new file mode 100644 (file)
index 0000000..e33c666
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/CollapsibleActionView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Menu.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Menu.class
new file mode 100644 (file)
index 0000000..917380a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Menu.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater$InflatedOnMenuItemClickListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater$InflatedOnMenuItemClickListener.class
new file mode 100644 (file)
index 0000000..87ae93f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater$InflatedOnMenuItemClickListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater$MenuState.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater$MenuState.class
new file mode 100644 (file)
index 0000000..0c03c6c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater$MenuState.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater.class
new file mode 100644 (file)
index 0000000..ce2200c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuInflater.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem$OnActionExpandListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem$OnActionExpandListener.class
new file mode 100644 (file)
index 0000000..c905524
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem$OnActionExpandListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem$OnMenuItemClickListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem$OnMenuItemClickListener.class
new file mode 100644 (file)
index 0000000..67695af
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem$OnMenuItemClickListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem.class
new file mode 100644 (file)
index 0000000..647b333
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/MenuItem.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/SubMenu.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/SubMenu.class
new file mode 100644 (file)
index 0000000..6bb94ff
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/SubMenu.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Window$Callback.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Window$Callback.class
new file mode 100644 (file)
index 0000000..7dfe356
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Window$Callback.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Window.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Window.class
new file mode 100644 (file)
index 0000000..13353f8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/view/Window.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivityChooserModelClient.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivityChooserModelClient.class
new file mode 100644 (file)
index 0000000..10861aa
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivityChooserModelClient.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivityResolveInfo.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivityResolveInfo.class
new file mode 100644 (file)
index 0000000..f1aec6d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivityResolveInfo.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivitySorter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivitySorter.class
new file mode 100644 (file)
index 0000000..3c1a4ee
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$ActivitySorter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$DefaultSorter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$DefaultSorter.class
new file mode 100644 (file)
index 0000000..f462a6f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$DefaultSorter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoricalRecord.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoricalRecord.class
new file mode 100644 (file)
index 0000000..7de936f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoricalRecord.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryLoader$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryLoader$1.class
new file mode 100644 (file)
index 0000000..5a7e018
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryLoader$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryLoader.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryLoader.class
new file mode 100644 (file)
index 0000000..d08e2ae
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryLoader.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryPersister.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryPersister.class
new file mode 100644 (file)
index 0000000..4a0ff82
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$HistoryPersister.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$OnChooseActivityListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$OnChooseActivityListener.class
new file mode 100644 (file)
index 0000000..151d2d5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$OnChooseActivityListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$SerialExecutor$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$SerialExecutor$1.class
new file mode 100644 (file)
index 0000000..5a8476b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$SerialExecutor$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$SerialExecutor.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$SerialExecutor.class
new file mode 100644 (file)
index 0000000..1e98dd2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel$SerialExecutor.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel.class
new file mode 100644 (file)
index 0000000..d933174
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserModel.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$1.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$1.class
new file mode 100644 (file)
index 0000000..9e35e28
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$1.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$2.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$2.class
new file mode 100644 (file)
index 0000000..895599e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$2.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$3.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$3.class
new file mode 100644 (file)
index 0000000..41aceb9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$3.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$ActivityChooserViewAdapter.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$ActivityChooserViewAdapter.class
new file mode 100644 (file)
index 0000000..9c05996
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$ActivityChooserViewAdapter.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$Callbacks.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$Callbacks.class
new file mode 100644 (file)
index 0000000..806c9a5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$Callbacks.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$SetActivated.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$SetActivated.class
new file mode 100644 (file)
index 0000000..a42d8f2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView$SetActivated.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView.class
new file mode 100644 (file)
index 0000000..f457429
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ActivityChooserView.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$OnShareTargetSelectedListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$OnShareTargetSelectedListener.class
new file mode 100644 (file)
index 0000000..25d140b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$OnShareTargetSelectedListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$ShareAcitivityChooserModelPolicy.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$ShareAcitivityChooserModelPolicy.class
new file mode 100644 (file)
index 0000000..6fb964b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$ShareAcitivityChooserModelPolicy.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener.class
new file mode 100644 (file)
index 0000000..acbf8a6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider$ShareMenuItemOnMenuItemClickListener.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider.class b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider.class
new file mode 100644 (file)
index 0000000..51329f7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/classes/com/actionbarsherlock/widget/ShareActionProvider.class differ
diff --git a/android-libraries/ActionBarSherlock/bin/jarlist.cache b/android-libraries/ActionBarSherlock/bin/jarlist.cache
new file mode 100644 (file)
index 0000000..1b5ec3f
--- /dev/null
@@ -0,0 +1,3 @@
+# cache for current jar dependecy. DO NOT EDIT.
+# format is <lastModified> <length> <SHA-1> <path>
+# Encoding is UTF-8
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..42bb366
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png
new file mode 100644 (file)
index 0000000..d12d923
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..612889a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..9a80fb7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..2b4a61a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644 (file)
index 0000000..75d3269
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644 (file)
index 0000000..ca7df22
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..b110188
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..95c76e3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png
new file mode 100644 (file)
index 0000000..d6b9634
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..20d7080
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..1dc40c9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..48bc536
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..46fcf71
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..2adaa18
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..629911f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..11c7940
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..720f52d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..6e4332f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..ac9f39b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..932b70a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..f4ddedf
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png
new file mode 100644 (file)
index 0000000..fc2e90a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png
new file mode 100644 (file)
index 0000000..2d8352b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png
new file mode 100644 (file)
index 0000000..365e83e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png
new file mode 100644 (file)
index 0000000..0a42fb2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png
new file mode 100644 (file)
index 0000000..8051417
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__dialog_full_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__dialog_full_holo_light.9.png
new file mode 100644 (file)
index 0000000..c9065de
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__dialog_full_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png
new file mode 100644 (file)
index 0000000..9deb8f0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_ab_back_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_ab_back_holo_light.png
new file mode 100644 (file)
index 0000000..5b29b1c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_ab_back_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png
new file mode 100644 (file)
index 0000000..bd2d459
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_cab_done_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_cab_done_holo_light.png
new file mode 100644 (file)
index 0000000..c6c30a1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_cab_done_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644 (file)
index 0000000..cb6ebda
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644 (file)
index 0000000..48d4728
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644 (file)
index 0000000..f5c5130
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_share_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_share_holo_light.png
new file mode 100644 (file)
index 0000000..7c12c57
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__ic_menu_share_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_activated_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_activated_holo.9.png
new file mode 100644 (file)
index 0000000..4da70ac
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_activated_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_divider_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_divider_holo_dark.9.png
new file mode 100644 (file)
index 0000000..a57e66a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_divider_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_divider_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_divider_holo_light.9.png
new file mode 100644 (file)
index 0000000..75bd2d7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_divider_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_focused_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_focused_holo.9.png
new file mode 100644 (file)
index 0000000..f958728
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_longpressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_longpressed_holo.9.png
new file mode 100644 (file)
index 0000000..4da70ac
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_longpressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..d3e7241
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..d3e7241
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_selector_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_selector_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..cb12896
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_selector_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_selector_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_selector_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..233da8e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__list_selector_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png
new file mode 100644 (file)
index 0000000..29ad572
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png
new file mode 100644 (file)
index 0000000..612b887
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png
new file mode 100644 (file)
index 0000000..6cde0bd
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_bg_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_bg_holo_light.9.png
new file mode 100644 (file)
index 0000000..82af131
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_bg_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..15f110b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_primary_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_primary_holo_light.9.png
new file mode 100644 (file)
index 0000000..15f110b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_primary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..4bf430f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png
new file mode 100644 (file)
index 0000000..4bf430f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_48_inner_holo.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_48_inner_holo.png
new file mode 100644 (file)
index 0000000..919c328
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_48_inner_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_48_outer_holo.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_48_outer_holo.png
new file mode 100644 (file)
index 0000000..ad987cb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_48_outer_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..9ae770c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..e932dee
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..5caed9d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..55abe71
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..8874292
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..a071008
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..8747bfc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..6893b36
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png
new file mode 100644 (file)
index 0000000..1e6ab9a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_holo.9.png
new file mode 100644 (file)
index 0000000..4dfaac8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..4060199
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_unselected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_unselected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..86304e5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/abs__tab_unselected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/ic_launcher.png b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..bcfa058
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-hdpi/ic_launcher.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-ldpi/ic_launcher.png b/android-libraries/ActionBarSherlock/bin/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..dd7c05b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-ldpi/ic_launcher.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..c2fef9a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png
new file mode 100644 (file)
index 0000000..54c8223
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..baa5298
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..fed7fa6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..d582d39
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644 (file)
index 0000000..735c049
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644 (file)
index 0000000..1071e09
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..a9f2be4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..a51dc9b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png
new file mode 100644 (file)
index 0000000..89eccd4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..fa4ca75
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..f2f6fc7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..6584f95
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..f3a769b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..06010e9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..ff64b45
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..b1ac62c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..f292424
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..b1d51c6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..10b0432
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..9632995
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..0837e7d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png
new file mode 100644 (file)
index 0000000..0a71f49
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png
new file mode 100644 (file)
index 0000000..4e4e516
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png
new file mode 100644 (file)
index 0000000..a6c5c8f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png
new file mode 100644 (file)
index 0000000..9da38a3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png
new file mode 100644 (file)
index 0000000..58d8dc1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__dialog_full_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__dialog_full_holo_light.9.png
new file mode 100644 (file)
index 0000000..f5a473b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__dialog_full_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png
new file mode 100644 (file)
index 0000000..7290c5c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_ab_back_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_ab_back_holo_light.png
new file mode 100644 (file)
index 0000000..7d944d3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_ab_back_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png
new file mode 100644 (file)
index 0000000..3382680
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_cab_done_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_cab_done_holo_light.png
new file mode 100644 (file)
index 0000000..f11b21f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_cab_done_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644 (file)
index 0000000..3b4e746
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644 (file)
index 0000000..aa5ea4f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644 (file)
index 0000000..00e499c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_share_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_share_holo_light.png
new file mode 100644 (file)
index 0000000..240d406
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__ic_menu_share_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_activated_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_activated_holo.9.png
new file mode 100644 (file)
index 0000000..92030f2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_activated_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_divider_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_divider_holo_dark.9.png
new file mode 100644 (file)
index 0000000..a57e66a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_divider_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_divider_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_divider_holo_light.9.png
new file mode 100644 (file)
index 0000000..75bd2d7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_divider_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_focused_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_focused_holo.9.png
new file mode 100644 (file)
index 0000000..7c9fdbf
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_longpressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_longpressed_holo.9.png
new file mode 100644 (file)
index 0000000..92030f2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_longpressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..d6717c1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..d6717c1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_selector_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_selector_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..9428f21
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_selector_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_selector_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_selector_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..80cd8e6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__list_selector_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png
new file mode 100644 (file)
index 0000000..99cf362
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png
new file mode 100644 (file)
index 0000000..5063687
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png
new file mode 100644 (file)
index 0000000..efe935f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_bg_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_bg_holo_light.9.png
new file mode 100644 (file)
index 0000000..8672828
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_bg_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..333dda5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_primary_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_primary_holo_light.9.png
new file mode 100644 (file)
index 0000000..333dda5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_primary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..29ffde6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png
new file mode 100644 (file)
index 0000000..29ffde6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_48_inner_holo.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_48_inner_holo.png
new file mode 100644 (file)
index 0000000..ff1dc7f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_48_inner_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_48_outer_holo.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_48_outer_holo.png
new file mode 100644 (file)
index 0000000..0b113bf
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_48_outer_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..6c63dd4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..3928d0d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..f7219e8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..ede8b34
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..e4de3f6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..334ec16
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..8d9531e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..0f504f8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png
new file mode 100644 (file)
index 0000000..bce0e08
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_holo.9.png
new file mode 100644 (file)
index 0000000..dd022de
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..2852fb5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_selected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..d2716b3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/ic_launcher.png b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..85848ff
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-mdpi/ic_launcher.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..d01fae9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png
new file mode 100644 (file)
index 0000000..5fc7d87
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..f6cbc62
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..f395cbd
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..6e6b999
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644 (file)
index 0000000..ca2e57b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644 (file)
index 0000000..a57c1b5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..2c4dd4f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..27d6c8b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png
new file mode 100644 (file)
index 0000000..5826306
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..3e72223
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..d2d7754
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..140518f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..97a6bd5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..3069943
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..920d2b5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..dfe7406
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..959ca7a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..df97212
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..7920188
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..1801d34
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..b3d3e19
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png
new file mode 100644 (file)
index 0000000..1bf70ca
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png
new file mode 100644 (file)
index 0000000..100d316
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png
new file mode 100644 (file)
index 0000000..58bdedd
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png
new file mode 100644 (file)
index 0000000..66d9d8d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png
new file mode 100644 (file)
index 0000000..86e2458
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png
new file mode 100644 (file)
index 0000000..b405843
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png
new file mode 100644 (file)
index 0000000..bfc1c66
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png
new file mode 100644 (file)
index 0000000..87a5a42
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png
new file mode 100644 (file)
index 0000000..fd5f416
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png
new file mode 100644 (file)
index 0000000..0ccab80
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644 (file)
index 0000000..ef9792a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644 (file)
index 0000000..3f275ad
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644 (file)
index 0000000..4492c49
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png
new file mode 100644 (file)
index 0000000..a61854b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_activated_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_activated_holo.9.png
new file mode 100644 (file)
index 0000000..c6cbc4d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_activated_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png
new file mode 100644 (file)
index 0000000..c1692f8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_divider_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_divider_holo_light.9.png
new file mode 100644 (file)
index 0000000..e190cfc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_divider_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_focused_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_focused_holo.9.png
new file mode 100644 (file)
index 0000000..9059f3e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_longpressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_longpressed_holo.9.png
new file mode 100644 (file)
index 0000000..c6cbc4d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_longpressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..8acdbf4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..8acdbf4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..0117091
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..4f12302
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png
new file mode 100644 (file)
index 0000000..d910806
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png
new file mode 100644 (file)
index 0000000..68494e7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png
new file mode 100644 (file)
index 0000000..b8a964b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png
new file mode 100644 (file)
index 0000000..380f8d1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..a6bd0ce
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png
new file mode 100644 (file)
index 0000000..a6bd0ce
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..058c512
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png
new file mode 100644 (file)
index 0000000..058c512
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_48_inner_holo.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_48_inner_holo.png
new file mode 100644 (file)
index 0000000..662036c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_48_inner_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_48_outer_holo.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_48_outer_holo.png
new file mode 100644 (file)
index 0000000..6d33f31
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_48_outer_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..487c06b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..3724097
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..b7088e1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..8e91ab9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..e16fead
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..475dfcd
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..3b6ec51
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..6e82972
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png
new file mode 100644 (file)
index 0000000..140ebfd
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_holo.9.png
new file mode 100644 (file)
index 0000000..a94f098
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..25ec789
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..c5ed3cb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/ic_launcher.png b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..916901e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/bin/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/android-libraries/ActionBarSherlock/gen/com/actionbarsherlock/BuildConfig.java b/android-libraries/ActionBarSherlock/gen/com/actionbarsherlock/BuildConfig.java
new file mode 100644 (file)
index 0000000..ceb2ab0
--- /dev/null
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package com.actionbarsherlock;
+
+public final class BuildConfig {
+    public final static boolean DEBUG = true;
+}
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/gen/com/actionbarsherlock/R.java b/android-libraries/ActionBarSherlock/gen/com/actionbarsherlock/R.java
new file mode 100644 (file)
index 0000000..b48b624
--- /dev/null
@@ -0,0 +1,2813 @@
+/* AUTO-GENERATED FILE.  DO NOT MODIFY.\r
+ *\r
+ * This class was automatically generated by the\r
+ * aapt tool from the resource data it found.  It\r
+ * should not be modified by hand.\r
+ */\r
+\r
+package com.actionbarsherlock;\r
+\r
+public final class R {\r
+    public static final class attr {\r
+        /**  Specified if we are forcing an action item overflow menu. \r
+         <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int absForceOverflow=0x7f010039;\r
+        /**  Custom divider drawable to use for elements in the action bar. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionBarDivider=0x7f01000e;\r
+        /**  Custom item state list drawable background for action bar items. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionBarItemBackground=0x7f01000f;\r
+        /**  Size of the Action Bar, including the contextual\r
+             bar used to present Action Modes. \r
+         <p>May be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+<p>May be one of the following constant values.</p>\r
+<table>\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\r
+<tr><td><code>wrap_content</code></td><td>0</td><td></td></tr>\r
+</table>\r
+         */\r
+        public static int actionBarSize=0x7f01000d;\r
+        /**  Reference to a style for the split Action Bar. This style\r
+             controls the split component that holds the menu/action\r
+             buttons. actionBarStyle is still used for the primary\r
+             bar. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionBarSplitStyle=0x7f01000b;\r
+        /**  Reference to a style for the Action Bar \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionBarStyle=0x7f01000a;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionBarTabBarStyle=0x7f010007;\r
+        /**  Default style for tabs within an action bar \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionBarTabStyle=0x7f010006;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionBarTabTextStyle=0x7f010008;\r
+        /**  Reference to a theme that should be used to inflate widgets\r
+             and layouts destined for the action bar. Most of the time\r
+             this will be a reference to the current theme, but when\r
+             the action bar has a significantly different contrast\r
+             profile than the rest of the activity the difference\r
+             can become important. If this is set to @null the current\r
+             theme will be used.\r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionBarWidgetTheme=0x7f01000c;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionButtonStyle=0x7f01002b;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionDropDownStyle=0x7f01002a;\r
+        /**  TextAppearance style that will be applied to text that\r
+             appears within action menu items. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionMenuTextAppearance=0x7f010010;\r
+        /**  Color for text that appears within action menu items. \r
+         <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int actionMenuTextColor=0x7f010011;\r
+        /**  Background drawable to use for action mode UI \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionModeBackground=0x7f010014;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionModeCloseButtonStyle=0x7f010013;\r
+        /**  Drawable to use for the close action mode button \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionModeCloseDrawable=0x7f010016;\r
+        /**  PopupWindow style to use for action modes when showing as a window overlay. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionModePopupWindowStyle=0x7f010018;\r
+        /**  Drawable to use for the Share action button in WebView selection action modes \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionModeShareDrawable=0x7f010017;\r
+        /**  Background drawable to use for action mode UI in the lower split bar \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionModeSplitBackground=0x7f010015;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionModeStyle=0x7f010012;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionOverflowButtonStyle=0x7f010009;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int actionSpinnerItemStyle=0x7f010030;\r
+        /**  Drawable used as a background for activated items. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int activatedBackgroundIndicator=0x7f010038;\r
+        /**  Default ActivityChooserView style. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int activityChooserViewStyle=0x7f010037;\r
+        /** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int background=0x7f010002;\r
+        /** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int backgroundSplit=0x7f010003;\r
+        /**  Specifies a background drawable for a second stacked row of the action bar. \r
+         <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int backgroundStacked=0x7f010040;\r
+        /**  Small Button style. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int buttonStyleSmall=0x7f010019;\r
+        /**  Specifies a layout for custom navigation. Overrides navigationMode. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int customNavigationLayout=0x7f010041;\r
+        /**  Options affecting how the action bar is displayed. \r
+         <p>Must be one or more (separated by '|') of the following constant values.</p>\r
+<table>\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\r
+<tr><td><code>useLogo</code></td><td>0x1</td><td></td></tr>\r
+<tr><td><code>showHome</code></td><td>0x2</td><td></td></tr>\r
+<tr><td><code>homeAsUp</code></td><td>0x4</td><td></td></tr>\r
+<tr><td><code>showTitle</code></td><td>0x8</td><td></td></tr>\r
+<tr><td><code>showCustom</code></td><td>0x10</td><td></td></tr>\r
+<tr><td><code>disableHome</code></td><td>0x20</td><td></td></tr>\r
+</table>\r
+         */\r
+        public static int displayOptions=0x7f01003b;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int divider=0x7f010005;\r
+        /**  Drawable to use for generic vertical dividers. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int dividerVertical=0x7f010029;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int dropDownListViewStyle=0x7f01002d;\r
+        /** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int dropdownListPreferredItemHeight=0x7f01002f;\r
+        /**  The drawable to show in the button for expanding the activities overflow popup.\r
+             <strong>Note:</strong> Clients would like to set this drawable\r
+             as a clue about the action the chosen activity will perform. For\r
+             example, if share activity is to be chosen the drawable should\r
+             give a clue that sharing is to be performed.\r
+         \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int expandActivityOverflowButtonDrawable=0x7f010050;\r
+        /**  Default background for the menu header. \r
+         <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int headerBackground=0x7f01004a;\r
+        /** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int height=0x7f010004;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int homeAsUpIndicator=0x7f01002c;\r
+        /**  Specifies a layout to use for the "home" section of the action bar. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int homeLayout=0x7f010042;\r
+        /**  Default horizontal divider between rows of menu items. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int horizontalDivider=0x7f010048;\r
+        /**  Specifies the drawable used for the application icon. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int icon=0x7f01003e;\r
+        /**  Specifies a style resource to use for an indeterminate progress spinner. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int indeterminateProgressStyle=0x7f010044;\r
+        /**  The maximal number of items initially shown in the activity list. \r
+         <p>Must be a string value, using '\\;' to escape characters such as '\\n' or '\\uxxxx' for a unicode character.\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int initialActivityCount=0x7f01004f;\r
+        /**  Default background for each menu item. \r
+         <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int itemBackground=0x7f01004b;\r
+        /**  Default disabled icon alpha for each menu item that shows an icon. \r
+         <p>Must be a floating point value, such as "<code>1.2</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int itemIconDisabledAlpha=0x7f01004d;\r
+        /**  Specifies padding that should be applied to the left and right sides of\r
+             system-provided items in the bar. \r
+         <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int itemPadding=0x7f010046;\r
+        /**  Default appearance of menu item text. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int itemTextAppearance=0x7f010047;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int listPopupWindowStyle=0x7f010036;\r
+        /**  A smaller, sleeker list item height. \r
+         <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int listPreferredItemHeightSmall=0x7f010023;\r
+        /**  The preferred padding along the left edge of list items. \r
+         <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int listPreferredItemPaddingLeft=0x7f010024;\r
+        /**  The preferred padding along the right edge of list items. \r
+         <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int listPreferredItemPaddingRight=0x7f010025;\r
+        /**  Specifies the drawable used for the application logo. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int logo=0x7f01003f;\r
+        /**  The type of navigation to use. \r
+         <p>Must be one of the following constant values.</p>\r
+<table>\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\r
+<tr><td><code>normal</code></td><td>0</td><td> Normal static title text </td></tr>\r
+<tr><td><code>listMode</code></td><td>1</td><td> The action bar will use a selection list for navigation. </td></tr>\r
+<tr><td><code>tabMode</code></td><td>2</td><td> The action bar will use a series of horizontal tabs for navigation. </td></tr>\r
+</table>\r
+         */\r
+        public static int navigationMode=0x7f01003a;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int popupMenuStyle=0x7f01002e;\r
+        /**  Whether space should be reserved in layout when an icon is missing. \r
+         <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int preserveIconSpacing=0x7f01004e;\r
+        /**  Specifies the horizontal padding on either end for an embedded progress bar. \r
+         <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int progressBarPadding=0x7f010045;\r
+        /**  Specifies a style resource to use for an embedded progress bar. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int progressBarStyle=0x7f010043;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int spinnerDropDownItemStyle=0x7f010022;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int spinnerItemStyle=0x7f010021;\r
+        /**  Specifies subtitle text used for navigationMode="normal" \r
+         <p>Must be a string value, using '\\;' to escape characters such as '\\n' or '\\uxxxx' for a unicode character.\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int subtitle=0x7f01003d;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int subtitleTextStyle=0x7f010001;\r
+        /**  Text color, typeface, size, and style for the text inside of a popup menu. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int textAppearanceLargePopupMenu=0x7f01001b;\r
+        /**  The preferred TextAppearance for the primary text of small list items. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int textAppearanceListItemSmall=0x7f010026;\r
+        /**  Text color, typeface, size, and style for "small" text. Defaults to secondary text color. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int textAppearanceSmall=0x7f01001d;\r
+        /**  Text color, typeface, size, and style for small text inside of a popup menu. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int textAppearanceSmallPopupMenu=0x7f01001c;\r
+        /** <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int textColorPrimary=0x7f01001e;\r
+        /** <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int textColorPrimaryDisableOnly=0x7f01001f;\r
+        /** <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int textColorPrimaryInverse=0x7f010020;\r
+        /**  Specifies title text used for navigationMode="normal" \r
+         <p>Must be a string value, using '\\;' to escape characters such as '\\n' or '\\uxxxx' for a unicode character.\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int title=0x7f01003c;\r
+        /** <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int titleTextStyle=0x7f010000;\r
+        /**  Default vertical divider between menu items. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int verticalDivider=0x7f010049;\r
+        /** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int windowActionBar=0x7f010032;\r
+        /** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int windowActionBarOverlay=0x7f010033;\r
+        /** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int windowActionModeOverlay=0x7f010034;\r
+        /**  Default animations for the menu. \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int windowAnimationStyle=0x7f01004c;\r
+        /**  This Drawable is overlaid over the foreground of the Window's content area, usually\r
+             to place a shadow below the title.  \r
+         <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+         */\r
+        public static int windowContentOverlay=0x7f01001a;\r
+        /** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int windowMinWidthMajor=0x7f010027;\r
+        /** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int windowMinWidthMinor=0x7f010028;\r
+        /** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int windowNoTitle=0x7f010031;\r
+        /** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int windowSplitActionBar=0x7f010035;\r
+    }\r
+    public static final class bool {\r
+        public static int abs__action_bar_embed_tabs=0x7f050000;\r
+        public static int abs__action_bar_expanded_action_views_exclusive=0x7f050002;\r
+        /**  Whether action menu items should be displayed in ALLCAPS or not.\r
+         Defaults to true. If this is not appropriate for specific locales\r
+         it should be disabled in that locale's resources. \r
+         */\r
+        public static int abs__config_actionMenuItemAllCaps=0x7f050004;\r
+        /**  Whether action menu items should obey the "withText" showAsAction\r
+         flag. This may be set to false for situations where space is\r
+         extremely limited. \r
+ Whether action menu items should obey the "withText" showAsAction\r
+         flag. This may be set to false for situations where space is\r
+         extremely limited. \r
+         */\r
+        public static int abs__config_allowActionMenuItemTextWithIcon=0x7f050005;\r
+        /**  Sets whether menu shortcuts should be displayed on panel menus when\r
+         a keyboard is present. \r
+         */\r
+        public static int abs__config_showMenuShortcutsWhenKeyboardPresent=0x7f050003;\r
+        public static int abs__split_action_bar_is_narrow=0x7f050001;\r
+    }\r
+    public static final class color {\r
+        public static int abs__background_holo_dark=0x7f060000;\r
+        public static int abs__background_holo_light=0x7f060001;\r
+        public static int abs__bright_foreground_disabled_holo_dark=0x7f060004;\r
+        public static int abs__bright_foreground_disabled_holo_light=0x7f060005;\r
+        public static int abs__bright_foreground_holo_dark=0x7f060002;\r
+        public static int abs__bright_foreground_holo_light=0x7f060003;\r
+        public static int abs__bright_foreground_inverse_holo_dark=0x7f060006;\r
+        public static int abs__bright_foreground_inverse_holo_light=0x7f060007;\r
+        public static int abs__holo_blue_light=0x7f060008;\r
+        public static int abs__primary_text_disable_only_holo_dark=0x7f060009;\r
+        public static int abs__primary_text_disable_only_holo_light=0x7f06000a;\r
+        public static int abs__primary_text_holo_dark=0x7f06000b;\r
+        public static int abs__primary_text_holo_light=0x7f06000c;\r
+    }\r
+    public static final class dimen {\r
+        /**  Default height of an action bar. \r
+ Default height of an action bar. \r
+ Default height of an action bar. \r
+ Default height of an action bar. \r
+ Default height of an action bar. \r
+ Default height of an action bar. \r
+ Default height of an action bar. \r
+ Default height of an action bar. \r
+         */\r
+        public static int abs__action_bar_default_height=0x7f070001;\r
+        /**  Vertical padding around action bar icons. \r
+ Vertical padding around action bar icons. \r
+ Vertical padding around action bar icons. \r
+ Vertical padding around action bar icons. \r
+ Vertical padding around action bar icons. \r
+ Vertical padding around action bar icons. \r
+ Vertical padding around action bar icons. \r
+ Vertical padding around action bar icons. \r
+         */\r
+        public static int abs__action_bar_icon_vertical_padding=0x7f070002;\r
+        /**  Bottom margin for action bar subtitles \r
+ Bottom margin for action bar subtitles \r
+ Bottom margin for action bar subtitles \r
+ Bottom margin for action bar subtitles \r
+ Bottom margin for action bar subtitles \r
+ Bottom margin for action bar subtitles \r
+ Bottom margin for action bar subtitles \r
+ Bottom margin for action bar subtitles \r
+         */\r
+        public static int abs__action_bar_subtitle_bottom_margin=0x7f070006;\r
+        /**  Text size for action bar subtitles \r
+ Text size for action bar subtitles \r
+ Text size for action bar subtitles \r
+ Text size for action bar subtitles \r
+ Text size for action bar subtitles \r
+ Text size for action bar subtitles \r
+ Text size for action bar subtitles \r
+ Text size for action bar subtitles \r
+         */\r
+        public static int abs__action_bar_subtitle_text_size=0x7f070004;\r
+        /**  Top margin for action bar subtitles \r
+ Top margin for action bar subtitles \r
+ Top margin for action bar subtitles \r
+ Top margin for action bar subtitles \r
+ Top margin for action bar subtitles \r
+ Top margin for action bar subtitles \r
+ Top margin for action bar subtitles \r
+ Top margin for action bar subtitles \r
+         */\r
+        public static int abs__action_bar_subtitle_top_margin=0x7f070005;\r
+        /**  Text size for action bar titles \r
+ Text size for action bar titles \r
+ Text size for action bar titles \r
+ Text size for action bar titles \r
+ Text size for action bar titles \r
+ Text size for action bar titles \r
+ Text size for action bar titles \r
+ Text size for action bar titles \r
+         */\r
+        public static int abs__action_bar_title_text_size=0x7f070003;\r
+        /**  Minimum width for an action button in the menu area of an action bar \r
+ Minimum width for an action button in the menu area of an action bar \r
+         */\r
+        public static int abs__action_button_min_width=0x7f070007;\r
+        /**  Dialog title height \r
+         */\r
+        public static int abs__alert_dialog_title_height=0x7f070008;\r
+        /**  The maximum width we would prefer dialogs to be.  0 if there is no\r
+         maximum (let them grow as large as the screen).  Actual values are\r
+         specified for -large and -xlarge configurations. \r
+         */\r
+        public static int abs__config_prefDialogWidth=0x7f070000;\r
+        /**  The platform's desired minimum size for a dialog's width when it\r
+         is along the major axis (that is the screen is landscape).  This may\r
+         be either a fraction or a dimension. \r
+ The platform's desired minimum size for a dialog's width when it\r
+         is along the major axis (that is the screen is landscape).  This may\r
+         be either a fraction or a dimension. \r
+ The platform's desired minimum size for a dialog's width when it\r
+         is along the major axis (that is the screen is landscape).  This may\r
+         be either a fraction or a dimension. \r
+         */\r
+        public static int abs__dialog_min_width_major=0x7f070009;\r
+        /**  The platform's desired minimum size for a dialog's width when it\r
+         is along the minor axis (that is the screen is portrait).  This may\r
+         be either a fraction or a dimension. \r
+ The platform's desired minimum size for a dialog's width when it\r
+         is along the minor axis (that is the screen is portrait).  This may\r
+         be either a fraction or a dimension. \r
+ The platform's desired minimum size for a dialog's width when it\r
+         is along the minor axis (that is the screen is portrait).  This may\r
+         be either a fraction or a dimension. \r
+         */\r
+        public static int abs__dialog_min_width_minor=0x7f07000a;\r
+        /**  Minimum width for an action button in the menu area of an action bar \r
+ Minimum width for an action button in the menu area of an action bar \r
+         */\r
+        public static int action_button_min_width=0x7f07000b;\r
+    }\r
+    public static final class drawable {\r
+        public static int abs__ab_bottom_solid_dark_holo=0x7f020000;\r
+        public static int abs__ab_bottom_solid_inverse_holo=0x7f020001;\r
+        public static int abs__ab_bottom_solid_light_holo=0x7f020002;\r
+        public static int abs__ab_bottom_transparent_dark_holo=0x7f020003;\r
+        public static int abs__ab_bottom_transparent_light_holo=0x7f020004;\r
+        public static int abs__ab_share_pack_holo_dark=0x7f020005;\r
+        public static int abs__ab_share_pack_holo_light=0x7f020006;\r
+        public static int abs__ab_solid_dark_holo=0x7f020007;\r
+        public static int abs__ab_solid_light_holo=0x7f020008;\r
+        public static int abs__ab_solid_shadow_holo=0x7f020009;\r
+        public static int abs__ab_stacked_solid_dark_holo=0x7f02000a;\r
+        public static int abs__ab_stacked_solid_light_holo=0x7f02000b;\r
+        public static int abs__ab_stacked_transparent_dark_holo=0x7f02000c;\r
+        public static int abs__ab_stacked_transparent_light_holo=0x7f02000d;\r
+        public static int abs__ab_transparent_dark_holo=0x7f02000e;\r
+        public static int abs__ab_transparent_light_holo=0x7f02000f;\r
+        public static int abs__activated_background_holo_dark=0x7f020010;\r
+        public static int abs__activated_background_holo_light=0x7f020011;\r
+        public static int abs__btn_cab_done_default_holo_dark=0x7f020012;\r
+        public static int abs__btn_cab_done_default_holo_light=0x7f020013;\r
+        public static int abs__btn_cab_done_focused_holo_dark=0x7f020014;\r
+        public static int abs__btn_cab_done_focused_holo_light=0x7f020015;\r
+        public static int abs__btn_cab_done_holo_dark=0x7f020016;\r
+        public static int abs__btn_cab_done_holo_light=0x7f020017;\r
+        public static int abs__btn_cab_done_pressed_holo_dark=0x7f020018;\r
+        public static int abs__btn_cab_done_pressed_holo_light=0x7f020019;\r
+        public static int abs__cab_background_bottom_holo_dark=0x7f02001a;\r
+        public static int abs__cab_background_bottom_holo_light=0x7f02001b;\r
+        public static int abs__cab_background_top_holo_dark=0x7f02001c;\r
+        public static int abs__cab_background_top_holo_light=0x7f02001d;\r
+        public static int abs__dialog_full_holo_dark=0x7f02001e;\r
+        public static int abs__dialog_full_holo_light=0x7f02001f;\r
+        public static int abs__ic_ab_back_holo_dark=0x7f020020;\r
+        public static int abs__ic_ab_back_holo_light=0x7f020021;\r
+        public static int abs__ic_cab_done_holo_dark=0x7f020022;\r
+        public static int abs__ic_cab_done_holo_light=0x7f020023;\r
+        public static int abs__ic_menu_moreoverflow_holo_dark=0x7f020024;\r
+        public static int abs__ic_menu_moreoverflow_holo_light=0x7f020025;\r
+        public static int abs__ic_menu_moreoverflow_normal_holo_dark=0x7f020026;\r
+        public static int abs__ic_menu_moreoverflow_normal_holo_light=0x7f020027;\r
+        public static int abs__ic_menu_share_holo_dark=0x7f020028;\r
+        public static int abs__ic_menu_share_holo_light=0x7f020029;\r
+        public static int abs__item_background_holo_dark=0x7f02002a;\r
+        public static int abs__item_background_holo_light=0x7f02002b;\r
+        public static int abs__list_activated_holo=0x7f02002c;\r
+        public static int abs__list_divider_holo_dark=0x7f02002d;\r
+        public static int abs__list_divider_holo_light=0x7f02002e;\r
+        public static int abs__list_focused_holo=0x7f02002f;\r
+        public static int abs__list_longpressed_holo=0x7f020030;\r
+        public static int abs__list_pressed_holo_dark=0x7f020031;\r
+        public static int abs__list_pressed_holo_light=0x7f020032;\r
+        public static int abs__list_selector_background_transition_holo_dark=0x7f020033;\r
+        public static int abs__list_selector_background_transition_holo_light=0x7f020034;\r
+        public static int abs__list_selector_disabled_holo_dark=0x7f020035;\r
+        public static int abs__list_selector_disabled_holo_light=0x7f020036;\r
+        public static int abs__list_selector_holo_dark=0x7f020037;\r
+        public static int abs__list_selector_holo_light=0x7f020038;\r
+        public static int abs__menu_dropdown_panel_holo_dark=0x7f020039;\r
+        public static int abs__menu_dropdown_panel_holo_light=0x7f02003a;\r
+        public static int abs__progress_bg_holo_dark=0x7f02003b;\r
+        public static int abs__progress_bg_holo_light=0x7f02003c;\r
+        public static int abs__progress_horizontal_holo_dark=0x7f02003d;\r
+        public static int abs__progress_horizontal_holo_light=0x7f02003e;\r
+        public static int abs__progress_medium_holo=0x7f02003f;\r
+        public static int abs__progress_primary_holo_dark=0x7f020040;\r
+        public static int abs__progress_primary_holo_light=0x7f020041;\r
+        public static int abs__progress_secondary_holo_dark=0x7f020042;\r
+        public static int abs__progress_secondary_holo_light=0x7f020043;\r
+        public static int abs__spinner_48_inner_holo=0x7f020044;\r
+        public static int abs__spinner_48_outer_holo=0x7f020045;\r
+        public static int abs__spinner_ab_default_holo_dark=0x7f020046;\r
+        public static int abs__spinner_ab_default_holo_light=0x7f020047;\r
+        public static int abs__spinner_ab_disabled_holo_dark=0x7f020048;\r
+        public static int abs__spinner_ab_disabled_holo_light=0x7f020049;\r
+        public static int abs__spinner_ab_focused_holo_dark=0x7f02004a;\r
+        public static int abs__spinner_ab_focused_holo_light=0x7f02004b;\r
+        public static int abs__spinner_ab_holo_dark=0x7f02004c;\r
+        public static int abs__spinner_ab_holo_light=0x7f02004d;\r
+        public static int abs__spinner_ab_pressed_holo_dark=0x7f02004e;\r
+        public static int abs__spinner_ab_pressed_holo_light=0x7f02004f;\r
+        public static int abs__tab_indicator_ab_holo=0x7f020050;\r
+        public static int abs__tab_selected_focused_holo=0x7f020051;\r
+        public static int abs__tab_selected_holo=0x7f020052;\r
+        public static int abs__tab_selected_pressed_holo=0x7f020053;\r
+        public static int abs__tab_unselected_pressed_holo=0x7f020054;\r
+        public static int ic_launcher=0x7f020055;\r
+    }\r
+    public static final class id {\r
+        public static int abs__action_bar=0x7f040022;\r
+        public static int abs__action_bar_container=0x7f040021;\r
+        public static int abs__action_bar_subtitle=0x7f040011;\r
+        public static int abs__action_bar_title=0x7f040010;\r
+        public static int abs__action_context_bar=0x7f040023;\r
+        public static int abs__action_menu_divider=0x7f04000c;\r
+        public static int abs__action_menu_presenter=0x7f04000d;\r
+        public static int abs__action_mode_bar=0x7f040026;\r
+        public static int abs__action_mode_bar_stub=0x7f040025;\r
+        public static int abs__action_mode_close_button=0x7f040014;\r
+        public static int abs__activity_chooser_view_content=0x7f040015;\r
+        public static int abs__checkbox=0x7f04001e;\r
+        public static int abs__content=0x7f04001d;\r
+        public static int abs__default_activity_button=0x7f040018;\r
+        public static int abs__expand_activities_button=0x7f040016;\r
+        public static int abs__home=0x7f04000a;\r
+        public static int abs__icon=0x7f04001a;\r
+        public static int abs__image=0x7f040017;\r
+        public static int abs__imageButton=0x7f040012;\r
+        public static int abs__list_item=0x7f040019;\r
+        public static int abs__progress_circular=0x7f04000e;\r
+        public static int abs__progress_horizontal=0x7f04000f;\r
+        public static int abs__radio=0x7f040020;\r
+        public static int abs__shortcut=0x7f04001f;\r
+        public static int abs__split_action_bar=0x7f040024;\r
+        public static int abs__textButton=0x7f040013;\r
+        public static int abs__title=0x7f04001b;\r
+        public static int abs__titleDivider=0x7f04001c;\r
+        public static int abs__up=0x7f04000b;\r
+        public static int disableHome=0x7f040009;\r
+        public static int homeAsUp=0x7f040006;\r
+        public static int listMode=0x7f040002;\r
+        public static int normal=0x7f040001;\r
+        public static int showCustom=0x7f040008;\r
+        public static int showHome=0x7f040005;\r
+        public static int showTitle=0x7f040007;\r
+        public static int tabMode=0x7f040003;\r
+        public static int useLogo=0x7f040004;\r
+        public static int wrap_content=0x7f040000;\r
+    }\r
+    public static final class integer {\r
+        public static int abs__max_action_buttons=0x7f080000;\r
+    }\r
+    public static final class layout {\r
+        public static int abs__action_bar_home=0x7f030000;\r
+        public static int abs__action_bar_tab=0x7f030001;\r
+        public static int abs__action_bar_tab_bar_view=0x7f030002;\r
+        public static int abs__action_bar_title_item=0x7f030003;\r
+        public static int abs__action_menu_item_layout=0x7f030004;\r
+        public static int abs__action_menu_layout=0x7f030005;\r
+        public static int abs__action_mode_bar=0x7f030006;\r
+        public static int abs__action_mode_close_item=0x7f030007;\r
+        public static int abs__activity_chooser_view=0x7f030008;\r
+        public static int abs__activity_chooser_view_list_item=0x7f030009;\r
+        public static int abs__dialog_title_holo=0x7f03000a;\r
+        public static int abs__list_menu_item_checkbox=0x7f03000b;\r
+        public static int abs__list_menu_item_icon=0x7f03000c;\r
+        public static int abs__list_menu_item_layout=0x7f03000d;\r
+        public static int abs__list_menu_item_radio=0x7f03000e;\r
+        public static int abs__popup_menu_item_layout=0x7f03000f;\r
+        public static int abs__screen_action_bar=0x7f030010;\r
+        public static int abs__screen_action_bar_overlay=0x7f030011;\r
+        public static int abs__screen_simple=0x7f030012;\r
+        public static int abs__screen_simple_overlay_action_mode=0x7f030013;\r
+        public static int main=0x7f030014;\r
+        public static int sherlock_spinner_dropdown_item=0x7f030015;\r
+        public static int sherlock_spinner_item=0x7f030016;\r
+    }\r
+    public static final class string {\r
+        /**  Content description for the action bar "home" affordance. [CHAR LIMIT=NONE] \r
+         */\r
+        public static int abs__action_bar_home_description=0x7f090000;\r
+        /**  Content description for the action bar "up" affordance. [CHAR LIMIT=NONE] \r
+         */\r
+        public static int abs__action_bar_up_description=0x7f090001;\r
+        /**  Content description for the action menu overflow button. [CHAR LIMIT=NONE] \r
+         */\r
+        public static int abs__action_menu_overflow_description=0x7f090002;\r
+        /**  Label for the "Done" button on the far left of action mode toolbars. \r
+         */\r
+        public static int abs__action_mode_done=0x7f090003;\r
+        /**  Title default for a dialog showing possible activities in ActivityChooserView [CHAR LIMIT=25] \r
+         */\r
+        public static int abs__activity_chooser_view_dialog_title_default=0x7f090005;\r
+        /**  Title for a button to expand the list of activities in ActivityChooserView [CHAR LIMIT=25] \r
+         */\r
+        public static int abs__activity_chooser_view_see_all=0x7f090004;\r
+        /**  Description of the shwoing of a popup window with activities to choose from. [CHAR LIMIT=NONE] \r
+         */\r
+        public static int abs__activitychooserview_choose_application=0x7f090007;\r
+        /**  Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] \r
+         */\r
+        public static int abs__share_action_provider_share_with=0x7f090006;\r
+        /**  Description of the choose target button in a ShareActionProvider (share UI). [CHAR LIMIT=NONE] \r
+         */\r
+        public static int abs__shareactionprovider_share_with=0x7f090008;\r
+        /**  Description of a share target (both in the list of such or the default share button) in a ShareActionProvider (share UI). [CHAR LIMIT=NONE] \r
+         */\r
+        public static int abs__shareactionprovider_share_with_application=0x7f090009;\r
+        public static int app_name=0x7f09000b;\r
+        public static int hello=0x7f09000a;\r
+    }\r
+    public static final class style {\r
+        public static int DialogWindowTitle_Sherlock=0x7f0a0033;\r
+        public static int DialogWindowTitle_Sherlock_Light=0x7f0a0034;\r
+        public static int Sherlock___TextAppearance_Small=0x7f0a0047;\r
+        public static int Sherlock___Theme=0x7f0a004a;\r
+        public static int Sherlock___Theme_DarkActionBar=0x7f0a004c;\r
+        public static int Sherlock___Theme_Dialog=0x7f0a004d;\r
+        public static int Sherlock___Theme_Light=0x7f0a004b;\r
+        public static int Sherlock___Widget_ActionBar=0x7f0a0001;\r
+        public static int Sherlock___Widget_ActionMode=0x7f0a0016;\r
+        public static int Sherlock___Widget_ActivityChooserView=0x7f0a001e;\r
+        public static int Sherlock___Widget_Holo_DropDownItem=0x7f0a0029;\r
+        public static int Sherlock___Widget_Holo_ListView=0x7f0a0026;\r
+        public static int Sherlock___Widget_Holo_Spinner=0x7f0a0023;\r
+        public static int TextAppearance_Sherlock_DialogWindowTitle=0x7f0a0045;\r
+        public static int TextAppearance_Sherlock_Light_DialogWindowTitle=0x7f0a0046;\r
+        public static int TextAppearance_Sherlock_Light_Small=0x7f0a0049;\r
+        public static int TextAppearance_Sherlock_Light_Widget_PopupMenu_Large=0x7f0a0040;\r
+        public static int TextAppearance_Sherlock_Light_Widget_PopupMenu_Small=0x7f0a0042;\r
+        public static int TextAppearance_Sherlock_Small=0x7f0a0048;\r
+        public static int TextAppearance_Sherlock_Widget_ActionBar_Menu=0x7f0a0035;\r
+        public static int TextAppearance_Sherlock_Widget_ActionBar_Subtitle=0x7f0a0038;\r
+        public static int TextAppearance_Sherlock_Widget_ActionBar_Subtitle_Inverse=0x7f0a0039;\r
+        public static int TextAppearance_Sherlock_Widget_ActionBar_Title=0x7f0a0036;\r
+        public static int TextAppearance_Sherlock_Widget_ActionBar_Title_Inverse=0x7f0a0037;\r
+        public static int TextAppearance_Sherlock_Widget_ActionMode_Subtitle=0x7f0a003c;\r
+        public static int TextAppearance_Sherlock_Widget_ActionMode_Subtitle_Inverse=0x7f0a003d;\r
+        public static int TextAppearance_Sherlock_Widget_ActionMode_Title=0x7f0a003a;\r
+        public static int TextAppearance_Sherlock_Widget_ActionMode_Title_Inverse=0x7f0a003b;\r
+        public static int TextAppearance_Sherlock_Widget_DropDownItem=0x7f0a0044;\r
+        public static int TextAppearance_Sherlock_Widget_PopupMenu=0x7f0a003e;\r
+        public static int TextAppearance_Sherlock_Widget_PopupMenu_Large=0x7f0a003f;\r
+        public static int TextAppearance_Sherlock_Widget_PopupMenu_Small=0x7f0a0041;\r
+        public static int TextAppearance_Sherlock_Widget_TextView_SpinnerItem=0x7f0a0043;\r
+        public static int Theme_Sherlock=0x7f0a004e;\r
+        public static int Theme_Sherlock_Dialog=0x7f0a0056;\r
+        public static int Theme_Sherlock_ForceOverflow=0x7f0a0053;\r
+        public static int Theme_Sherlock_Light=0x7f0a004f;\r
+        public static int Theme_Sherlock_Light_DarkActionBar=0x7f0a0050;\r
+        public static int Theme_Sherlock_Light_DarkActionBar_ForceOverflow=0x7f0a0055;\r
+        public static int Theme_Sherlock_Light_Dialog=0x7f0a0057;\r
+        public static int Theme_Sherlock_Light_ForceOverflow=0x7f0a0054;\r
+        public static int Theme_Sherlock_Light_NoActionBar=0x7f0a0052;\r
+        public static int Theme_Sherlock_NoActionBar=0x7f0a0051;\r
+        public static int Widget=0x7f0a0000;\r
+        public static int Widget_Sherlock_ActionBar=0x7f0a0002;\r
+        public static int Widget_Sherlock_ActionBar_Solid=0x7f0a0003;\r
+        public static int Widget_Sherlock_ActionBar_TabBar=0x7f0a000a;\r
+        public static int Widget_Sherlock_ActionBar_TabText=0x7f0a000d;\r
+        public static int Widget_Sherlock_ActionBar_TabView=0x7f0a0007;\r
+        public static int Widget_Sherlock_ActionButton=0x7f0a0010;\r
+        public static int Widget_Sherlock_ActionButton_CloseMode=0x7f0a0012;\r
+        public static int Widget_Sherlock_ActionButton_Overflow=0x7f0a0014;\r
+        public static int Widget_Sherlock_ActionMode=0x7f0a0017;\r
+        public static int Widget_Sherlock_ActivityChooserView=0x7f0a001f;\r
+        public static int Widget_Sherlock_Button_Small=0x7f0a0021;\r
+        public static int Widget_Sherlock_DropDownItem_Spinner=0x7f0a002a;\r
+        public static int Widget_Sherlock_Light_ActionBar=0x7f0a0004;\r
+        public static int Widget_Sherlock_Light_ActionBar_Solid=0x7f0a0005;\r
+        public static int Widget_Sherlock_Light_ActionBar_Solid_Inverse=0x7f0a0006;\r
+        public static int Widget_Sherlock_Light_ActionBar_TabBar=0x7f0a000b;\r
+        public static int Widget_Sherlock_Light_ActionBar_TabBar_Inverse=0x7f0a000c;\r
+        public static int Widget_Sherlock_Light_ActionBar_TabText=0x7f0a000e;\r
+        public static int Widget_Sherlock_Light_ActionBar_TabText_Inverse=0x7f0a000f;\r
+        public static int Widget_Sherlock_Light_ActionBar_TabView=0x7f0a0008;\r
+        public static int Widget_Sherlock_Light_ActionBar_TabView_Inverse=0x7f0a0009;\r
+        public static int Widget_Sherlock_Light_ActionButton=0x7f0a0011;\r
+        public static int Widget_Sherlock_Light_ActionButton_CloseMode=0x7f0a0013;\r
+        public static int Widget_Sherlock_Light_ActionButton_Overflow=0x7f0a0015;\r
+        public static int Widget_Sherlock_Light_ActionMode=0x7f0a0018;\r
+        public static int Widget_Sherlock_Light_ActionMode_Inverse=0x7f0a0019;\r
+        public static int Widget_Sherlock_Light_ActivityChooserView=0x7f0a0020;\r
+        public static int Widget_Sherlock_Light_Button_Small=0x7f0a0022;\r
+        public static int Widget_Sherlock_Light_DropDownItem_Spinner=0x7f0a002b;\r
+        public static int Widget_Sherlock_Light_ListPopupWindow=0x7f0a001b;\r
+        public static int Widget_Sherlock_Light_ListView_DropDown=0x7f0a0028;\r
+        public static int Widget_Sherlock_Light_PopupMenu=0x7f0a001d;\r
+        public static int Widget_Sherlock_Light_PopupWindow_ActionMode=0x7f0a002d;\r
+        public static int Widget_Sherlock_Light_ProgressBar=0x7f0a002f;\r
+        public static int Widget_Sherlock_Light_ProgressBar_Horizontal=0x7f0a0031;\r
+        public static int Widget_Sherlock_Light_Spinner_DropDown_ActionBar=0x7f0a0025;\r
+        public static int Widget_Sherlock_ListPopupWindow=0x7f0a001a;\r
+        public static int Widget_Sherlock_ListView_DropDown=0x7f0a0027;\r
+        public static int Widget_Sherlock_PopupMenu=0x7f0a001c;\r
+        public static int Widget_Sherlock_PopupWindow_ActionMode=0x7f0a002c;\r
+        public static int Widget_Sherlock_ProgressBar=0x7f0a002e;\r
+        public static int Widget_Sherlock_ProgressBar_Horizontal=0x7f0a0030;\r
+        public static int Widget_Sherlock_Spinner_DropDown_ActionBar=0x7f0a0024;\r
+        public static int Widget_Sherlock_TextView_SpinnerItem=0x7f0a0032;\r
+    }\r
+    public static final class styleable {\r
+        /**  Attributes used to style the Action Bar. \r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_background com.actionbarsherlock:background}</code></td><td> Specifies a background drawable for the action bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_backgroundSplit com.actionbarsherlock:backgroundSplit}</code></td><td> Specifies a background drawable for the bottom component of a split action bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_backgroundStacked com.actionbarsherlock:backgroundStacked}</code></td><td> Specifies a background drawable for a second stacked row of the action bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_customNavigationLayout com.actionbarsherlock:customNavigationLayout}</code></td><td> Specifies a layout for custom navigation.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_displayOptions com.actionbarsherlock:displayOptions}</code></td><td> Options affecting how the action bar is displayed.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_divider com.actionbarsherlock:divider}</code></td><td> Specifies the drawable used for item dividers.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_height com.actionbarsherlock:height}</code></td><td> Specifies a fixed height.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_homeLayout com.actionbarsherlock:homeLayout}</code></td><td> Specifies a layout to use for the "home" section of the action bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_icon com.actionbarsherlock:icon}</code></td><td> Specifies the drawable used for the application icon.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_indeterminateProgressStyle com.actionbarsherlock:indeterminateProgressStyle}</code></td><td> Specifies a style resource to use for an indeterminate progress spinner.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_itemPadding com.actionbarsherlock:itemPadding}</code></td><td> Specifies padding that should be applied to the left and right sides of\r
+             system-provided items in the bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_logo com.actionbarsherlock:logo}</code></td><td> Specifies the drawable used for the application logo.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_navigationMode com.actionbarsherlock:navigationMode}</code></td><td> The type of navigation to use.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_progressBarPadding com.actionbarsherlock:progressBarPadding}</code></td><td> Specifies the horizontal padding on either end for an embedded progress bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_progressBarStyle com.actionbarsherlock:progressBarStyle}</code></td><td> Specifies a style resource to use for an embedded progress bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_subtitle com.actionbarsherlock:subtitle}</code></td><td> Specifies subtitle text used for navigationMode="normal" </td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_subtitleTextStyle com.actionbarsherlock:subtitleTextStyle}</code></td><td> Specifies a style to use for subtitle text.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_title com.actionbarsherlock:title}</code></td><td> Specifies title text used for navigationMode="normal" </td></tr>\r
+           <tr><td><code>{@link #SherlockActionBar_titleTextStyle com.actionbarsherlock:titleTextStyle}</code></td><td> Specifies a style to use for title text.</td></tr>\r
+           </table>\r
+           @see #SherlockActionBar_background\r
+           @see #SherlockActionBar_backgroundSplit\r
+           @see #SherlockActionBar_backgroundStacked\r
+           @see #SherlockActionBar_customNavigationLayout\r
+           @see #SherlockActionBar_displayOptions\r
+           @see #SherlockActionBar_divider\r
+           @see #SherlockActionBar_height\r
+           @see #SherlockActionBar_homeLayout\r
+           @see #SherlockActionBar_icon\r
+           @see #SherlockActionBar_indeterminateProgressStyle\r
+           @see #SherlockActionBar_itemPadding\r
+           @see #SherlockActionBar_logo\r
+           @see #SherlockActionBar_navigationMode\r
+           @see #SherlockActionBar_progressBarPadding\r
+           @see #SherlockActionBar_progressBarStyle\r
+           @see #SherlockActionBar_subtitle\r
+           @see #SherlockActionBar_subtitleTextStyle\r
+           @see #SherlockActionBar_title\r
+           @see #SherlockActionBar_titleTextStyle\r
+         */\r
+        public static final int[] SherlockActionBar = {\r
+            0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003,\r
+            0x7f010004, 0x7f010005, 0x7f01003a, 0x7f01003b,\r
+            0x7f01003c, 0x7f01003d, 0x7f01003e, 0x7f01003f,\r
+            0x7f010040, 0x7f010041, 0x7f010042, 0x7f010043,\r
+            0x7f010044, 0x7f010045, 0x7f010046\r
+        };\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a background drawable for the action bar. \r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:background\r
+        */\r
+        public static final int SherlockActionBar_background = 2;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a background drawable for the bottom component of a split action bar. \r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:backgroundSplit\r
+        */\r
+        public static final int SherlockActionBar_backgroundSplit = 3;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a background drawable for a second stacked row of the action bar. \r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:backgroundStacked\r
+        */\r
+        public static final int SherlockActionBar_backgroundStacked = 12;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a layout for custom navigation. Overrides navigationMode. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:customNavigationLayout\r
+        */\r
+        public static final int SherlockActionBar_customNavigationLayout = 13;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Options affecting how the action bar is displayed. \r
+\r
+\r
+          <p>Must be one or more (separated by '|') of the following constant values.</p>\r
+<table>\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\r
+<tr><td><code>useLogo</code></td><td>0x1</td><td></td></tr>\r
+<tr><td><code>showHome</code></td><td>0x2</td><td></td></tr>\r
+<tr><td><code>homeAsUp</code></td><td>0x4</td><td></td></tr>\r
+<tr><td><code>showTitle</code></td><td>0x8</td><td></td></tr>\r
+<tr><td><code>showCustom</code></td><td>0x10</td><td></td></tr>\r
+<tr><td><code>disableHome</code></td><td>0x20</td><td></td></tr>\r
+</table>\r
+          <p>This is a private symbol.\r
+          @attr name android:displayOptions\r
+        */\r
+        public static final int SherlockActionBar_displayOptions = 7;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies the drawable used for item dividers. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:divider\r
+        */\r
+        public static final int SherlockActionBar_divider = 5;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a fixed height. \r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:height\r
+        */\r
+        public static final int SherlockActionBar_height = 4;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a layout to use for the "home" section of the action bar. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:homeLayout\r
+        */\r
+        public static final int SherlockActionBar_homeLayout = 14;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies the drawable used for the application icon. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:icon\r
+        */\r
+        public static final int SherlockActionBar_icon = 10;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a style resource to use for an indeterminate progress spinner. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:indeterminateProgressStyle\r
+        */\r
+        public static final int SherlockActionBar_indeterminateProgressStyle = 16;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies padding that should be applied to the left and right sides of\r
+             system-provided items in the bar. \r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:itemPadding\r
+        */\r
+        public static final int SherlockActionBar_itemPadding = 18;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies the drawable used for the application logo. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:logo\r
+        */\r
+        public static final int SherlockActionBar_logo = 11;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The type of navigation to use. \r
+\r
+\r
+          <p>Must be one of the following constant values.</p>\r
+<table>\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\r
+<tr><td><code>normal</code></td><td>0</td><td> Normal static title text </td></tr>\r
+<tr><td><code>listMode</code></td><td>1</td><td> The action bar will use a selection list for navigation. </td></tr>\r
+<tr><td><code>tabMode</code></td><td>2</td><td> The action bar will use a series of horizontal tabs for navigation. </td></tr>\r
+</table>\r
+          <p>This is a private symbol.\r
+          @attr name android:navigationMode\r
+        */\r
+        public static final int SherlockActionBar_navigationMode = 6;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies the horizontal padding on either end for an embedded progress bar. \r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:progressBarPadding\r
+        */\r
+        public static final int SherlockActionBar_progressBarPadding = 17;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a style resource to use for an embedded progress bar. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:progressBarStyle\r
+        */\r
+        public static final int SherlockActionBar_progressBarStyle = 15;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies subtitle text used for navigationMode="normal" \r
+\r
+\r
+          <p>Must be a string value, using '\\;' to escape characters such as '\\n' or '\\uxxxx' for a unicode character.\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:subtitle\r
+        */\r
+        public static final int SherlockActionBar_subtitle = 9;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a style to use for subtitle text. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:subtitleTextStyle\r
+        */\r
+        public static final int SherlockActionBar_subtitleTextStyle = 1;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies title text used for navigationMode="normal" \r
+\r
+\r
+          <p>Must be a string value, using '\\;' to escape characters such as '\\n' or '\\uxxxx' for a unicode character.\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:title\r
+        */\r
+        public static final int SherlockActionBar_title = 8;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a style to use for title text. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:titleTextStyle\r
+        */\r
+        public static final int SherlockActionBar_titleTextStyle = 0;\r
+        /** Attributes that can be used with a SherlockActionMenuItemView.\r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockActionMenuItemView_android_minWidth com.actionbarsherlock:android_minWidth}</code></td><td></td></tr>\r
+           </table>\r
+           @see #SherlockActionMenuItemView_android_minWidth\r
+         */\r
+        public static final int[] SherlockActionMenuItemView = {\r
+            0x0101013f\r
+        };\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#android_minWidth}\r
+          attribute's value can be found in the {@link #SherlockActionMenuItemView} array.\r
+          @attr name android:android_minWidth\r
+        */\r
+        public static final int SherlockActionMenuItemView_android_minWidth = 0;\r
+        /** Attributes that can be used with a SherlockActionMode.\r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockActionMode_background com.actionbarsherlock:background}</code></td><td> Specifies a background for the action mode bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionMode_backgroundSplit com.actionbarsherlock:backgroundSplit}</code></td><td> Specifies a background for the split action mode bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionMode_height com.actionbarsherlock:height}</code></td><td> Specifies a fixed height for the action mode bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionMode_subtitleTextStyle com.actionbarsherlock:subtitleTextStyle}</code></td><td> Specifies a style to use for subtitle text.</td></tr>\r
+           <tr><td><code>{@link #SherlockActionMode_titleTextStyle com.actionbarsherlock:titleTextStyle}</code></td><td> Specifies a style to use for title text.</td></tr>\r
+           </table>\r
+           @see #SherlockActionMode_background\r
+           @see #SherlockActionMode_backgroundSplit\r
+           @see #SherlockActionMode_height\r
+           @see #SherlockActionMode_subtitleTextStyle\r
+           @see #SherlockActionMode_titleTextStyle\r
+         */\r
+        public static final int[] SherlockActionMode = {\r
+            0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003,\r
+            0x7f010004\r
+        };\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a background for the action mode bar. \r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:background\r
+        */\r
+        public static final int SherlockActionMode_background = 2;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a background for the split action mode bar. \r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:backgroundSplit\r
+        */\r
+        public static final int SherlockActionMode_backgroundSplit = 3;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a fixed height for the action mode bar. \r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:height\r
+        */\r
+        public static final int SherlockActionMode_height = 4;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a style to use for subtitle text. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:subtitleTextStyle\r
+        */\r
+        public static final int SherlockActionMode_subtitleTextStyle = 1;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specifies a style to use for title text. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:titleTextStyle\r
+        */\r
+        public static final int SherlockActionMode_titleTextStyle = 0;\r
+        /** Attributes that can be used with a SherlockActivityChooserView.\r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockActivityChooserView_android_background com.actionbarsherlock:android_background}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockActivityChooserView_expandActivityOverflowButtonDrawable com.actionbarsherlock:expandActivityOverflowButtonDrawable}</code></td><td> The drawable to show in the button for expanding the activities overflow popup.</td></tr>\r
+           <tr><td><code>{@link #SherlockActivityChooserView_initialActivityCount com.actionbarsherlock:initialActivityCount}</code></td><td> The maximal number of items initially shown in the activity list.</td></tr>\r
+           </table>\r
+           @see #SherlockActivityChooserView_android_background\r
+           @see #SherlockActivityChooserView_expandActivityOverflowButtonDrawable\r
+           @see #SherlockActivityChooserView_initialActivityCount\r
+         */\r
+        public static final int[] SherlockActivityChooserView = {\r
+            0x010100d4, 0x7f01004f, 0x7f010050\r
+        };\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#android_background}\r
+          attribute's value can be found in the {@link #SherlockActivityChooserView} array.\r
+          @attr name android:android_background\r
+        */\r
+        public static final int SherlockActivityChooserView_android_background = 0;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The drawable to show in the button for expanding the activities overflow popup.\r
+             <strong>Note:</strong> Clients would like to set this drawable\r
+             as a clue about the action the chosen activity will perform. For\r
+             example, if share activity is to be chosen the drawable should\r
+             give a clue that sharing is to be performed.\r
+         \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:expandActivityOverflowButtonDrawable\r
+        */\r
+        public static final int SherlockActivityChooserView_expandActivityOverflowButtonDrawable = 2;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The maximal number of items initially shown in the activity list. \r
+\r
+\r
+          <p>Must be a string value, using '\\;' to escape characters such as '\\n' or '\\uxxxx' for a unicode character.\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:initialActivityCount\r
+        */\r
+        public static final int SherlockActivityChooserView_initialActivityCount = 1;\r
+        /**  Base attributes that are available to all groups. \r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockMenuGroup_android_checkableBehavior com.actionbarsherlock:android_checkableBehavior}</code></td><td> Whether the items are capable of displaying a check mark.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuGroup_android_enabled com.actionbarsherlock:android_enabled}</code></td><td> Whether the items are enabled.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuGroup_android_id com.actionbarsherlock:android_id}</code></td><td> The ID of the group.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuGroup_android_menuCategory com.actionbarsherlock:android_menuCategory}</code></td><td> The category applied to all items within this group.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuGroup_android_orderInCategory com.actionbarsherlock:android_orderInCategory}</code></td><td> The order within the category applied to all items within this group.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuGroup_android_visible com.actionbarsherlock:android_visible}</code></td><td> Whether the items are shown/visible.</td></tr>\r
+           </table>\r
+           @see #SherlockMenuGroup_android_checkableBehavior\r
+           @see #SherlockMenuGroup_android_enabled\r
+           @see #SherlockMenuGroup_android_id\r
+           @see #SherlockMenuGroup_android_menuCategory\r
+           @see #SherlockMenuGroup_android_orderInCategory\r
+           @see #SherlockMenuGroup_android_visible\r
+         */\r
+        public static final int[] SherlockMenuGroup = {\r
+            0x0101000e, 0x010100d0, 0x01010194, 0x010101de,\r
+            0x010101df, 0x010101e0\r
+        };\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Whether the items are capable of displaying a check mark. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_checkableBehavior}.\r
+          @attr name android:android_checkableBehavior\r
+        */\r
+        public static final int SherlockMenuGroup_android_checkableBehavior = 5;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Whether the items are enabled. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_enabled}.\r
+          @attr name android:android_enabled\r
+        */\r
+        public static final int SherlockMenuGroup_android_enabled = 0;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The ID of the group. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_id}.\r
+          @attr name android:android_id\r
+        */\r
+        public static final int SherlockMenuGroup_android_id = 1;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The category applied to all items within this group.\r
+             (This will be or'ed with the orderInCategory attribute.) \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_menuCategory}.\r
+          @attr name android:android_menuCategory\r
+        */\r
+        public static final int SherlockMenuGroup_android_menuCategory = 3;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The order within the category applied to all items within this group.\r
+             (This will be or'ed with the category attribute.) \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_orderInCategory}.\r
+          @attr name android:android_orderInCategory\r
+        */\r
+        public static final int SherlockMenuGroup_android_orderInCategory = 4;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Whether the items are shown/visible. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_visible}.\r
+          @attr name android:android_visible\r
+        */\r
+        public static final int SherlockMenuGroup_android_visible = 2;\r
+        /**  Base attributes that are available to all Item objects. \r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_actionLayout com.actionbarsherlock:android_actionLayout}</code></td><td> An optional layout to be used as an action view.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_actionProviderClass com.actionbarsherlock:android_actionProviderClass}</code></td><td> The name of an optional ActionProvider class to instantiate an action view\r
+             and perform operations such as default action for that menu item.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_actionViewClass com.actionbarsherlock:android_actionViewClass}</code></td><td> The name of an optional View class to instantiate and use as an\r
+             action view.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_alphabeticShortcut com.actionbarsherlock:android_alphabeticShortcut}</code></td><td> The alphabetic shortcut key.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_checkable com.actionbarsherlock:android_checkable}</code></td><td> Whether the item is capable of displaying a check mark.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_checked com.actionbarsherlock:android_checked}</code></td><td> Whether the item is checked.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_enabled com.actionbarsherlock:android_enabled}</code></td><td> Whether the item is enabled.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_icon com.actionbarsherlock:android_icon}</code></td><td> The icon associated with this item.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_id com.actionbarsherlock:android_id}</code></td><td> The ID of the item.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_menuCategory com.actionbarsherlock:android_menuCategory}</code></td><td> The category applied to the item.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_numericShortcut com.actionbarsherlock:android_numericShortcut}</code></td><td> The numeric shortcut key.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_onClick com.actionbarsherlock:android_onClick}</code></td><td> Name of a method on the Context used to inflate the menu that will be\r
+             called when the item is clicked.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_orderInCategory com.actionbarsherlock:android_orderInCategory}</code></td><td> The order within the category applied to the item.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_showAsAction com.actionbarsherlock:android_showAsAction}</code></td><td> How this item should display in the Action Bar, if present.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_title com.actionbarsherlock:android_title}</code></td><td> The title associated with the item.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_titleCondensed com.actionbarsherlock:android_titleCondensed}</code></td><td> The condensed title associated with the item.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuItem_android_visible com.actionbarsherlock:android_visible}</code></td><td> Whether the item is shown/visible.</td></tr>\r
+           </table>\r
+           @see #SherlockMenuItem_android_actionLayout\r
+           @see #SherlockMenuItem_android_actionProviderClass\r
+           @see #SherlockMenuItem_android_actionViewClass\r
+           @see #SherlockMenuItem_android_alphabeticShortcut\r
+           @see #SherlockMenuItem_android_checkable\r
+           @see #SherlockMenuItem_android_checked\r
+           @see #SherlockMenuItem_android_enabled\r
+           @see #SherlockMenuItem_android_icon\r
+           @see #SherlockMenuItem_android_id\r
+           @see #SherlockMenuItem_android_menuCategory\r
+           @see #SherlockMenuItem_android_numericShortcut\r
+           @see #SherlockMenuItem_android_onClick\r
+           @see #SherlockMenuItem_android_orderInCategory\r
+           @see #SherlockMenuItem_android_showAsAction\r
+           @see #SherlockMenuItem_android_title\r
+           @see #SherlockMenuItem_android_titleCondensed\r
+           @see #SherlockMenuItem_android_visible\r
+         */\r
+        public static final int[] SherlockMenuItem = {\r
+            0x01010002, 0x0101000e, 0x010100d0, 0x01010106,\r
+            0x01010194, 0x010101de, 0x010101df, 0x010101e1,\r
+            0x010101e2, 0x010101e3, 0x010101e4, 0x010101e5,\r
+            0x0101026f, 0x010102d9, 0x010102fb, 0x010102fc,\r
+            0x01010389\r
+        };\r
+        /**\r
+          <p>\r
+          @attr description\r
+           An optional layout to be used as an action view.\r
+             See {@link android.view.MenuItem#setActionView(android.view.View)}\r
+             for more info. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_actionLayout}.\r
+          @attr name android:android_actionLayout\r
+        */\r
+        public static final int SherlockMenuItem_android_actionLayout = 14;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The name of an optional ActionProvider class to instantiate an action view\r
+             and perform operations such as default action for that menu item.\r
+             See {@link android.view.MenuItem#setActionProvider(android.view.ActionProvider)}\r
+             for more info. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_actionProviderClass}.\r
+          @attr name android:android_actionProviderClass\r
+        */\r
+        public static final int SherlockMenuItem_android_actionProviderClass = 16;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The name of an optional View class to instantiate and use as an\r
+             action view. See {@link android.view.MenuItem#setActionView(android.view.View)}\r
+             for more info. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_actionViewClass}.\r
+          @attr name android:android_actionViewClass\r
+        */\r
+        public static final int SherlockMenuItem_android_actionViewClass = 15;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The alphabetic shortcut key.  This is the shortcut when using a keyboard\r
+             with alphabetic keys. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_alphabeticShortcut}.\r
+          @attr name android:android_alphabeticShortcut\r
+        */\r
+        public static final int SherlockMenuItem_android_alphabeticShortcut = 9;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Whether the item is capable of displaying a check mark. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_checkable}.\r
+          @attr name android:android_checkable\r
+        */\r
+        public static final int SherlockMenuItem_android_checkable = 11;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Whether the item is checked.  Note that you must first have enabled checking with\r
+             the checkable attribute or else the check mark will not appear. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_checked}.\r
+          @attr name android:android_checked\r
+        */\r
+        public static final int SherlockMenuItem_android_checked = 3;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Whether the item is enabled. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_enabled}.\r
+          @attr name android:android_enabled\r
+        */\r
+        public static final int SherlockMenuItem_android_enabled = 1;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The icon associated with this item.  This icon will not always be shown, so\r
+             the title should be sufficient in describing this item. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_icon}.\r
+          @attr name android:android_icon\r
+        */\r
+        public static final int SherlockMenuItem_android_icon = 0;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The ID of the item. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_id}.\r
+          @attr name android:android_id\r
+        */\r
+        public static final int SherlockMenuItem_android_id = 2;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The category applied to the item.\r
+             (This will be or'ed with the orderInCategory attribute.) \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_menuCategory}.\r
+          @attr name android:android_menuCategory\r
+        */\r
+        public static final int SherlockMenuItem_android_menuCategory = 5;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The numeric shortcut key.  This is the shortcut when using a numeric (e.g., 12-key)\r
+             keyboard. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_numericShortcut}.\r
+          @attr name android:android_numericShortcut\r
+        */\r
+        public static final int SherlockMenuItem_android_numericShortcut = 10;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Name of a method on the Context used to inflate the menu that will be\r
+             called when the item is clicked. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_onClick}.\r
+          @attr name android:android_onClick\r
+        */\r
+        public static final int SherlockMenuItem_android_onClick = 12;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The order within the category applied to the item.\r
+             (This will be or'ed with the category attribute.) \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_orderInCategory}.\r
+          @attr name android:android_orderInCategory\r
+        */\r
+        public static final int SherlockMenuItem_android_orderInCategory = 6;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           How this item should display in the Action Bar, if present. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_showAsAction}.\r
+          @attr name android:android_showAsAction\r
+        */\r
+        public static final int SherlockMenuItem_android_showAsAction = 13;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The title associated with the item. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_title}.\r
+          @attr name android:android_title\r
+        */\r
+        public static final int SherlockMenuItem_android_title = 7;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The condensed title associated with the item.  This is used in situations where the\r
+             normal title may be too long to be displayed. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_titleCondensed}.\r
+          @attr name android:android_titleCondensed\r
+        */\r
+        public static final int SherlockMenuItem_android_titleCondensed = 8;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Whether the item is shown/visible. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_visible}.\r
+          @attr name android:android_visible\r
+        */\r
+        public static final int SherlockMenuItem_android_visible = 4;\r
+        /** Attributes that can be used with a SherlockMenuView.\r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockMenuView_headerBackground com.actionbarsherlock:headerBackground}</code></td><td> Default background for the menu header.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuView_horizontalDivider com.actionbarsherlock:horizontalDivider}</code></td><td> Default horizontal divider between rows of menu items.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuView_itemBackground com.actionbarsherlock:itemBackground}</code></td><td> Default background for each menu item.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuView_itemIconDisabledAlpha com.actionbarsherlock:itemIconDisabledAlpha}</code></td><td> Default disabled icon alpha for each menu item that shows an icon.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuView_itemTextAppearance com.actionbarsherlock:itemTextAppearance}</code></td><td> Default appearance of menu item text.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuView_preserveIconSpacing com.actionbarsherlock:preserveIconSpacing}</code></td><td> Whether space should be reserved in layout when an icon is missing.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuView_verticalDivider com.actionbarsherlock:verticalDivider}</code></td><td> Default vertical divider between menu items.</td></tr>\r
+           <tr><td><code>{@link #SherlockMenuView_windowAnimationStyle com.actionbarsherlock:windowAnimationStyle}</code></td><td> Default animations for the menu.</td></tr>\r
+           </table>\r
+           @see #SherlockMenuView_headerBackground\r
+           @see #SherlockMenuView_horizontalDivider\r
+           @see #SherlockMenuView_itemBackground\r
+           @see #SherlockMenuView_itemIconDisabledAlpha\r
+           @see #SherlockMenuView_itemTextAppearance\r
+           @see #SherlockMenuView_preserveIconSpacing\r
+           @see #SherlockMenuView_verticalDivider\r
+           @see #SherlockMenuView_windowAnimationStyle\r
+         */\r
+        public static final int[] SherlockMenuView = {\r
+            0x7f010047, 0x7f010048, 0x7f010049, 0x7f01004a,\r
+            0x7f01004b, 0x7f01004c, 0x7f01004d, 0x7f01004e\r
+        };\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default background for the menu header. \r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:headerBackground\r
+        */\r
+        public static final int SherlockMenuView_headerBackground = 3;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default horizontal divider between rows of menu items. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:horizontalDivider\r
+        */\r
+        public static final int SherlockMenuView_horizontalDivider = 1;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default background for each menu item. \r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:itemBackground\r
+        */\r
+        public static final int SherlockMenuView_itemBackground = 4;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default disabled icon alpha for each menu item that shows an icon. \r
+\r
+\r
+          <p>Must be a floating point value, such as "<code>1.2</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:itemIconDisabledAlpha\r
+        */\r
+        public static final int SherlockMenuView_itemIconDisabledAlpha = 6;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default appearance of menu item text. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:itemTextAppearance\r
+        */\r
+        public static final int SherlockMenuView_itemTextAppearance = 0;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Whether space should be reserved in layout when an icon is missing. \r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:preserveIconSpacing\r
+        */\r
+        public static final int SherlockMenuView_preserveIconSpacing = 7;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default vertical divider between menu items. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:verticalDivider\r
+        */\r
+        public static final int SherlockMenuView_verticalDivider = 2;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default animations for the menu. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:windowAnimationStyle\r
+        */\r
+        public static final int SherlockMenuView_windowAnimationStyle = 5;\r
+        /** Attributes that can be used with a SherlockSpinner.\r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockSpinner_android_dropDownHorizontalOffset com.actionbarsherlock:android_dropDownHorizontalOffset}</code></td><td> Horizontal offset from the spinner widget for positioning the dropdown\r
+             in spinnerMode="dropdown".</td></tr>\r
+           <tr><td><code>{@link #SherlockSpinner_android_dropDownSelector com.actionbarsherlock:android_dropDownSelector}</code></td><td> List selector to use for spinnerMode="dropdown" display.</td></tr>\r
+           <tr><td><code>{@link #SherlockSpinner_android_dropDownVerticalOffset com.actionbarsherlock:android_dropDownVerticalOffset}</code></td><td> Vertical offset from the spinner widget for positioning the dropdown in\r
+             spinnerMode="dropdown".</td></tr>\r
+           <tr><td><code>{@link #SherlockSpinner_android_dropDownWidth com.actionbarsherlock:android_dropDownWidth}</code></td><td> Width of the dropdown in spinnerMode="dropdown".</td></tr>\r
+           <tr><td><code>{@link #SherlockSpinner_android_gravity com.actionbarsherlock:android_gravity}</code></td><td> Gravity setting for positioning the currently selected item.</td></tr>\r
+           <tr><td><code>{@link #SherlockSpinner_android_popupBackground com.actionbarsherlock:android_popupBackground}</code></td><td> Background drawable to use for the dropdown in spinnerMode="dropdown".</td></tr>\r
+           <tr><td><code>{@link #SherlockSpinner_android_popupPromptView com.actionbarsherlock:android_popupPromptView}</code></td><td> Reference to a layout to use for displaying a prompt in the dropdown for\r
+             spinnerMode="dropdown".</td></tr>\r
+           <tr><td><code>{@link #SherlockSpinner_android_prompt com.actionbarsherlock:android_prompt}</code></td><td> The prompt to display when the spinner's dialog is shown.</td></tr>\r
+           </table>\r
+           @see #SherlockSpinner_android_dropDownHorizontalOffset\r
+           @see #SherlockSpinner_android_dropDownSelector\r
+           @see #SherlockSpinner_android_dropDownVerticalOffset\r
+           @see #SherlockSpinner_android_dropDownWidth\r
+           @see #SherlockSpinner_android_gravity\r
+           @see #SherlockSpinner_android_popupBackground\r
+           @see #SherlockSpinner_android_popupPromptView\r
+           @see #SherlockSpinner_android_prompt\r
+         */\r
+        public static final int[] SherlockSpinner = {\r
+            0x010100af, 0x01010175, 0x01010176, 0x0101017b,\r
+            0x01010262, 0x010102ac, 0x010102ad, 0x010103ef\r
+        };\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Horizontal offset from the spinner widget for positioning the dropdown\r
+             in spinnerMode="dropdown". \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_dropDownHorizontalOffset}.\r
+          @attr name android:android_dropDownHorizontalOffset\r
+        */\r
+        public static final int SherlockSpinner_android_dropDownHorizontalOffset = 5;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           List selector to use for spinnerMode="dropdown" display. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_dropDownSelector}.\r
+          @attr name android:android_dropDownSelector\r
+        */\r
+        public static final int SherlockSpinner_android_dropDownSelector = 1;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Vertical offset from the spinner widget for positioning the dropdown in\r
+             spinnerMode="dropdown". \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_dropDownVerticalOffset}.\r
+          @attr name android:android_dropDownVerticalOffset\r
+        */\r
+        public static final int SherlockSpinner_android_dropDownVerticalOffset = 6;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Width of the dropdown in spinnerMode="dropdown". \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_dropDownWidth}.\r
+          @attr name android:android_dropDownWidth\r
+        */\r
+        public static final int SherlockSpinner_android_dropDownWidth = 4;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Gravity setting for positioning the currently selected item. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_gravity}.\r
+          @attr name android:android_gravity\r
+        */\r
+        public static final int SherlockSpinner_android_gravity = 0;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Background drawable to use for the dropdown in spinnerMode="dropdown". \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_popupBackground}.\r
+          @attr name android:android_popupBackground\r
+        */\r
+        public static final int SherlockSpinner_android_popupBackground = 2;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Reference to a layout to use for displaying a prompt in the dropdown for\r
+             spinnerMode="dropdown". This layout must contain a TextView with the id\r
+             @android:id/text1 to be populated with the prompt text. \r
+          <p>This is a private symbol.\r
+          @attr name android:android_popupPromptView\r
+        */\r
+        public static final int SherlockSpinner_android_popupPromptView = 7;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The prompt to display when the spinner's dialog is shown. \r
+          <p>This corresponds to the global attribute          resource symbol {@link com.actionbarsherlock.R.attr#android_prompt}.\r
+          @attr name android:android_prompt\r
+        */\r
+        public static final int SherlockSpinner_android_prompt = 3;\r
+        /** Attributes that can be used with a SherlockTheme.\r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #SherlockTheme_absForceOverflow com.actionbarsherlock:absForceOverflow}</code></td><td> Specified if we are forcing an action item overflow menu.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarDivider com.actionbarsherlock:actionBarDivider}</code></td><td> Custom divider drawable to use for elements in the action bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarItemBackground com.actionbarsherlock:actionBarItemBackground}</code></td><td> Custom item state list drawable background for action bar items.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarSize com.actionbarsherlock:actionBarSize}</code></td><td> Size of the Action Bar, including the contextual\r
+             bar used to present Action Modes.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarSplitStyle com.actionbarsherlock:actionBarSplitStyle}</code></td><td> Reference to a style for the split Action Bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarStyle com.actionbarsherlock:actionBarStyle}</code></td><td> Reference to a style for the Action Bar </td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarTabBarStyle com.actionbarsherlock:actionBarTabBarStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarTabStyle com.actionbarsherlock:actionBarTabStyle}</code></td><td> Default style for tabs within an action bar </td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarTabTextStyle com.actionbarsherlock:actionBarTabTextStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionBarWidgetTheme com.actionbarsherlock:actionBarWidgetTheme}</code></td><td> Reference to a theme that should be used to inflate widgets\r
+             and layouts destined for the action bar.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionButtonStyle com.actionbarsherlock:actionButtonStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionDropDownStyle com.actionbarsherlock:actionDropDownStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionMenuTextAppearance com.actionbarsherlock:actionMenuTextAppearance}</code></td><td> TextAppearance style that will be applied to text that\r
+             appears within action menu items.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionMenuTextColor com.actionbarsherlock:actionMenuTextColor}</code></td><td> Color for text that appears within action menu items.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionModeBackground com.actionbarsherlock:actionModeBackground}</code></td><td> Background drawable to use for action mode UI </td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionModeCloseButtonStyle com.actionbarsherlock:actionModeCloseButtonStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionModeCloseDrawable com.actionbarsherlock:actionModeCloseDrawable}</code></td><td> Drawable to use for the close action mode button </td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionModePopupWindowStyle com.actionbarsherlock:actionModePopupWindowStyle}</code></td><td> PopupWindow style to use for action modes when showing as a window overlay.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionModeShareDrawable com.actionbarsherlock:actionModeShareDrawable}</code></td><td> Drawable to use for the Share action button in WebView selection action modes </td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionModeSplitBackground com.actionbarsherlock:actionModeSplitBackground}</code></td><td> Background drawable to use for action mode UI in the lower split bar </td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionModeStyle com.actionbarsherlock:actionModeStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionOverflowButtonStyle com.actionbarsherlock:actionOverflowButtonStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_actionSpinnerItemStyle com.actionbarsherlock:actionSpinnerItemStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_activatedBackgroundIndicator com.actionbarsherlock:activatedBackgroundIndicator}</code></td><td> Drawable used as a background for activated items.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_activityChooserViewStyle com.actionbarsherlock:activityChooserViewStyle}</code></td><td> Default ActivityChooserView style.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_android_windowIsFloating com.actionbarsherlock:android_windowIsFloating}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_buttonStyleSmall com.actionbarsherlock:buttonStyleSmall}</code></td><td> Small Button style.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_dividerVertical com.actionbarsherlock:dividerVertical}</code></td><td> Drawable to use for generic vertical dividers.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_dropDownListViewStyle com.actionbarsherlock:dropDownListViewStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_dropdownListPreferredItemHeight com.actionbarsherlock:dropdownListPreferredItemHeight}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_homeAsUpIndicator com.actionbarsherlock:homeAsUpIndicator}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_listPopupWindowStyle com.actionbarsherlock:listPopupWindowStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_listPreferredItemHeightSmall com.actionbarsherlock:listPreferredItemHeightSmall}</code></td><td> A smaller, sleeker list item height.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_listPreferredItemPaddingLeft com.actionbarsherlock:listPreferredItemPaddingLeft}</code></td><td> The preferred padding along the left edge of list items.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_listPreferredItemPaddingRight com.actionbarsherlock:listPreferredItemPaddingRight}</code></td><td> The preferred padding along the right edge of list items.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_popupMenuStyle com.actionbarsherlock:popupMenuStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_spinnerDropDownItemStyle com.actionbarsherlock:spinnerDropDownItemStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_spinnerItemStyle com.actionbarsherlock:spinnerItemStyle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_textAppearanceLargePopupMenu com.actionbarsherlock:textAppearanceLargePopupMenu}</code></td><td> Text color, typeface, size, and style for the text inside of a popup menu.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_textAppearanceListItemSmall com.actionbarsherlock:textAppearanceListItemSmall}</code></td><td> The preferred TextAppearance for the primary text of small list items.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_textAppearanceSmall com.actionbarsherlock:textAppearanceSmall}</code></td><td> Text color, typeface, size, and style for "small" text.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_textAppearanceSmallPopupMenu com.actionbarsherlock:textAppearanceSmallPopupMenu}</code></td><td> Text color, typeface, size, and style for small text inside of a popup menu.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_textColorPrimary com.actionbarsherlock:textColorPrimary}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_textColorPrimaryDisableOnly com.actionbarsherlock:textColorPrimaryDisableOnly}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_textColorPrimaryInverse com.actionbarsherlock:textColorPrimaryInverse}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_windowActionBar com.actionbarsherlock:windowActionBar}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_windowActionBarOverlay com.actionbarsherlock:windowActionBarOverlay}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_windowActionModeOverlay com.actionbarsherlock:windowActionModeOverlay}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_windowContentOverlay com.actionbarsherlock:windowContentOverlay}</code></td><td> This Drawable is overlaid over the foreground of the Window's content area, usually\r
+             to place a shadow below the title.</td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_windowMinWidthMajor com.actionbarsherlock:windowMinWidthMajor}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_windowMinWidthMinor com.actionbarsherlock:windowMinWidthMinor}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_windowNoTitle com.actionbarsherlock:windowNoTitle}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #SherlockTheme_windowSplitActionBar com.actionbarsherlock:windowSplitActionBar}</code></td><td></td></tr>\r
+           </table>\r
+           @see #SherlockTheme_absForceOverflow\r
+           @see #SherlockTheme_actionBarDivider\r
+           @see #SherlockTheme_actionBarItemBackground\r
+           @see #SherlockTheme_actionBarSize\r
+           @see #SherlockTheme_actionBarSplitStyle\r
+           @see #SherlockTheme_actionBarStyle\r
+           @see #SherlockTheme_actionBarTabBarStyle\r
+           @see #SherlockTheme_actionBarTabStyle\r
+           @see #SherlockTheme_actionBarTabTextStyle\r
+           @see #SherlockTheme_actionBarWidgetTheme\r
+           @see #SherlockTheme_actionButtonStyle\r
+           @see #SherlockTheme_actionDropDownStyle\r
+           @see #SherlockTheme_actionMenuTextAppearance\r
+           @see #SherlockTheme_actionMenuTextColor\r
+           @see #SherlockTheme_actionModeBackground\r
+           @see #SherlockTheme_actionModeCloseButtonStyle\r
+           @see #SherlockTheme_actionModeCloseDrawable\r
+           @see #SherlockTheme_actionModePopupWindowStyle\r
+           @see #SherlockTheme_actionModeShareDrawable\r
+           @see #SherlockTheme_actionModeSplitBackground\r
+           @see #SherlockTheme_actionModeStyle\r
+           @see #SherlockTheme_actionOverflowButtonStyle\r
+           @see #SherlockTheme_actionSpinnerItemStyle\r
+           @see #SherlockTheme_activatedBackgroundIndicator\r
+           @see #SherlockTheme_activityChooserViewStyle\r
+           @see #SherlockTheme_android_windowIsFloating\r
+           @see #SherlockTheme_buttonStyleSmall\r
+           @see #SherlockTheme_dividerVertical\r
+           @see #SherlockTheme_dropDownListViewStyle\r
+           @see #SherlockTheme_dropdownListPreferredItemHeight\r
+           @see #SherlockTheme_homeAsUpIndicator\r
+           @see #SherlockTheme_listPopupWindowStyle\r
+           @see #SherlockTheme_listPreferredItemHeightSmall\r
+           @see #SherlockTheme_listPreferredItemPaddingLeft\r
+           @see #SherlockTheme_listPreferredItemPaddingRight\r
+           @see #SherlockTheme_popupMenuStyle\r
+           @see #SherlockTheme_spinnerDropDownItemStyle\r
+           @see #SherlockTheme_spinnerItemStyle\r
+           @see #SherlockTheme_textAppearanceLargePopupMenu\r
+           @see #SherlockTheme_textAppearanceListItemSmall\r
+           @see #SherlockTheme_textAppearanceSmall\r
+           @see #SherlockTheme_textAppearanceSmallPopupMenu\r
+           @see #SherlockTheme_textColorPrimary\r
+           @see #SherlockTheme_textColorPrimaryDisableOnly\r
+           @see #SherlockTheme_textColorPrimaryInverse\r
+           @see #SherlockTheme_windowActionBar\r
+           @see #SherlockTheme_windowActionBarOverlay\r
+           @see #SherlockTheme_windowActionModeOverlay\r
+           @see #SherlockTheme_windowContentOverlay\r
+           @see #SherlockTheme_windowMinWidthMajor\r
+           @see #SherlockTheme_windowMinWidthMinor\r
+           @see #SherlockTheme_windowNoTitle\r
+           @see #SherlockTheme_windowSplitActionBar\r
+         */\r
+        public static final int[] SherlockTheme = {\r
+            0x01010057, 0x7f010006, 0x7f010007, 0x7f010008,\r
+            0x7f010009, 0x7f01000a, 0x7f01000b, 0x7f01000c,\r
+            0x7f01000d, 0x7f01000e, 0x7f01000f, 0x7f010010,\r
+            0x7f010011, 0x7f010012, 0x7f010013, 0x7f010014,\r
+            0x7f010015, 0x7f010016, 0x7f010017, 0x7f010018,\r
+            0x7f010019, 0x7f01001a, 0x7f01001b, 0x7f01001c,\r
+            0x7f01001d, 0x7f01001e, 0x7f01001f, 0x7f010020,\r
+            0x7f010021, 0x7f010022, 0x7f010023, 0x7f010024,\r
+            0x7f010025, 0x7f010026, 0x7f010027, 0x7f010028,\r
+            0x7f010029, 0x7f01002a, 0x7f01002b, 0x7f01002c,\r
+            0x7f01002d, 0x7f01002e, 0x7f01002f, 0x7f010030,\r
+            0x7f010031, 0x7f010032, 0x7f010033, 0x7f010034,\r
+            0x7f010035, 0x7f010036, 0x7f010037, 0x7f010038,\r
+            0x7f010039\r
+        };\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Specified if we are forcing an action item overflow menu. \r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:absForceOverflow\r
+        */\r
+        public static final int SherlockTheme_absForceOverflow = 52;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Custom divider drawable to use for elements in the action bar. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionBarDivider\r
+        */\r
+        public static final int SherlockTheme_actionBarDivider = 9;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Custom item state list drawable background for action bar items. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionBarItemBackground\r
+        */\r
+        public static final int SherlockTheme_actionBarItemBackground = 10;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Size of the Action Bar, including the contextual\r
+             bar used to present Action Modes. \r
+\r
+\r
+          <p>May be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+<p>May be one of the following constant values.</p>\r
+<table>\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\r
+<tr><td><code>wrap_content</code></td><td>0</td><td></td></tr>\r
+</table>\r
+          <p>This is a private symbol.\r
+          @attr name android:actionBarSize\r
+        */\r
+        public static final int SherlockTheme_actionBarSize = 8;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Reference to a style for the split Action Bar. This style\r
+             controls the split component that holds the menu/action\r
+             buttons. actionBarStyle is still used for the primary\r
+             bar. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionBarSplitStyle\r
+        */\r
+        public static final int SherlockTheme_actionBarSplitStyle = 6;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Reference to a style for the Action Bar \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionBarStyle\r
+        */\r
+        public static final int SherlockTheme_actionBarStyle = 5;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#actionBarTabBarStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:actionBarTabBarStyle\r
+        */\r
+        public static final int SherlockTheme_actionBarTabBarStyle = 2;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default style for tabs within an action bar \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionBarTabStyle\r
+        */\r
+        public static final int SherlockTheme_actionBarTabStyle = 1;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#actionBarTabTextStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:actionBarTabTextStyle\r
+        */\r
+        public static final int SherlockTheme_actionBarTabTextStyle = 3;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Reference to a theme that should be used to inflate widgets\r
+             and layouts destined for the action bar. Most of the time\r
+             this will be a reference to the current theme, but when\r
+             the action bar has a significantly different contrast\r
+             profile than the rest of the activity the difference\r
+             can become important. If this is set to @null the current\r
+             theme will be used.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionBarWidgetTheme\r
+        */\r
+        public static final int SherlockTheme_actionBarWidgetTheme = 7;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#actionButtonStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:actionButtonStyle\r
+        */\r
+        public static final int SherlockTheme_actionButtonStyle = 38;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#actionDropDownStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:actionDropDownStyle\r
+        */\r
+        public static final int SherlockTheme_actionDropDownStyle = 37;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           TextAppearance style that will be applied to text that\r
+             appears within action menu items. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionMenuTextAppearance\r
+        */\r
+        public static final int SherlockTheme_actionMenuTextAppearance = 11;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Color for text that appears within action menu items. \r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionMenuTextColor\r
+        */\r
+        public static final int SherlockTheme_actionMenuTextColor = 12;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Background drawable to use for action mode UI \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionModeBackground\r
+        */\r
+        public static final int SherlockTheme_actionModeBackground = 15;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#actionModeCloseButtonStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:actionModeCloseButtonStyle\r
+        */\r
+        public static final int SherlockTheme_actionModeCloseButtonStyle = 14;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Drawable to use for the close action mode button \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionModeCloseDrawable\r
+        */\r
+        public static final int SherlockTheme_actionModeCloseDrawable = 17;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           PopupWindow style to use for action modes when showing as a window overlay. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionModePopupWindowStyle\r
+        */\r
+        public static final int SherlockTheme_actionModePopupWindowStyle = 19;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Drawable to use for the Share action button in WebView selection action modes \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionModeShareDrawable\r
+        */\r
+        public static final int SherlockTheme_actionModeShareDrawable = 18;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Background drawable to use for action mode UI in the lower split bar \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:actionModeSplitBackground\r
+        */\r
+        public static final int SherlockTheme_actionModeSplitBackground = 16;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#actionModeStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:actionModeStyle\r
+        */\r
+        public static final int SherlockTheme_actionModeStyle = 13;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#actionOverflowButtonStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:actionOverflowButtonStyle\r
+        */\r
+        public static final int SherlockTheme_actionOverflowButtonStyle = 4;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#actionSpinnerItemStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:actionSpinnerItemStyle\r
+        */\r
+        public static final int SherlockTheme_actionSpinnerItemStyle = 43;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Drawable used as a background for activated items. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:activatedBackgroundIndicator\r
+        */\r
+        public static final int SherlockTheme_activatedBackgroundIndicator = 51;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Default ActivityChooserView style. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:activityChooserViewStyle\r
+        */\r
+        public static final int SherlockTheme_activityChooserViewStyle = 50;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#android_windowIsFloating}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+          @attr name android:android_windowIsFloating\r
+        */\r
+        public static final int SherlockTheme_android_windowIsFloating = 0;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Small Button style. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:buttonStyleSmall\r
+        */\r
+        public static final int SherlockTheme_buttonStyleSmall = 20;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Drawable to use for generic vertical dividers. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:dividerVertical\r
+        */\r
+        public static final int SherlockTheme_dividerVertical = 36;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#dropDownListViewStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:dropDownListViewStyle\r
+        */\r
+        public static final int SherlockTheme_dropDownListViewStyle = 40;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#dropdownListPreferredItemHeight}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:dropdownListPreferredItemHeight\r
+        */\r
+        public static final int SherlockTheme_dropdownListPreferredItemHeight = 42;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#homeAsUpIndicator}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:homeAsUpIndicator\r
+        */\r
+        public static final int SherlockTheme_homeAsUpIndicator = 39;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#listPopupWindowStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:listPopupWindowStyle\r
+        */\r
+        public static final int SherlockTheme_listPopupWindowStyle = 49;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           A smaller, sleeker list item height. \r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:listPreferredItemHeightSmall\r
+        */\r
+        public static final int SherlockTheme_listPreferredItemHeightSmall = 30;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The preferred padding along the left edge of list items. \r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:listPreferredItemPaddingLeft\r
+        */\r
+        public static final int SherlockTheme_listPreferredItemPaddingLeft = 31;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The preferred padding along the right edge of list items. \r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          <p>This is a private symbol.\r
+          @attr name android:listPreferredItemPaddingRight\r
+        */\r
+        public static final int SherlockTheme_listPreferredItemPaddingRight = 32;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#popupMenuStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:popupMenuStyle\r
+        */\r
+        public static final int SherlockTheme_popupMenuStyle = 41;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#spinnerDropDownItemStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:spinnerDropDownItemStyle\r
+        */\r
+        public static final int SherlockTheme_spinnerDropDownItemStyle = 29;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#spinnerItemStyle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          @attr name android:spinnerItemStyle\r
+        */\r
+        public static final int SherlockTheme_spinnerItemStyle = 28;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Text color, typeface, size, and style for the text inside of a popup menu. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:textAppearanceLargePopupMenu\r
+        */\r
+        public static final int SherlockTheme_textAppearanceLargePopupMenu = 22;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           The preferred TextAppearance for the primary text of small list items. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:textAppearanceListItemSmall\r
+        */\r
+        public static final int SherlockTheme_textAppearanceListItemSmall = 33;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Text color, typeface, size, and style for "small" text. Defaults to secondary text color. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:textAppearanceSmall\r
+        */\r
+        public static final int SherlockTheme_textAppearanceSmall = 24;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           Text color, typeface, size, and style for small text inside of a popup menu. \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:textAppearanceSmallPopupMenu\r
+        */\r
+        public static final int SherlockTheme_textAppearanceSmallPopupMenu = 23;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#textColorPrimary}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:textColorPrimary\r
+        */\r
+        public static final int SherlockTheme_textColorPrimary = 25;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#textColorPrimaryDisableOnly}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:textColorPrimaryDisableOnly\r
+        */\r
+        public static final int SherlockTheme_textColorPrimaryDisableOnly = 26;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#textColorPrimaryInverse}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:textColorPrimaryInverse\r
+        */\r
+        public static final int SherlockTheme_textColorPrimaryInverse = 27;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#windowActionBar}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:windowActionBar\r
+        */\r
+        public static final int SherlockTheme_windowActionBar = 45;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#windowActionBarOverlay}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:windowActionBarOverlay\r
+        */\r
+        public static final int SherlockTheme_windowActionBarOverlay = 46;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#windowActionModeOverlay}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:windowActionModeOverlay\r
+        */\r
+        public static final int SherlockTheme_windowActionModeOverlay = 47;\r
+        /**\r
+          <p>\r
+          @attr description\r
+           This Drawable is overlaid over the foreground of the Window's content area, usually\r
+             to place a shadow below the title.  \r
+\r
+\r
+          <p>Must be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+          <p>This is a private symbol.\r
+          @attr name android:windowContentOverlay\r
+        */\r
+        public static final int SherlockTheme_windowContentOverlay = 21;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#windowMinWidthMajor}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:windowMinWidthMajor\r
+        */\r
+        public static final int SherlockTheme_windowMinWidthMajor = 34;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#windowMinWidthMinor}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:windowMinWidthMinor\r
+        */\r
+        public static final int SherlockTheme_windowMinWidthMinor = 35;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#windowNoTitle}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:windowNoTitle\r
+        */\r
+        public static final int SherlockTheme_windowNoTitle = 44;\r
+        /**\r
+          <p>This symbol is the offset where the {@link com.actionbarsherlock.R.attr#windowSplitActionBar}\r
+          attribute's value can be found in the {@link #SherlockTheme} array.\r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:windowSplitActionBar\r
+        */\r
+        public static final int SherlockTheme_windowSplitActionBar = 48;\r
+    };\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/libs/android-support-v4.jar b/android-libraries/ActionBarSherlock/libs/android-support-v4.jar
new file mode 100644 (file)
index 0000000..1fbeba0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/libs/android-support-v4.jar differ
diff --git a/android-libraries/ActionBarSherlock/proguard-project.txt b/android-libraries/ActionBarSherlock/proguard-project.txt
new file mode 100644 (file)
index 0000000..f2fe155
--- /dev/null
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/android-libraries/ActionBarSherlock/project.properties b/android-libraries/ActionBarSherlock/project.properties
new file mode 100644 (file)
index 0000000..f28bc83
--- /dev/null
@@ -0,0 +1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+android.library=true
+# Project target.
+target=android-15
diff --git a/android-libraries/ActionBarSherlock/res/color/abs__primary_text_disable_only_holo_dark.xml b/android-libraries/ActionBarSherlock/res/color/abs__primary_text_disable_only_holo_dark.xml
new file mode 100644 (file)
index 0000000..ea7459a
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/abs__bright_foreground_disabled_holo_dark"/>
+    <item android:color="@color/abs__bright_foreground_holo_dark"/> <!-- not selected -->
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/color/abs__primary_text_disable_only_holo_light.xml b/android-libraries/ActionBarSherlock/res/color/abs__primary_text_disable_only_holo_light.xml
new file mode 100644 (file)
index 0000000..0edb33b
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/abs__bright_foreground_disabled_holo_light"/>
+    <item android:color="@color/abs__bright_foreground_holo_light"/> <!-- not selected -->
+</selector>
+
diff --git a/android-libraries/ActionBarSherlock/res/color/abs__primary_text_holo_dark.xml b/android-libraries/ActionBarSherlock/res/color/abs__primary_text_holo_dark.xml
new file mode 100644 (file)
index 0000000..2bcfd0b
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/abs__bright_foreground_disabled_holo_dark"/>
+    <item android:state_window_focused="false" android:color="@color/abs__bright_foreground_holo_dark"/>
+    <item android:state_pressed="true" android:color="@color/abs__bright_foreground_holo_dark"/>
+    <item android:state_selected="true" android:color="@color/abs__bright_foreground_holo_dark"/>
+    <item android:state_activated="true" android:color="@color/abs__bright_foreground_holo_dark"/>
+    <item android:color="@color/abs__bright_foreground_holo_dark"/> <!-- not selected -->
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/color/abs__primary_text_holo_light.xml b/android-libraries/ActionBarSherlock/res/color/abs__primary_text_holo_light.xml
new file mode 100644 (file)
index 0000000..198384f
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false" android:color="@color/abs__bright_foreground_disabled_holo_light"/>
+    <item android:state_window_focused="false" android:color="@color/abs__bright_foreground_holo_light"/>
+    <item android:state_pressed="true" android:color="@color/abs__bright_foreground_holo_light"/>
+    <item android:state_selected="true" android:color="@color/abs__bright_foreground_holo_light"/>
+    <item android:state_activated="true" android:color="@color/abs__bright_foreground_holo_light"/>
+    <item android:color="@color/abs__bright_foreground_holo_light"/> <!-- not selected -->
+    
+</selector>
+
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..769463b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png
new file mode 100644 (file)
index 0000000..88f11dc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_inverse_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..7305047
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..712a551
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..bf3b943
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_bottom_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644 (file)
index 0000000..6c14157
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_share_pack_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644 (file)
index 0000000..f4ff16b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_share_pack_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..cbbaec5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..af917e5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png
new file mode 100644 (file)
index 0000000..2d59f35
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_solid_shadow_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..0520e5a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..e3e3f93
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..1e39572
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..a16db85
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_stacked_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..0eff695
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..219b170
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ab_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..b0dc31f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..4bc2683
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..4af38fb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..d32f74c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..66adffe
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..caeff9c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__btn_cab_done_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png
new file mode 100644 (file)
index 0000000..1d836f6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_bottom_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png
new file mode 100644 (file)
index 0000000..5818666
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_bottom_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png
new file mode 100644 (file)
index 0000000..564fb34
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_top_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png
new file mode 100644 (file)
index 0000000..ae21b76
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__cab_background_top_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png
new file mode 100644 (file)
index 0000000..79e56f5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__dialog_full_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__dialog_full_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__dialog_full_holo_light.9.png
new file mode 100644 (file)
index 0000000..e029f21
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__dialog_full_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png
new file mode 100644 (file)
index 0000000..897a1c1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_ab_back_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_ab_back_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_ab_back_holo_light.png
new file mode 100644 (file)
index 0000000..0c89f71
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_ab_back_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png
new file mode 100644 (file)
index 0000000..d8662e3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_cab_done_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_cab_done_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_cab_done_holo_light.png
new file mode 100644 (file)
index 0000000..ed03f62
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_cab_done_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644 (file)
index 0000000..2abc458
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644 (file)
index 0000000..bb6aef1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_moreoverflow_normal_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644 (file)
index 0000000..6f747c8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_share_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_share_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_share_holo_light.png
new file mode 100644 (file)
index 0000000..682b2fd
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__ic_menu_share_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_activated_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_activated_holo.9.png
new file mode 100644 (file)
index 0000000..4ea7afa
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_activated_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_divider_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_divider_holo_dark.9.png
new file mode 100644 (file)
index 0000000..986ab0b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_divider_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_divider_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_divider_holo_light.9.png
new file mode 100644 (file)
index 0000000..0279e17
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_divider_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_focused_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_focused_holo.9.png
new file mode 100644 (file)
index 0000000..516f5c7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_longpressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_longpressed_holo.9.png
new file mode 100644 (file)
index 0000000..4ea7afa
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_longpressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..5654cd6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..5654cd6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_selector_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_selector_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..f6fd30d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_selector_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_selector_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_selector_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..ca8e9a2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__list_selector_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png
new file mode 100644 (file)
index 0000000..4d3d208
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__menu_dropdown_panel_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png
new file mode 100644 (file)
index 0000000..924a99d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__menu_dropdown_panel_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png
new file mode 100644 (file)
index 0000000..310c368
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_bg_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_bg_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_bg_holo_light.9.png
new file mode 100644 (file)
index 0000000..70cb7fc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_bg_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..1c26920
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_primary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_primary_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_primary_holo_light.9.png
new file mode 100644 (file)
index 0000000..1c26920
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_primary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..40d0d16
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_secondary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png
new file mode 100644 (file)
index 0000000..40d0d16
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__progress_secondary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_48_inner_holo.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_48_inner_holo.png
new file mode 100644 (file)
index 0000000..c8358e9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_48_inner_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_48_outer_holo.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_48_outer_holo.png
new file mode 100644 (file)
index 0000000..f62f74b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_48_outer_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..eb28ff9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..d281adb
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..b298586
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..4215396
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..a280eab
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..f8d619b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..955a2f3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..6c22e22
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__spinner_ab_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png
new file mode 100644 (file)
index 0000000..673e3bf
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_holo.9.png
new file mode 100644 (file)
index 0000000..d57df98
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..6278eef
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_selected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_unselected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_unselected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..aadc6f8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/abs__tab_unselected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-hdpi/ic_launcher.png b/android-libraries/ActionBarSherlock/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..96a442e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-hdpi/ic_launcher.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-ldpi/ic_launcher.png b/android-libraries/ActionBarSherlock/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..9923872
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-ldpi/ic_launcher.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..b229367
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png
new file mode 100644 (file)
index 0000000..c65f443
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_inverse_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..0706c8a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..d814d02
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..b139c8e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_bottom_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644 (file)
index 0000000..ed4ba34
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_share_pack_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644 (file)
index 0000000..8f10bd5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_share_pack_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..743d00b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..17c1fb9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png
new file mode 100644 (file)
index 0000000..ddfc8e3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_solid_shadow_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..007a4b2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..ad6e1a4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..0ad6c88
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..19b50ab
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_stacked_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..ad980b1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..60e6c52
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ab_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..5461b9c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..5dc6f80
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..a70b53c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..c7a9896
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..85d7aad
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..f7b01e0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__btn_cab_done_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png
new file mode 100644 (file)
index 0000000..d8f1c8b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_bottom_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png
new file mode 100644 (file)
index 0000000..31e4989
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_bottom_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png
new file mode 100644 (file)
index 0000000..7c2cbe5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_top_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png
new file mode 100644 (file)
index 0000000..30cbdc1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__cab_background_top_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png
new file mode 100644 (file)
index 0000000..fb3660e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__dialog_full_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__dialog_full_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__dialog_full_holo_light.9.png
new file mode 100644 (file)
index 0000000..f18050e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__dialog_full_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png
new file mode 100644 (file)
index 0000000..df2d3d1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_ab_back_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_ab_back_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_ab_back_holo_light.png
new file mode 100644 (file)
index 0000000..b2aa9c2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_ab_back_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png
new file mode 100644 (file)
index 0000000..a17b6a7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_cab_done_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_cab_done_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_cab_done_holo_light.png
new file mode 100644 (file)
index 0000000..b28b3b5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_cab_done_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644 (file)
index 0000000..ba704b6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644 (file)
index 0000000..01d6816
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_moreoverflow_normal_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644 (file)
index 0000000..6bf21e3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_share_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_share_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_share_holo_light.png
new file mode 100644 (file)
index 0000000..70fe31a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__ic_menu_share_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_activated_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_activated_holo.9.png
new file mode 100644 (file)
index 0000000..3bf8e03
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_activated_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_divider_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_divider_holo_dark.9.png
new file mode 100644 (file)
index 0000000..986ab0b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_divider_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_divider_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_divider_holo_light.9.png
new file mode 100644 (file)
index 0000000..0279e17
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_divider_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_focused_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_focused_holo.9.png
new file mode 100644 (file)
index 0000000..7c0599e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_longpressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_longpressed_holo.9.png
new file mode 100644 (file)
index 0000000..3bf8e03
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_longpressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..6e77525
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..6e77525
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_selector_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_selector_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..92da2f0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_selector_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_selector_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_selector_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..42cb646
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__list_selector_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png
new file mode 100644 (file)
index 0000000..460ec46
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__menu_dropdown_panel_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png
new file mode 100644 (file)
index 0000000..e84adf2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__menu_dropdown_panel_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png
new file mode 100644 (file)
index 0000000..3d946e5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_bg_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_bg_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_bg_holo_light.9.png
new file mode 100644 (file)
index 0000000..4bb22f0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_bg_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..ab8ec69
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_primary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_primary_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_primary_holo_light.9.png
new file mode 100644 (file)
index 0000000..ab8ec69
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_primary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..7274274
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_secondary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png
new file mode 100644 (file)
index 0000000..7274274
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__progress_secondary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_48_inner_holo.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_48_inner_holo.png
new file mode 100644 (file)
index 0000000..9458668
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_48_inner_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_48_outer_holo.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_48_outer_holo.png
new file mode 100644 (file)
index 0000000..4ce73ed
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_48_outer_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..29aff4d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..4055f70
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..ea4ee04
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..f74c02b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..09a2992
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..6536ee6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..202b5b7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..6de0ba8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__spinner_ab_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png
new file mode 100644 (file)
index 0000000..c9972e7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_holo.9.png
new file mode 100644 (file)
index 0000000..587337c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..155c4fc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_selected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..b1223fe
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/abs__tab_unselected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-mdpi/ic_launcher.png b/android-libraries/ActionBarSherlock/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..359047d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-mdpi/ic_launcher.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-v11/abs__progress_medium_holo.xml b/android-libraries/ActionBarSherlock/res/drawable-v11/abs__progress_medium_holo.xml
new file mode 100644 (file)
index 0000000..6bcbdb8
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2010, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <rotate
+             android:drawable="@drawable/abs__spinner_48_outer_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="0"
+             android:toDegrees="1080" />
+    </item>
+    <item>
+        <rotate
+             android:drawable="@drawable/abs__spinner_48_inner_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="720"
+             android:toDegrees="0" />
+    </item>
+</layer-list>
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..5753346
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png
new file mode 100644 (file)
index 0000000..7e6c047
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_inverse_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..8155fe8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..6cee9a1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..fa4d76a
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_bottom_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png
new file mode 100644 (file)
index 0000000..55099d4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png
new file mode 100644 (file)
index 0000000..3c4701f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_share_pack_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..6622cba
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..c427297
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png
new file mode 100644 (file)
index 0000000..d0df29d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_solid_shadow_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png
new file mode 100644 (file)
index 0000000..a0d9c1b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_solid_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png
new file mode 100644 (file)
index 0000000..d36f99f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_solid_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..5ad475d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..6ade5ee
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_stacked_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png
new file mode 100644 (file)
index 0000000..719b923
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_transparent_dark_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png
new file mode 100644 (file)
index 0000000..6da264d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ab_transparent_light_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..7ef2db7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..2283b4c
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..6d2039e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..3c909b5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..131d103
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..3e7dcdf
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__btn_cab_done_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png
new file mode 100644 (file)
index 0000000..0bd0980
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_bottom_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png
new file mode 100644 (file)
index 0000000..43ed26d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_bottom_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png
new file mode 100644 (file)
index 0000000..6b31579
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_top_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png
new file mode 100644 (file)
index 0000000..df0121b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__cab_background_top_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png
new file mode 100644 (file)
index 0000000..f4970ad
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__dialog_full_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png
new file mode 100644 (file)
index 0000000..172fc3b
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__dialog_full_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png
new file mode 100644 (file)
index 0000000..8ded62f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_ab_back_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png
new file mode 100644 (file)
index 0000000..517e9f7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_ab_back_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png
new file mode 100644 (file)
index 0000000..2e06dd0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_cab_done_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png
new file mode 100644 (file)
index 0000000..bb19810
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_cab_done_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png
new file mode 100644 (file)
index 0000000..a92fb1d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png
new file mode 100644 (file)
index 0000000..930ca8d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_moreoverflow_normal_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png
new file mode 100644 (file)
index 0000000..45a0f1d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_dark.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png
new file mode 100644 (file)
index 0000000..528e554
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__ic_menu_share_holo_light.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_activated_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_activated_holo.9.png
new file mode 100644 (file)
index 0000000..eda10e6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_activated_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png
new file mode 100644 (file)
index 0000000..e62f011
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_divider_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_divider_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_divider_holo_light.9.png
new file mode 100644 (file)
index 0000000..65061c0
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_divider_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_focused_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_focused_holo.9.png
new file mode 100644 (file)
index 0000000..690cb1e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_longpressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_longpressed_holo.9.png
new file mode 100644 (file)
index 0000000..eda10e6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_longpressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..e4b3393
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..e4b3393
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..88726b6
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_selector_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..c6a7d4d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__list_selector_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png
new file mode 100644 (file)
index 0000000..e2aff72
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png
new file mode 100644 (file)
index 0000000..93066c8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__menu_dropdown_panel_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png
new file mode 100644 (file)
index 0000000..345f5d3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_bg_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png
new file mode 100644 (file)
index 0000000..c843ef3
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_bg_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..c6c3f1e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_primary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png
new file mode 100644 (file)
index 0000000..c6c3f1e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_primary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png
new file mode 100644 (file)
index 0000000..205b66e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_secondary_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png
new file mode 100644 (file)
index 0000000..205b66e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__progress_secondary_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_48_inner_holo.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_48_inner_holo.png
new file mode 100644 (file)
index 0000000..19517c4
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_48_inner_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_48_outer_holo.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_48_outer_holo.png
new file mode 100644 (file)
index 0000000..14143c5
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_48_outer_holo.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png
new file mode 100644 (file)
index 0000000..d8929fc
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_default_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png
new file mode 100644 (file)
index 0000000..9174c4e
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_default_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png
new file mode 100644 (file)
index 0000000..3015d30
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png
new file mode 100644 (file)
index 0000000..126637d
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_disabled_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png
new file mode 100644 (file)
index 0000000..d45c7a8
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_focused_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png
new file mode 100644 (file)
index 0000000..29036b9
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_focused_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png
new file mode 100644 (file)
index 0000000..2cb34d7
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_dark.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png
new file mode 100644 (file)
index 0000000..82f752f
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__spinner_ab_pressed_holo_light.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png
new file mode 100644 (file)
index 0000000..03cfb09
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_focused_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_holo.9.png
new file mode 100644 (file)
index 0000000..e4229f2
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..e862cb1
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_selected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png
new file mode 100644 (file)
index 0000000..f1eb673
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/abs__tab_unselected_pressed_holo.9.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable-xhdpi/ic_launcher.png b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..71c6d76
Binary files /dev/null and b/android-libraries/ActionBarSherlock/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__activated_background_holo_dark.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__activated_background_holo_dark.xml
new file mode 100644 (file)
index 0000000..85c2c02
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="true" android:drawable="@drawable/abs__list_activated_holo" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__activated_background_holo_light.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__activated_background_holo_light.xml
new file mode 100644 (file)
index 0000000..85c2c02
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_activated="true" android:drawable="@drawable/abs__list_activated_holo" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__btn_cab_done_holo_dark.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__btn_cab_done_holo_dark.xml
new file mode 100644 (file)
index 0000000..cab8962
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+        android:drawable="@drawable/abs__btn_cab_done_pressed_holo_dark" />
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/abs__btn_cab_done_focused_holo_dark" />
+    <item android:state_enabled="true"
+        android:drawable="@drawable/abs__btn_cab_done_default_holo_dark" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__btn_cab_done_holo_light.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__btn_cab_done_holo_light.xml
new file mode 100644 (file)
index 0000000..42ba8a0
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+        android:drawable="@drawable/abs__btn_cab_done_pressed_holo_light" />
+    <item android:state_focused="true" android:state_enabled="true"
+        android:drawable="@drawable/abs__btn_cab_done_focused_holo_light" />
+    <item android:state_enabled="true"
+        android:drawable="@drawable/abs__btn_cab_done_default_holo_light" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__ic_menu_moreoverflow_holo_dark.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__ic_menu_moreoverflow_holo_dark.xml
new file mode 100644 (file)
index 0000000..2588a49
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/abs__ic_menu_moreoverflow_normal_holo_dark" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__ic_menu_moreoverflow_holo_light.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__ic_menu_moreoverflow_holo_light.xml
new file mode 100644 (file)
index 0000000..e2078c9
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/abs__ic_menu_moreoverflow_normal_holo_light" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__item_background_holo_dark.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__item_background_holo_dark.xml
new file mode 100644 (file)
index 0000000..d99b7a4
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abs__list_selector_disabled_holo_dark" />
+    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/abs__list_selector_disabled_holo_dark" />
+    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_dark" />
+    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_dark" />
+    <item android:state_focused="true"                                                             android:drawable="@drawable/abs__list_focused_holo" />
+    <item                                                                                          android:drawable="@android:color/transparent" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__item_background_holo_light.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__item_background_holo_light.xml
new file mode 100644 (file)
index 0000000..da5fb2e
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abs__list_selector_disabled_holo_light" />
+    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/abs__list_selector_disabled_holo_light" />
+    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_light" />
+    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_light" />
+    <item android:state_focused="true"                                                             android:drawable="@drawable/abs__list_focused_holo" />
+    <item                                                                                          android:drawable="@android:color/transparent" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_background_transition_holo_dark.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_background_transition_holo_dark.xml
new file mode 100644 (file)
index 0000000..b2ce4f0
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/abs__list_pressed_holo_dark"  />
+    <item android:drawable="@drawable/abs__list_longpressed_holo"  />
+</transition>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_background_transition_holo_light.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_background_transition_holo_light.xml
new file mode 100644 (file)
index 0000000..d7e31b1
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/abs__list_pressed_holo_light"  />
+    <item android:drawable="@drawable/abs__list_longpressed_holo"  />
+</transition>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_holo_dark.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_holo_dark.xml
new file mode 100644 (file)
index 0000000..08b8b12
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
+
+    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abs__list_selector_disabled_holo_dark" />
+    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/abs__list_selector_disabled_holo_dark" />
+    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_dark" />
+    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_dark" />
+    <item android:state_focused="true"                                                             android:drawable="@drawable/abs__list_focused_holo" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_holo_light.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__list_selector_holo_light.xml
new file mode 100644 (file)
index 0000000..ada490b
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
+
+    <!-- Even though these two point to the same resource, have two states so the drawable will invalidate itself when coming out of pressed state. -->
+    <item android:state_focused="true"  android:state_enabled="false" android:state_pressed="true" android:drawable="@drawable/abs__list_selector_disabled_holo_light" />
+    <item android:state_focused="true"  android:state_enabled="false"                              android:drawable="@drawable/abs__list_selector_disabled_holo_light" />
+    <item android:state_focused="true"                                android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_light" />
+    <item android:state_focused="false"                               android:state_pressed="true" android:drawable="@drawable/abs__list_selector_background_transition_holo_light" />
+    <item android:state_focused="true"                                                             android:drawable="@drawable/abs__list_focused_holo" />
+
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__progress_horizontal_holo_dark.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__progress_horizontal_holo_dark.xml
new file mode 100644 (file)
index 0000000..bd19140
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:id="@android:id/background"
+          android:drawable="@drawable/abs__progress_bg_holo_dark" />
+
+    <item android:id="@android:id/secondaryProgress">
+        <scale android:scaleWidth="100%"
+               android:drawable="@drawable/abs__progress_secondary_holo_dark" />
+    </item>
+
+    <item android:id="@android:id/progress">
+        <scale android:scaleWidth="100%"
+               android:drawable="@drawable/abs__progress_primary_holo_dark" />
+    </item>
+
+</layer-list>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__progress_horizontal_holo_light.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__progress_horizontal_holo_light.xml
new file mode 100644 (file)
index 0000000..321f07c
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:id="@android:id/background"
+          android:drawable="@drawable/abs__progress_bg_holo_light" />
+
+    <item android:id="@android:id/secondaryProgress">
+        <scale android:scaleWidth="100%"
+               android:drawable="@drawable/abs__progress_secondary_holo_light" />
+    </item>
+
+    <item android:id="@android:id/progress">
+        <scale android:scaleWidth="100%"
+               android:drawable="@drawable/abs__progress_primary_holo_light" />
+    </item>
+
+</layer-list>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__progress_medium_holo.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__progress_medium_holo.xml
new file mode 100644 (file)
index 0000000..6d4814f
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2010, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <rotate
+             android:drawable="@drawable/abs__spinner_48_outer_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="0"
+             android:toDegrees="1080" />
+    </item>
+    <item>
+        <rotate
+             android:drawable="@drawable/abs__spinner_48_inner_holo"
+             android:pivotX="50%"
+             android:pivotY="50%"
+             android:fromDegrees="0"
+             android:toDegrees="720" />
+    </item>
+</layer-list>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__spinner_ab_holo_dark.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__spinner_ab_holo_dark.xml
new file mode 100644 (file)
index 0000000..4af5e22
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:drawable="@drawable/abs__spinner_ab_disabled_holo_dark" />
+    <item android:state_pressed="true"
+          android:drawable="@drawable/abs__spinner_ab_pressed_holo_dark" />
+    <item android:state_pressed="false" android:state_focused="true"
+          android:drawable="@drawable/abs__spinner_ab_focused_holo_dark" />
+    <item android:drawable="@drawable/abs__spinner_ab_default_holo_dark" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__spinner_ab_holo_light.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__spinner_ab_holo_light.xml
new file mode 100644 (file)
index 0000000..b785084
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:drawable="@drawable/abs__spinner_ab_disabled_holo_light" />
+    <item android:state_pressed="true"
+          android:drawable="@drawable/abs__spinner_ab_pressed_holo_light" />
+    <item android:state_pressed="false" android:state_focused="true"
+          android:drawable="@drawable/abs__spinner_ab_focused_holo_light" />
+    <item android:drawable="@drawable/abs__spinner_ab_default_holo_light" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/drawable/abs__tab_indicator_ab_holo.xml b/android-libraries/ActionBarSherlock/res/drawable/abs__tab_indicator_ab_holo.xml
new file mode 100644 (file)
index 0000000..d34e208
--- /dev/null
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Non focused states -->
+    <item android:state_focused="false" android:state_selected="false" android:state_pressed="false" android:drawable="@android:color/transparent" />
+    <item android:state_focused="false" android:state_selected="true"  android:state_pressed="false" android:drawable="@drawable/abs__tab_selected_holo" />
+
+    <!-- Focused states -->
+    <item android:state_focused="true" android:state_selected="false" android:state_pressed="false" android:drawable="@drawable/abs__list_focused_holo" />
+    <item android:state_focused="true" android:state_selected="true"  android:state_pressed="false" android:drawable="@drawable/abs__tab_selected_focused_holo" />
+
+    <!-- Pressed -->
+    <!--    Non focused states -->
+    <item android:state_focused="false" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/abs__list_pressed_holo_dark" />
+    <item android:state_focused="false" android:state_selected="true"  android:state_pressed="true" android:drawable="@drawable/abs__tab_selected_pressed_holo" />
+
+    <!--    Focused states -->
+    <item android:state_focused="true" android:state_selected="false" android:state_pressed="true" android:drawable="@drawable/abs__tab_unselected_pressed_holo" />
+    <item android:state_focused="true" android:state_selected="true"  android:state_pressed="true" android:drawable="@drawable/abs__tab_selected_pressed_holo" />
+</selector>
diff --git a/android-libraries/ActionBarSherlock/res/layout-large/abs__action_mode_close_item.xml b/android-libraries/ActionBarSherlock/res/layout-large/abs__action_mode_close_item.xml
new file mode 100644 (file)
index 0000000..8811dad
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/abs__action_mode_close_button"
+        android:focusable="true"
+        android:clickable="true"
+        android:paddingLeft="8dip"
+        style="?attr/actionModeCloseButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginRight="16dip">
+    <ImageView android:layout_width="48dip"
+               android:layout_height="wrap_content"
+               android:layout_gravity="center"
+               android:scaleType="center"
+               android:src="?attr/actionModeCloseDrawable" />
+    <TextView android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:layout_gravity="center"
+              android:layout_marginLeft="4dip"
+              android:layout_marginRight="16dip"
+              android:textAppearance="?android:attr/textAppearanceSmall"
+              android:textSize="12sp"
+              android:textAllCaps="true"
+              android:text="@string/abs__action_mode_done" />
+</com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout-v14/sherlock_spinner_dropdown_item.xml b/android-libraries/ActionBarSherlock/res/layout-v14/sherlock_spinner_dropdown_item.xml
new file mode 100644 (file)
index 0000000..6c183c0
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:id="@android:id/text1"
+    style="?android:attr/spinnerDropDownItemStyle"
+    android:singleLine="true"
+    android:layout_width="match_parent"
+    android:layout_height="?attr/dropdownListPreferredItemHeight"
+    android:ellipsize="marquee" />
diff --git a/android-libraries/ActionBarSherlock/res/layout-v14/sherlock_spinner_item.xml b/android-libraries/ActionBarSherlock/res/layout-v14/sherlock_spinner_item.xml
new file mode 100644 (file)
index 0000000..61dc025
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:id="@android:id/text1"
+    style="?android:attr/spinnerItemStyle"
+    android:singleLine="true"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:ellipsize="marquee" />
diff --git a/android-libraries/ActionBarSherlock/res/layout-xlarge/abs__screen_action_bar.xml b/android-libraries/ActionBarSherlock/res/layout-xlarge/abs__screen_action_bar.xml
new file mode 100644 (file)
index 0000000..040df44
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+This is an optimized layout for a screen with the Action Bar enabled.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:fitsSystemWindows="true"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent">
+    <com.actionbarsherlock.internal.widget.ActionBarContainer
+        android:id="@+id/abs__action_bar_container"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        style="?attr/actionBarStyle">
+        <com.actionbarsherlock.internal.widget.ActionBarView
+            android:id="@+id/abs__action_bar"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            style="?attr/actionBarStyle" />
+        <com.actionbarsherlock.internal.widget.ActionBarContextView
+            android:id="@+id/abs__action_context_bar"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?attr/actionModeStyle" />
+    </com.actionbarsherlock.internal.widget.ActionBarContainer>
+    <com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout
+        android:id="@+id/abs__content"
+        android:layout_width="fill_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:foregroundGravity="fill_horizontal|top"
+        android:foreground="?attr/windowContentOverlay" />
+</LinearLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout-xlarge/abs__screen_action_bar_overlay.xml b/android-libraries/ActionBarSherlock/res/layout-xlarge/abs__screen_action_bar_overlay.xml
new file mode 100644 (file)
index 0000000..c64ef14
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+This is an optimized layout for a screen with
+the Action Bar enabled overlaying application content.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fitsSystemWindows="true">
+    <com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout android:id="@+id/abs__content"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" />
+    <com.actionbarsherlock.internal.widget.ActionBarContainer android:id="@+id/abs__action_bar_container"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        style="?attr/actionBarStyle"
+        android:gravity="top">
+        <com.actionbarsherlock.internal.widget.ActionBarView
+            android:id="@+id/abs__action_bar"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            style="?attr/actionBarStyle" />
+        <com.actionbarsherlock.internal.widget.ActionBarContextView
+            android:id="@+id/abs__action_context_bar"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?attr/actionModeStyle" />
+    </com.actionbarsherlock.internal.widget.ActionBarContainer>
+    <ImageView android:src="?attr/windowContentOverlay"
+               android:scaleType="fitXY"
+               android:layout_width="match_parent"
+               android:layout_height="wrap_content"
+               android:layout_below="@id/abs__action_bar_container" />
+</RelativeLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__action_bar_home.xml b/android-libraries/ActionBarSherlock/res/layout/abs__action_bar_home.xml
new file mode 100644 (file)
index 0000000..5c1e9ec
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+      class="com.actionbarsherlock.internal.widget.ActionBarView$HomeView"
+      android:layout_width="wrap_content"
+      android:layout_height="fill_parent"
+      android:background="?attr/actionBarItemBackground">
+    <ImageView android:id="@id/abs__up"
+               android:src="?attr/homeAsUpIndicator"
+               android:layout_gravity="center_vertical|left"
+               android:visibility="gone"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_marginRight="-8dip" />
+    <ImageView android:id="@id/abs__home"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_marginRight="8dip"
+               android:layout_marginTop="@dimen/abs__action_bar_icon_vertical_padding"
+               android:layout_marginBottom="@dimen/abs__action_bar_icon_vertical_padding"
+               android:layout_gravity="center"
+               android:adjustViewBounds="true"
+               android:scaleType="fitCenter" />
+</view>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__action_bar_tab.xml b/android-libraries/ActionBarSherlock/res/layout/abs__action_bar_tab.xml
new file mode 100644 (file)
index 0000000..f46f7a0
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.actionbarsherlock.internal.widget.ScrollingTabContainerView$TabView"
+    style="?attr/actionBarTabStyle"
+/>
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__action_bar_tab_bar_view.xml b/android-libraries/ActionBarSherlock/res/layout/abs__action_bar_tab_bar_view.xml
new file mode 100644 (file)
index 0000000..0d51220
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<com.actionbarsherlock.internal.widget.IcsLinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    style="?attr/actionBarTabBarStyle"
+/>
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__action_bar_title_item.xml b/android-libraries/ActionBarSherlock/res/layout/abs__action_bar_title_item.xml
new file mode 100644 (file)
index 0000000..dd69aca
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:orientation="horizontal"
+              android:paddingRight="16dip"
+              android:background="?attr/actionBarItemBackground"
+              android:enabled="false">
+
+    <ImageView android:id="@id/abs__up"
+               android:src="?attr/homeAsUpIndicator"
+               android:layout_gravity="center_vertical|left"
+               android:visibility="gone"
+               android:layout_width="wrap_content"
+               android:layout_height="wrap_content" />
+
+    <LinearLayout android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="center_vertical|left"
+                  android:orientation="vertical">
+        <TextView android:id="@+id/abs__action_bar_title"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:singleLine="true"
+                  android:ellipsize="end" />
+        <TextView android:id="@+id/abs__action_bar_subtitle"
+                  android:layout_width="wrap_content"
+                  android:layout_height="wrap_content"
+                  android:layout_marginTop="@dimen/abs__action_bar_subtitle_top_margin"
+                  android:layout_marginBottom="@dimen/abs__action_bar_subtitle_bottom_margin"
+                  android:singleLine="true"
+                  android:ellipsize="end"
+                  android:visibility="gone" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__action_menu_item_layout.xml b/android-libraries/ActionBarSherlock/res/layout/abs__action_menu_item_layout.xml
new file mode 100644 (file)
index 0000000..13149fd
--- /dev/null
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.actionbarsherlock.internal.view.menu.ActionMenuItemView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:addStatesFromChildren="true"
+    android:gravity="center"
+    android:focusable="true"
+    android:paddingLeft="4dip"
+    android:paddingRight="4dip"
+    style="?attr/actionButtonStyle">
+    <ImageButton android:id="@+id/abs__imageButton"
+                 android:layout_width="wrap_content"
+                 android:layout_height="wrap_content"
+                 android:layout_gravity="center"
+                 android:visibility="gone"
+                 android:layout_marginTop="4dip"
+                 android:layout_marginBottom="4dip"
+                 android:layout_marginLeft="4dip"
+                 android:layout_marginRight="4dip"
+                 android:scaleType="fitCenter"
+                 android:adjustViewBounds="true"
+                 android:background="@null"
+                 android:focusable="false" />
+    <com.actionbarsherlock.internal.widget.CapitalizingButton android:id="@+id/abs__textButton"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:visibility="gone"
+            android:textAppearance="?attr/actionMenuTextAppearance"
+            style="?attr/buttonStyleSmall"
+            android:textColor="?attr/actionMenuTextColor"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:background="@null"
+            android:paddingTop="4dip"
+            android:paddingBottom="4dip"
+            android:paddingLeft="4dip"
+            android:paddingRight="4dip"
+            android:focusable="false" />
+</com.actionbarsherlock.internal.view.menu.ActionMenuItemView>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__action_menu_layout.xml b/android-libraries/ActionBarSherlock/res/layout/abs__action_menu_layout.xml
new file mode 100644 (file)
index 0000000..a6f8e53
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.actionbarsherlock.internal.view.menu.ActionMenuView
+     xmlns:android="http://schemas.android.com/apk/res/android"
+     android:layout_width="wrap_content"
+     android:layout_height="wrap_content"
+     android:divider="?attr/actionBarDivider"
+     android:dividerPadding="12dip"
+     android:gravity="center_vertical" />
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__action_mode_bar.xml b/android-libraries/ActionBarSherlock/res/layout/abs__action_mode_bar.xml
new file mode 100644 (file)
index 0000000..7168dc7
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.actionbarsherlock.internal.widget.ActionBarContextView
+     xmlns:android="http://schemas.android.com/apk/res/android"
+     android:layout_width="fill_parent"
+     android:layout_height="wrap_content"
+     android:visibility="gone"
+     style="?attr/actionModeStyle" />
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__action_mode_close_item.xml b/android-libraries/ActionBarSherlock/res/layout/abs__action_mode_close_item.xml
new file mode 100644 (file)
index 0000000..875ec3e
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/abs__action_mode_close_button"
+        android:focusable="true"
+        android:clickable="true"
+        android:paddingLeft="8dip"
+        style="?attr/actionModeCloseButtonStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:layout_marginRight="16dip">
+    <ImageView android:layout_width="wrap_content"
+               android:layout_height="wrap_content"
+               android:layout_gravity="center"
+               android:scaleType="fitCenter"
+               android:src="?attr/actionModeCloseDrawable" />
+</com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__activity_chooser_view.xml b/android-libraries/ActionBarSherlock/res/layout/abs__activity_chooser_view.xml
new file mode 100644 (file)
index 0000000..019d14e
--- /dev/null
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<com.actionbarsherlock.internal.widget.IcsLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/abs__activity_chooser_view_content"
+    android:layout_width="wrap_content"
+    android:layout_height="fill_parent"
+    android:layout_gravity="center"
+    style="?attr/activityChooserViewStyle">
+
+    <FrameLayout
+        android:id="@+id/abs__expand_activities_button"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:layout_gravity="center"
+        android:focusable="true"
+        android:addStatesFromChildren="true"
+        android:background="?attr/actionBarItemBackground">
+
+        <ImageView android:id="@+id/abs__image"
+            android:layout_width="56dip"
+            android:layout_height="36dip"
+            android:layout_gravity="center"
+            android:paddingTop="2dip"
+            android:paddingBottom="2dip"
+            android:paddingLeft="12dip"
+            android:paddingRight="12dip"
+            android:scaleType="fitCenter"
+            android:adjustViewBounds="true" />
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:id="@+id/abs__default_activity_button"
+        android:layout_width="wrap_content"
+        android:layout_height="fill_parent"
+        android:layout_gravity="center"
+        android:focusable="true"
+        android:addStatesFromChildren="true"
+        android:background="?attr/actionBarItemBackground">
+
+        <ImageView android:id="@+id/abs__image"
+            android:layout_width="56dip"
+            android:layout_height="36dip"
+            android:layout_gravity="center"
+            android:paddingTop="2dip"
+            android:paddingBottom="2dip"
+            android:paddingLeft="12dip"
+            android:paddingRight="12dip"
+            android:scaleType="fitCenter"
+            android:adjustViewBounds="true" />
+
+    </FrameLayout>
+
+</com.actionbarsherlock.internal.widget.IcsLinearLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__activity_chooser_view_list_item.xml b/android-libraries/ActionBarSherlock/res/layout/abs__activity_chooser_view_list_item.xml
new file mode 100644 (file)
index 0000000..b430032
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/abs__list_item"
+    android:layout_width="match_parent"
+    android:layout_height="?attr/dropdownListPreferredItemHeight"
+    android:paddingLeft="16dip"
+    android:paddingRight="16dip"
+    android:minWidth="196dip"
+    android:background="?attr/activatedBackgroundIndicator"
+    android:orientation="vertical" >
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:duplicateParentState="true" >
+
+        <ImageView
+            android:id="@+id/abs__icon"
+            android:layout_width="32dip"
+            android:layout_height="32dip"
+            android:layout_gravity="center_vertical"
+            android:layout_marginRight="8dip"
+            android:duplicateParentState="true" />
+
+        <TextView
+            android:id="@+id/abs__title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:textAppearance="?attr/textAppearanceLargePopupMenu"
+            android:duplicateParentState="true"
+            android:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__dialog_title_holo.xml b/android-libraries/ActionBarSherlock/res/layout/abs__dialog_title_holo.xml
new file mode 100644 (file)
index 0000000..6402f28
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+This is an optimized layout for a screen, with the minimum set of features
+enabled.
+-->
+
+<com.actionbarsherlock.internal.widget.FakeDialogPhoneWindow xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:fitsSystemWindows="true">
+    <TextView android:id="@android:id/title" style="?android:attr/windowTitleStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/abs__alert_dialog_title_height"
+        android:paddingLeft="16dip"
+        android:paddingRight="16dip"
+        android:gravity="center_vertical|left" />
+    <View android:id="@+id/abs__titleDivider"
+            android:layout_width="fill_parent"
+            android:layout_height="2dip"
+            android:background="@color/abs__holo_blue_light" />
+    <FrameLayout
+        android:layout_width="wrap_content" android:layout_height="0dp"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:foreground="?attr/windowContentOverlay">
+        <FrameLayout android:id="@+id/abs__content"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent" />
+    </FrameLayout>
+</com.actionbarsherlock.internal.widget.FakeDialogPhoneWindow>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_checkbox.xml b/android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_checkbox.xml
new file mode 100644 (file)
index 0000000..39aca3a
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/abs__checkbox"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
+    android:focusable="false"
+    android:clickable="false"
+    android:duplicateParentState="true" />
+
+
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_icon.xml b/android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_icon.xml
new file mode 100644 (file)
index 0000000..55ab28a
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/abs__icon"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
+    android:layout_marginLeft="8dip"
+    android:layout_marginRight="-8dip"
+    android:layout_marginTop="8dip"
+    android:layout_marginBottom="8dip"
+    android:scaleType="centerInside"
+    android:duplicateParentState="true" />
+
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_layout.xml b/android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_layout.xml
new file mode 100644 (file)
index 0000000..147f36f
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.actionbarsherlock.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="?attr/listPreferredItemHeightSmall">
+    
+    <!-- Icon will be inserted here. -->
+    
+    <!-- The title and summary have some gap between them, and this 'group' should be centered vertically. -->
+    <RelativeLayout
+        android:layout_width="0dip"
+        android:layout_weight="1"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginLeft="?attr/listPreferredItemPaddingLeft"
+        android:layout_marginRight="?attr/listPreferredItemPaddingRight"
+        android:duplicateParentState="true">
+        
+        <TextView 
+            android:id="@+id/abs__title"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentLeft="true"
+            android:textAppearance="?attr/textAppearanceListItemSmall"
+            android:singleLine="true"
+            android:duplicateParentState="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+        <TextView
+            android:id="@+id/abs__shortcut"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/abs__title"
+            android:layout_alignParentLeft="true"
+            android:textAppearance="?attr/textAppearanceSmall"
+            android:singleLine="true"
+            android:duplicateParentState="true" />
+
+    </RelativeLayout>
+
+    <!-- Checkbox, and/or radio button will be inserted here. -->
+    
+</com.actionbarsherlock.internal.view.menu.ListMenuItemView>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_radio.xml b/android-libraries/ActionBarSherlock/res/layout/abs__list_menu_item_radio.xml
new file mode 100644 (file)
index 0000000..ff54bbe
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/abs__radio"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center_vertical"
+    android:focusable="false"
+    android:clickable="false"
+    android:duplicateParentState="true" />
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__popup_menu_item_layout.xml b/android-libraries/ActionBarSherlock/res/layout/abs__popup_menu_item_layout.xml
new file mode 100644 (file)
index 0000000..d42425a
--- /dev/null
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.actionbarsherlock.internal.view.menu.ListMenuItemView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="?attr/dropdownListPreferredItemHeight"
+    android:minWidth="196dip"
+    android:paddingRight="16dip">
+    
+    <!-- Icon will be inserted here. -->
+    
+    <!-- The title and summary have some gap between them, and this 'group' should be centered vertically. -->
+    <RelativeLayout
+        android:layout_width="0dip"
+        android:layout_weight="1"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_marginLeft="16dip"
+        android:duplicateParentState="true">
+        
+        <TextView 
+            android:id="@+id/abs__title"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentLeft="true"
+            android:textAppearance="?attr/textAppearanceLargePopupMenu"
+            android:singleLine="true"
+            android:duplicateParentState="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal" />
+
+        <TextView
+            android:id="@+id/abs__shortcut"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@id/abs__title"
+            android:layout_alignParentLeft="true"
+            android:textAppearance="?attr/textAppearanceSmallPopupMenu"
+            android:singleLine="true"
+            android:duplicateParentState="true" />
+
+    </RelativeLayout>
+
+    <!-- Checkbox, and/or radio button will be inserted here. -->
+    
+</com.actionbarsherlock.internal.view.menu.ListMenuItemView>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__screen_action_bar.xml b/android-libraries/ActionBarSherlock/res/layout/abs__screen_action_bar.xml
new file mode 100644 (file)
index 0000000..1fb82fe
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+This is an optimized layout for a screen with the Action Bar enabled.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:fitsSystemWindows="true">
+    <com.actionbarsherlock.internal.widget.ActionBarContainer
+        android:id="@+id/abs__action_bar_container"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        style="?attr/actionBarStyle">
+        <com.actionbarsherlock.internal.widget.ActionBarView
+            android:id="@+id/abs__action_bar"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            style="?attr/actionBarStyle" />
+        <com.actionbarsherlock.internal.widget.ActionBarContextView
+            android:id="@+id/abs__action_context_bar"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?attr/actionModeStyle" />
+    </com.actionbarsherlock.internal.widget.ActionBarContainer>
+    <com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout
+        android:id="@+id/abs__content"
+        android:layout_width="fill_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:foregroundGravity="fill_horizontal|top"
+        android:foreground="?attr/windowContentOverlay" />
+    <com.actionbarsherlock.internal.widget.ActionBarContainer
+        android:id="@+id/abs__split_action_bar"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        android:gravity="center"
+        style="?attr/actionBarSplitStyle" />
+</LinearLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__screen_action_bar_overlay.xml b/android-libraries/ActionBarSherlock/res/layout/abs__screen_action_bar_overlay.xml
new file mode 100644 (file)
index 0000000..0961ef5
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+This is an optimized layout for a screen with
+the Action Bar enabled overlaying application content.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true">
+    <com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout android:id="@+id/abs__content"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+    <com.actionbarsherlock.internal.widget.ActionBarContainer android:id="@+id/abs__action_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        style="?attr/actionBarStyle"
+        android:gravity="top">
+        <com.actionbarsherlock.internal.widget.ActionBarView
+            android:id="@+id/abs__action_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            style="?attr/actionBarStyle" />
+        <com.actionbarsherlock.internal.widget.ActionBarContextView
+            android:id="@+id/abs__action_context_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?attr/actionModeStyle" />
+    </com.actionbarsherlock.internal.widget.ActionBarContainer>
+    <ImageView android:src="?attr/windowContentOverlay"
+               android:scaleType="fitXY"
+               android:layout_width="match_parent"
+               android:layout_height="wrap_content"
+               android:layout_below="@id/abs__action_bar_container" />
+    <com.actionbarsherlock.internal.widget.ActionBarContainer android:id="@+id/abs__split_action_bar"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  android:layout_gravity="bottom"
+                  style="?attr/actionBarSplitStyle"
+                  android:visibility="gone"
+                  android:gravity="center"/>
+</FrameLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__screen_simple.xml b/android-libraries/ActionBarSherlock/res/layout/abs__screen_simple.xml
new file mode 100644 (file)
index 0000000..33e2dea
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/layout/screen_simple.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+This is an optimized layout for a screen, with the minimum set of features
+enabled.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fitsSystemWindows="true"
+    android:orientation="vertical">
+    <ViewStub android:id="@+id/abs__action_mode_bar_stub"
+              android:inflatedId="@+id/abs__action_mode_bar"
+              android:layout="@layout/abs__action_mode_bar"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content" />
+    <com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout
+         android:id="@+id/abs__content"
+         android:layout_width="fill_parent"
+         android:layout_height="fill_parent"
+         android:foregroundGravity="fill_horizontal|top"
+         android:foreground="?attr/windowContentOverlay" />
+</LinearLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/abs__screen_simple_overlay_action_mode.xml b/android-libraries/ActionBarSherlock/res/layout/abs__screen_simple_overlay_action_mode.xml
new file mode 100644 (file)
index 0000000..f8b9fb1
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+This is an optimized layout for a screen, with the minimum set of features
+enabled.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:fitsSystemWindows="true">
+    <com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout
+         android:id="@+id/abs__content"
+         android:layout_width="fill_parent"
+         android:layout_height="fill_parent"
+         android:foregroundGravity="fill_horizontal|top"
+         android:foreground="?attr/windowContentOverlay" />
+    <ViewStub android:id="@+id/abs__action_mode_bar_stub"
+              android:inflatedId="@+id/abs__action_mode_bar"
+              android:layout="@layout/abs__action_mode_bar"
+              android:layout_width="fill_parent"
+              android:layout_height="wrap_content" />
+</FrameLayout>
diff --git a/android-libraries/ActionBarSherlock/res/layout/main.xml b/android-libraries/ActionBarSherlock/res/layout/main.xml
new file mode 100644 (file)
index 0000000..ac9c0ab
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="fill_parent"\r
+    android:layout_height="fill_parent"\r
+    android:orientation="vertical" >\r
+\r
+    <TextView\r
+        android:layout_width="fill_parent"\r
+        android:layout_height="wrap_content"\r
+        android:text="@string/hello" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/res/layout/sherlock_spinner_dropdown_item.xml b/android-libraries/ActionBarSherlock/res/layout/sherlock_spinner_dropdown_item.xml
new file mode 100644 (file)
index 0000000..a6c6252
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:id="@android:id/text1"
+    style="?attr/spinnerDropDownItemStyle"
+    android:singleLine="true"
+    android:layout_width="match_parent"
+    android:layout_height="?attr/dropdownListPreferredItemHeight"
+    android:ellipsize="marquee" />
diff --git a/android-libraries/ActionBarSherlock/res/layout/sherlock_spinner_item.xml b/android-libraries/ActionBarSherlock/res/layout/sherlock_spinner_item.xml
new file mode 100644 (file)
index 0000000..bea7401
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
+    android:id="@android:id/text1"
+    style="?attr/spinnerItemStyle"
+    android:singleLine="true"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:ellipsize="marquee" />
diff --git a/android-libraries/ActionBarSherlock/res/values-land/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-land/abs__dimens.xml
new file mode 100644 (file)
index 0000000..502cc16
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Default height of an action bar. -->
+    <dimen name="abs__action_bar_default_height">40dip</dimen>
+    <!-- Vertical padding around action bar icons. -->
+    <dimen name="abs__action_bar_icon_vertical_padding">4dip</dimen>
+    <!-- Text size for action bar titles -->
+    <dimen name="abs__action_bar_title_text_size">16dp</dimen>
+    <!-- Text size for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_text_size">12dp</dimen>
+    <!-- Top margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_top_margin">-2dp</dimen>
+    <!-- Bottom margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_bottom_margin">4dip</dimen>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-large-hdpi-1024x600/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-large-hdpi-1024x600/abs__dimens.xml
new file mode 100644 (file)
index 0000000..3312cfa
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Default height of an action bar. -->
+    <dimen name="abs__action_bar_default_height">48dip</dimen>
+    <!-- Vertical padding around action bar icons. -->
+    <dimen name="abs__action_bar_icon_vertical_padding">8dip</dimen>
+    <!-- Text size for action bar titles -->
+    <dimen name="abs__action_bar_title_text_size">18dp</dimen>
+    <!-- Text size for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_text_size">14dp</dimen>
+    <!-- Top margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_top_margin">-3dp</dimen>
+    <!-- Bottom margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_bottom_margin">5dip</dimen>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-large-land-hdpi-1024x600/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-large-land-hdpi-1024x600/abs__dimens.xml
new file mode 100644 (file)
index 0000000..502cc16
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Default height of an action bar. -->
+    <dimen name="abs__action_bar_default_height">40dip</dimen>
+    <!-- Vertical padding around action bar icons. -->
+    <dimen name="abs__action_bar_icon_vertical_padding">4dip</dimen>
+    <!-- Text size for action bar titles -->
+    <dimen name="abs__action_bar_title_text_size">16dp</dimen>
+    <!-- Text size for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_text_size">12dp</dimen>
+    <!-- Top margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_top_margin">-2dp</dimen>
+    <!-- Bottom margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_bottom_margin">4dip</dimen>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-large-land-mdpi-1024x600/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-large-land-mdpi-1024x600/abs__dimens.xml
new file mode 100644 (file)
index 0000000..3312cfa
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Default height of an action bar. -->
+    <dimen name="abs__action_bar_default_height">48dip</dimen>
+    <!-- Vertical padding around action bar icons. -->
+    <dimen name="abs__action_bar_icon_vertical_padding">8dip</dimen>
+    <!-- Text size for action bar titles -->
+    <dimen name="abs__action_bar_title_text_size">18dp</dimen>
+    <!-- Text size for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_text_size">14dp</dimen>
+    <!-- Top margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_top_margin">-3dp</dimen>
+    <!-- Bottom margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_bottom_margin">5dip</dimen>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-large-mdpi-1024x600/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-large-mdpi-1024x600/abs__dimens.xml
new file mode 100644 (file)
index 0000000..3591033
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Default height of an action bar. -->
+    <dimen name="abs__action_bar_default_height">56dip</dimen>
+    <!-- Vertical padding around action bar icons. -->
+    <dimen name="abs__action_bar_icon_vertical_padding">4dip</dimen>
+    <!-- Text size for action bar titles -->
+    <dimen name="abs__action_bar_title_text_size">18dp</dimen>
+    <!-- Text size for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_text_size">14dp</dimen>
+    <!-- Top margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_top_margin">-3dp</dimen>
+    <!-- Bottom margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_bottom_margin">9dip</dimen>
+
+    <!-- Minimum width for an action button in the menu area of an action bar -->
+    <dimen name="action_button_min_width">64dip</dimen>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-large/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-large/abs__dimens.xml
new file mode 100644 (file)
index 0000000..63b12f7
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- The platform's desired minimum size for a dialog's width when it
+         is along the major axis (that is the screen is landscape).  This may
+         be either a fraction or a dimension. -->
+    <item type="dimen" name="abs__dialog_min_width_major">55%</item>
+    <!-- The platform's desired minimum size for a dialog's width when it
+         is along the minor axis (that is the screen is portrait).  This may
+         be either a fraction or a dimension. -->
+    <item type="dimen" name="abs__dialog_min_width_minor">80%</item>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-sw600dp/abs__bools.xml b/android-libraries/ActionBarSherlock/res/values-sw600dp/abs__bools.xml
new file mode 100644 (file)
index 0000000..7a48e15
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <bool name="abs__action_bar_expanded_action_views_exclusive">false</bool>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-sw600dp/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-sw600dp/abs__dimens.xml
new file mode 100644 (file)
index 0000000..f678538
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Default height of an action bar. -->
+    <dimen name="abs__action_bar_default_height">56dip</dimen>
+    <!-- Vertical padding around action bar icons. -->
+    <dimen name="abs__action_bar_icon_vertical_padding">4dip</dimen>
+    <!-- Text size for action bar titles -->
+    <dimen name="abs__action_bar_title_text_size">18dp</dimen>
+    <!-- Text size for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_text_size">14dp</dimen>
+    <!-- Top margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_top_margin">-3dp</dimen>
+    <!-- Bottom margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_bottom_margin">9dip</dimen>
+    
+    <integer name="abs__max_action_buttons">5</integer>
+
+    <!-- Minimum width for an action button in the menu area of an action bar -->
+    <dimen name="action_button_min_width">64dip</dimen>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-v11/abs__themes.xml b/android-libraries/ActionBarSherlock/res/values-v11/abs__themes.xml
new file mode 100644 (file)
index 0000000..0347357
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+    <style name="Sherlock.__Theme" parent="android:Theme.Holo">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowActionBar">false</item>
+    </style>
+    <style name="Sherlock.__Theme.Light" parent="android:Theme.Holo.Light">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowActionBar">false</item>
+    </style>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-v14/abs__styles.xml b/android-libraries/ActionBarSherlock/res/values-v14/abs__styles.xml
new file mode 100644 (file)
index 0000000..f2aa64d
--- /dev/null
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+    <style name="Widget.Sherlock.ActionBar" parent="android:Widget.Holo.ActionBar">
+    </style>
+    <style name="Widget.Sherlock.ActionBar.Solid" parent="android:Widget.Holo.ActionBar.Solid">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar" parent="android:Widget.Holo.Light.ActionBar">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.Solid" parent="android:Widget.Holo.Light.ActionBar.Solid">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.Solid.Inverse" parent="android:Widget.Holo.Light.ActionBar.Solid.Inverse">
+    </style>
+
+    <style name="Widget.Sherlock.ActionBar.TabView" parent="android:Widget.Holo.ActionBar.TabView">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabView" parent="android:Widget.Holo.Light.ActionBar.TabView">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabView.Inverse" parent="android:Widget.Holo.Light.ActionBar.TabView.Inverse">
+    </style>
+
+    <style name="Widget.Sherlock.ActionBar.TabBar" parent="android:Widget.Holo.ActionBar.TabBar">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabBar" parent="android:Widget.Holo.Light.ActionBar.TabBar">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabBar.Inverse" parent="android:Widget.Holo.Light.ActionBar.TabBar.Inverse">
+    </style>
+
+    <style name="Widget.Sherlock.ActionBar.TabText" parent="android:Widget.Holo.ActionBar.TabText">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabText" parent="android:Widget.Holo.Light.ActionBar.TabText">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabText.Inverse" parent="android:Widget.Holo.Light.ActionBar.TabText.Inverse">
+    </style>
+
+    <style name="Widget.Sherlock.ActionButton" parent="android:Widget.Holo.ActionButton">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionButton" parent="android:Widget.Holo.Light.ActionButton">
+    </style>
+
+    <style name="Widget.Sherlock.ActionButton.CloseMode" parent="android:Widget.Holo.ActionButton.CloseMode">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionButton.CloseMode" parent="android:Widget.Holo.Light.ActionButton.CloseMode">
+    </style>
+
+    <style name="Widget.Sherlock.ActionButton.Overflow" parent="android:Widget.Holo.ActionButton.Overflow">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionButton.Overflow" parent="android:Widget.Holo.Light.ActionButton.Overflow">
+    </style>
+
+    <style name="Widget.Sherlock.ActionMode" parent="android:Widget.Holo.ActionMode">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionMode" parent="android:Widget.Holo.Light.ActionMode">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionMode.Inverse" parent="android:Widget.Holo.Light.ActionMode.Inverse">
+    </style>
+
+    <style name="Widget.Sherlock.PopupMenu" parent="android:Widget.Holo.PopupMenu">
+    </style>
+    <style name="Widget.Sherlock.Light.PopupMenu" parent="android:Widget.Holo.Light.PopupMenu">
+    </style>
+
+    <style name="Widget.Sherlock.Spinner.DropDown.ActionBar" parent="android:Widget.Holo.Spinner">
+    </style>
+    <style name="Widget.Sherlock.Light.Spinner.DropDown.ActionBar" parent="android:Widget.Holo.Light.Spinner">
+    </style>
+
+    <style name="Widget.Sherlock.ListView.DropDown" parent="android:Widget.Holo.ListView.DropDown">
+    </style>
+    <style name="Widget.Sherlock.Light.ListView.DropDown" parent="android:Widget.Holo.Light.ListView.DropDown">
+    </style>
+
+    <style name="Widget.Sherlock.PopupWindow.ActionMode" parent="android:Widget.Holo.PopupWindow">
+    </style>
+    <style name="Widget.Sherlock.Light.PopupWindow.ActionMode" parent="android:Widget.Holo.Light.PopupWindow">
+    </style>
+
+    <style name="Widget.Sherlock.ProgressBar" parent="android:Widget.Holo.ProgressBar">
+    </style>
+    <style name="Widget.Sherlock.Light.ProgressBar" parent="android:Widget.Holo.Light.ProgressBar">
+    </style>
+
+    <style name="Widget.Sherlock.ProgressBar.Horizontal" parent="android:Widget.Holo.ProgressBar.Horizontal">
+    </style>
+    <style name="Widget.Sherlock.Light.ProgressBar.Horizontal" parent="android:Widget.Holo.Light.ProgressBar.Horizontal">
+    </style>
+
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Menu" parent="android:TextAppearance.Holo.Widget.ActionBar.Menu">
+    </style>
+
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Title" parent="android:TextAppearance.Holo.Widget.ActionBar.Title">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Title.Inverse" parent="android:TextAppearance.Holo.Widget.ActionBar.Title.Inverse">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Subtitle" parent="android:TextAppearance.Holo.Widget.ActionBar.Subtitle">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Subtitle.Inverse" parent="android:TextAppearance.Holo.Widget.ActionBar.Subtitle.Inverse">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionMode.Title" parent="android:TextAppearance.Holo.Widget.ActionMode.Title">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionMode.Title.Inverse" parent="android:TextAppearance.Holo.Widget.ActionMode.Title.Inverse">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionMode.Subtitle" parent="android:TextAppearance.Holo.Widget.ActionMode.Subtitle">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionMode.Subtitle.Inverse" parent="android:TextAppearance.Holo.Widget.ActionMode.Subtitle.Inverse">
+    </style>
+
+    <style name="TextAppearance.Sherlock.Widget.PopupMenu" parent="android:TextAppearance.Holo.Widget.PopupMenu">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.PopupMenu.Large" parent="android:TextAppearance.Holo.Widget.PopupMenu.Large">
+    </style>
+    <style name="TextAppearance.Sherlock.Light.Widget.PopupMenu.Large" parent="android:TextAppearance.Holo.Widget.PopupMenu.Large">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.PopupMenu.Small" parent="android:TextAppearance.Holo.Widget.PopupMenu.Small">
+    </style>
+    <style name="TextAppearance.Sherlock.Light.Widget.PopupMenu.Small" parent="android:TextAppearance.Holo.Widget.PopupMenu.Small">
+    </style>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-v14/abs__themes.xml b/android-libraries/ActionBarSherlock/res/values-v14/abs__themes.xml
new file mode 100644 (file)
index 0000000..ceb9607
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+    <style name="Sherlock.__Theme" parent="android:Theme.Holo">
+    </style>
+    <style name="Sherlock.__Theme.Light" parent="android:Theme.Holo.Light">
+    </style>
+    <style name="Sherlock.__Theme.DarkActionBar" parent="android:Theme.Holo.Light.DarkActionBar">
+        <!-- Useful for offsetting contents with an overlay action bar. -->
+        <item name="actionBarSize">?android:attr/actionBarSize</item>
+        <!-- Needed for our bug-fix dropdown list navigation layout. :( -->
+        <item name="dropdownListPreferredItemHeight">48dp</item>
+        <!-- Needed for our ShareActionProvider implementation. -->
+        <item name="android:actionBarWidgetTheme">@style/Theme.Sherlock</item>
+        <!-- For crazy people who use IcsSpinner. -->
+        <item name="dropDownListViewStyle">?android:attr/dropDownListViewStyle</item>
+    </style>
+
+    <style name="Theme.Sherlock.NoActionBar">
+      <item name="android:windowActionBar">false</item>
+      <item name="android:windowNoTitle">true</item>
+    </style>
+    <style name="Theme.Sherlock.Light.NoActionBar">
+      <item name="android:windowActionBar">false</item>
+      <item name="android:windowNoTitle">true</item>
+    </style>
+
+    <style name="Theme.Sherlock.Dialog" parent="android:Theme.Holo.Dialog">
+    </style>
+    <style name="Theme.Sherlock.Light.Dialog" parent="android:Theme.Holo.Light.Dialog">
+    </style>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-w360dp/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-w360dp/abs__dimens.xml
new file mode 100644 (file)
index 0000000..6f49d7e
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <integer name="abs__max_action_buttons">3</integer>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-w480dp/abs__bools.xml b/android-libraries/ActionBarSherlock/res/values-w480dp/abs__bools.xml
new file mode 100644 (file)
index 0000000..3eaf4ae
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <bool name="abs__action_bar_embed_tabs">true</bool>
+    <bool name="abs__split_action_bar_is_narrow">false</bool>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-w480dp/abs__config.xml b/android-libraries/ActionBarSherlock/res/values-w480dp/abs__config.xml
new file mode 100644 (file)
index 0000000..88357b0
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Whether action menu items should obey the "withText" showAsAction
+         flag. This may be set to false for situations where space is
+         extremely limited. -->
+    <bool name="abs__config_allowActionMenuItemTextWithIcon">true</bool>
+
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-w500dp/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-w500dp/abs__dimens.xml
new file mode 100644 (file)
index 0000000..2fd4dee
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <integer name="abs__max_action_buttons">4</integer>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-w600dp/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-w600dp/abs__dimens.xml
new file mode 100644 (file)
index 0000000..b085952
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <integer name="abs__max_action_buttons">5</integer>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values-xlarge/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values-xlarge/abs__dimens.xml
new file mode 100644 (file)
index 0000000..bfc535d
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Default height of an action bar. -->
+    <dimen name="abs__action_bar_default_height">56dip</dimen>
+    <!-- Vertical padding around action bar icons. -->
+    <dimen name="abs__action_bar_icon_vertical_padding">4dip</dimen>
+    <!-- Text size for action bar titles -->
+    <dimen name="abs__action_bar_title_text_size">18dp</dimen>
+    <!-- Text size for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_text_size">14dp</dimen>
+    <!-- Top margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_top_margin">-3dp</dimen>
+    <!-- Bottom margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_bottom_margin">9dip</dimen>
+
+    <!-- Minimum width for an action button in the menu area of an action bar -->
+    <dimen name="abs__action_button_min_width">64dip</dimen>
+    
+    <!-- The platform's desired minimum size for a dialog's width when it
+         is along the major axis (that is the screen is landscape).  This may
+         be either a fraction or a dimension. -->
+    <item type="dimen" name="abs__dialog_min_width_major">45%</item>
+    <!-- The platform's desired minimum size for a dialog's width when it
+         is along the minor axis (that is the screen is portrait).  This may
+         be either a fraction or a dimension. -->
+    <item type="dimen" name="abs__dialog_min_width_minor">72%</item>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__attrs.xml b/android-libraries/ActionBarSherlock/res/values/abs__attrs.xml
new file mode 100644 (file)
index 0000000..81c3471
--- /dev/null
@@ -0,0 +1,380 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+    <attr name="titleTextStyle" format="reference" />
+    <attr name="subtitleTextStyle" format="reference" />
+    <attr name="background" format="reference|color" />
+    <attr name="backgroundSplit" format="reference|color" />
+    <attr name="height" format="dimension" />
+    <attr name="divider" format="reference" />
+
+    <declare-styleable name="SherlockTheme">
+        <!-- =================== -->
+        <!-- Action bar styles   -->
+        <!-- =================== -->
+        <eat-comment />
+        <!-- Default style for tabs within an action bar -->
+        <attr name="actionBarTabStyle" format="reference" />
+        <attr name="actionBarTabBarStyle" format="reference" />
+        <attr name="actionBarTabTextStyle" format="reference" />
+        <attr name="actionOverflowButtonStyle" format="reference" />
+        <!-- Reference to a style for the Action Bar -->
+        <attr name="actionBarStyle" format="reference" />
+        <!-- Reference to a style for the split Action Bar. This style
+             controls the split component that holds the menu/action
+             buttons. actionBarStyle is still used for the primary
+             bar. -->
+        <attr name="actionBarSplitStyle" format="reference" />
+        <!-- Reference to a theme that should be used to inflate widgets
+             and layouts destined for the action bar. Most of the time
+             this will be a reference to the current theme, but when
+             the action bar has a significantly different contrast
+             profile than the rest of the activity the difference
+             can become important. If this is set to @null the current
+             theme will be used.-->
+        <attr name="actionBarWidgetTheme" format="reference" />
+        <!-- Size of the Action Bar, including the contextual
+             bar used to present Action Modes. -->
+        <attr name="actionBarSize" format="dimension" >
+            <enum name="wrap_content" value="0" />
+        </attr>
+        <!-- Custom divider drawable to use for elements in the action bar. -->
+        <attr name="actionBarDivider" format="reference" />
+        <!-- Custom item state list drawable background for action bar items. -->
+        <attr name="actionBarItemBackground" format="reference" />
+        <!-- TextAppearance style that will be applied to text that
+             appears within action menu items. -->
+        <attr name="actionMenuTextAppearance" format="reference" />
+        <!-- Color for text that appears within action menu items. -->
+        <attr name="actionMenuTextColor" format="color|reference" />
+
+        <!-- =================== -->
+        <!-- Action mode styles  -->
+        <!-- =================== -->
+        <eat-comment />
+        <attr name="actionModeStyle" format="reference" />
+        <attr name="actionModeCloseButtonStyle" format="reference" />
+        <!-- Background drawable to use for action mode UI -->
+        <attr name="actionModeBackground" format="reference" />
+        <!-- Background drawable to use for action mode UI in the lower split bar -->
+        <attr name="actionModeSplitBackground" format="reference" />
+        <!-- Drawable to use for the close action mode button -->
+        <attr name="actionModeCloseDrawable" format="reference" />
+        <!-- Drawable to use for the Share action button in WebView selection action modes -->
+        <attr name="actionModeShareDrawable" format="reference" />
+
+        <!-- PopupWindow style to use for action modes when showing as a window overlay. -->
+        <attr name="actionModePopupWindowStyle" format="reference" />
+
+        <!-- ============= -->
+        <!-- Button styles -->
+        <!-- ============= -->
+        <eat-comment />
+
+        <!-- Small Button style. -->
+        <attr name="buttonStyleSmall" format="reference" />
+
+
+
+        <!-- This Drawable is overlaid over the foreground of the Window's content area, usually
+             to place a shadow below the title.  -->
+        <attr name="windowContentOverlay" format="reference" />
+
+        <!-- Text color, typeface, size, and style for the text inside of a popup menu. -->
+        <attr name="textAppearanceLargePopupMenu" format="reference" />
+
+        <!-- Text color, typeface, size, and style for small text inside of a popup menu. -->
+        <attr name="textAppearanceSmallPopupMenu" format="reference" />
+
+
+        <!-- Text color, typeface, size, and style for "small" text. Defaults to secondary text color. -->
+        <attr name="textAppearanceSmall" format="reference" />
+
+        <attr name="textColorPrimary" format="color" />
+        <attr name="textColorPrimaryDisableOnly" format="color" />
+        <attr name="textColorPrimaryInverse" format="color" />
+
+        <attr name="spinnerItemStyle" format="reference" />
+        <attr name="spinnerDropDownItemStyle" format="reference" />
+
+        <!-- =========== -->
+        <!-- List styles -->
+        <!-- =========== -->
+        <eat-comment />
+
+        <!-- A smaller, sleeker list item height. -->
+        <attr name="listPreferredItemHeightSmall" format="dimension" />
+
+        <!-- The preferred padding along the left edge of list items. -->
+        <attr name="listPreferredItemPaddingLeft" format="dimension" />
+        <!-- The preferred padding along the right edge of list items. -->
+        <attr name="listPreferredItemPaddingRight" format="dimension" />
+
+        <!-- The preferred TextAppearance for the primary text of small list items. -->
+        <attr name="textAppearanceListItemSmall" format="reference" />
+
+
+        <attr name="windowMinWidthMajor" format="dimension" />
+        <attr name="windowMinWidthMinor" format="dimension" />
+
+
+
+        <!-- Drawable to use for generic vertical dividers. -->
+        <attr name="dividerVertical" format="reference" />
+
+        <attr name="actionDropDownStyle" format="reference" />
+        <attr name="actionButtonStyle" format="reference" />
+        <attr name="homeAsUpIndicator" format="reference" />
+        <attr name="dropDownListViewStyle" format="reference" />
+        <attr name="popupMenuStyle" format="reference" />
+        <attr name="dropdownListPreferredItemHeight" format="dimension" />
+        <attr name="actionSpinnerItemStyle" format="reference" />
+        <attr name="windowNoTitle" format="boolean"/>
+        <attr name="windowActionBar" format="boolean"/>
+        <attr name="windowActionBarOverlay" format="boolean"/>
+        <attr name="windowActionModeOverlay" format="boolean"/>
+        <attr name="windowSplitActionBar" format="boolean" />
+
+
+        <attr name="listPopupWindowStyle" format="reference" />
+
+
+        <!-- Default ActivityChooserView style. -->
+        <attr name="activityChooserViewStyle" format="reference" />
+        <!-- Drawable used as a background for activated items. -->
+        <attr name="activatedBackgroundIndicator" format="reference" />
+
+        <!-- Specified if we are forcing an action item overflow menu. -->
+        <attr name="absForceOverflow" format="boolean" />
+
+        <attr name="android:windowIsFloating" />
+    </declare-styleable>
+
+
+    <!-- Attributes used to style the Action Bar. -->
+    <declare-styleable name="SherlockActionBar">
+        <!-- The type of navigation to use. -->
+        <attr name="navigationMode">
+            <!-- Normal static title text -->
+            <enum name="normal" value="0" />
+            <!-- The action bar will use a selection list for navigation. -->
+            <enum name="listMode" value="1" />
+            <!-- The action bar will use a series of horizontal tabs for navigation. -->
+            <enum name="tabMode" value="2" />
+        </attr>
+        <!-- Options affecting how the action bar is displayed. -->
+        <attr name="displayOptions">
+            <flag name="useLogo" value="0x1" />
+            <flag name="showHome" value="0x2" />
+            <flag name="homeAsUp" value="0x4" />
+            <flag name="showTitle" value="0x8" />
+            <flag name="showCustom" value="0x10" />
+            <flag name="disableHome" value="0x20" />
+        </attr>
+        <!-- Specifies title text used for navigationMode="normal" -->
+        <attr name="title" format="string" />
+        <!-- Specifies subtitle text used for navigationMode="normal" -->
+        <attr name="subtitle" format="string" />
+        <!-- Specifies a style to use for title text. -->
+        <attr name="titleTextStyle" />
+        <!-- Specifies a style to use for subtitle text. -->
+        <attr name="subtitleTextStyle" />
+        <!-- Specifies the drawable used for the application icon. -->
+        <attr name="icon" format="reference" />
+        <!-- Specifies the drawable used for the application logo. -->
+        <attr name="logo" format="reference" />
+        <!-- Specifies the drawable used for item dividers. -->
+        <attr name="divider" />
+        <!-- Specifies a background drawable for the action bar. -->
+        <attr name="background" />
+        <!-- Specifies a background drawable for a second stacked row of the action bar. -->
+        <attr name="backgroundStacked" format="reference|color" />
+        <!-- Specifies a background drawable for the bottom component of a split action bar. -->
+        <attr name="backgroundSplit" />
+        <!-- Specifies a layout for custom navigation. Overrides navigationMode. -->
+        <attr name="customNavigationLayout" format="reference" />
+        <!-- Specifies a fixed height. -->
+        <attr name="height" />
+        <!-- Specifies a layout to use for the "home" section of the action bar. -->
+        <attr name="homeLayout" format="reference" />
+        <!-- Specifies a style resource to use for an embedded progress bar. -->
+        <attr name="progressBarStyle" format="reference" />
+        <!-- Specifies a style resource to use for an indeterminate progress spinner. -->
+        <attr name="indeterminateProgressStyle" format="reference" />
+        <!-- Specifies the horizontal padding on either end for an embedded progress bar. -->
+        <attr name="progressBarPadding" format="dimension" />
+        <!-- Specifies padding that should be applied to the left and right sides of
+             system-provided items in the bar. -->
+        <attr name="itemPadding" format="dimension" />
+    </declare-styleable>
+
+
+    <declare-styleable name="SherlockActionMode">
+        <!-- Specifies a style to use for title text. -->
+        <attr name="titleTextStyle" />
+        <!-- Specifies a style to use for subtitle text. -->
+        <attr name="subtitleTextStyle" />
+        <!-- Specifies a background for the action mode bar. -->
+        <attr name="background" />
+        <!-- Specifies a background for the split action mode bar. -->
+        <attr name="backgroundSplit" />
+        <!-- Specifies a fixed height for the action mode bar. -->
+        <attr name="height" />
+    </declare-styleable>
+
+    <declare-styleable name="SherlockMenuView">
+        <!-- Default appearance of menu item text. -->
+        <attr name="itemTextAppearance" format="reference" />
+        <!-- Default horizontal divider between rows of menu items. -->
+        <attr name="horizontalDivider" format="reference" />
+        <!-- Default vertical divider between menu items. -->
+        <attr name="verticalDivider" format="reference" />
+        <!-- Default background for the menu header. -->
+        <attr name="headerBackground" format="color|reference" />
+        <!-- Default background for each menu item. -->
+        <attr name="itemBackground" format="color|reference" />
+        <!-- Default animations for the menu. -->
+        <attr name="windowAnimationStyle" format="reference" />
+        <!-- Default disabled icon alpha for each menu item that shows an icon. -->
+        <attr name="itemIconDisabledAlpha" format="float" />
+        <!-- Whether space should be reserved in layout when an icon is missing. -->
+        <attr name="preserveIconSpacing" format="boolean" />
+    </declare-styleable>
+
+    <declare-styleable name="SherlockActionMenuItemView">
+        <attr name="android:minWidth" />
+    </declare-styleable>
+
+    <declare-styleable name="SherlockActivityChooserView">
+        <!-- The maximal number of items initially shown in the activity list. -->
+        <attr name="initialActivityCount" format="string" />
+        <!-- The drawable to show in the button for expanding the activities overflow popup.
+             <strong>Note:</strong> Clients would like to set this drawable
+             as a clue about the action the chosen activity will perform. For
+             example, if share activity is to be chosen the drawable should
+             give a clue that sharing is to be performed.
+         -->
+        <attr name="expandActivityOverflowButtonDrawable" format="reference" />
+
+        <attr name="android:background" />
+    </declare-styleable>
+
+    <!-- Base attributes that are available to all groups. -->
+    <declare-styleable name="SherlockMenuGroup">
+
+        <!-- The ID of the group. -->
+        <attr name="android:id" />
+
+        <!-- The category applied to all items within this group.
+             (This will be or'ed with the orderInCategory attribute.) -->
+        <attr name="android:menuCategory" />
+
+        <!-- The order within the category applied to all items within this group.
+             (This will be or'ed with the category attribute.) -->
+        <attr name="android:orderInCategory" />
+
+        <!-- Whether the items are capable of displaying a check mark. -->
+        <attr name="android:checkableBehavior" />
+
+        <!-- Whether the items are shown/visible. -->
+        <attr name="android:visible" />
+
+        <!-- Whether the items are enabled. -->
+        <attr name="android:enabled" />
+
+    </declare-styleable>
+
+    <!-- Base attributes that are available to all Item objects. -->
+    <declare-styleable name="SherlockMenuItem">
+
+        <!-- The ID of the item. -->
+        <attr name="android:id" />
+
+        <!-- The category applied to the item.
+             (This will be or'ed with the orderInCategory attribute.) -->
+        <attr name="android:menuCategory" />
+
+        <!-- The order within the category applied to the item.
+             (This will be or'ed with the category attribute.) -->
+        <attr name="android:orderInCategory" />
+
+        <!-- The title associated with the item. -->
+        <attr name="android:title" />
+
+        <!-- The condensed title associated with the item.  This is used in situations where the
+             normal title may be too long to be displayed. -->
+        <attr name="android:titleCondensed" />
+
+        <!-- The icon associated with this item.  This icon will not always be shown, so
+             the title should be sufficient in describing this item. -->
+        <attr name="android:icon" />
+
+        <!-- The alphabetic shortcut key.  This is the shortcut when using a keyboard
+             with alphabetic keys. -->
+        <attr name="android:alphabeticShortcut" />
+
+        <!-- The numeric shortcut key.  This is the shortcut when using a numeric (e.g., 12-key)
+             keyboard. -->
+        <attr name="android:numericShortcut" />
+
+        <!-- Whether the item is capable of displaying a check mark. -->
+        <attr name="android:checkable" />
+
+        <!-- Whether the item is checked.  Note that you must first have enabled checking with
+             the checkable attribute or else the check mark will not appear. -->
+        <attr name="android:checked" />
+
+        <!-- Whether the item is shown/visible. -->
+        <attr name="android:visible" />
+
+        <!-- Whether the item is enabled. -->
+        <attr name="android:enabled" />
+
+        <!-- Name of a method on the Context used to inflate the menu that will be
+             called when the item is clicked. -->
+        <attr name="android:onClick" />
+
+        <!-- How this item should display in the Action Bar, if present. -->
+        <attr name="android:showAsAction" />
+
+        <!-- An optional layout to be used as an action view.
+             See {@link android.view.MenuItem#setActionView(android.view.View)}
+             for more info. -->
+        <attr name="android:actionLayout" />
+
+        <!-- The name of an optional View class to instantiate and use as an
+             action view. See {@link android.view.MenuItem#setActionView(android.view.View)}
+             for more info. -->
+        <attr name="android:actionViewClass" />
+
+        <!-- The name of an optional ActionProvider class to instantiate an action view
+             and perform operations such as default action for that menu item.
+             See {@link android.view.MenuItem#setActionProvider(android.view.ActionProvider)}
+             for more info. -->
+        <attr name="android:actionProviderClass" />
+
+    </declare-styleable>
+
+    <declare-styleable name="SherlockSpinner">
+        <!-- The prompt to display when the spinner's dialog is shown. -->
+        <attr name="android:prompt" />
+        <!-- List selector to use for spinnerMode="dropdown" display. -->
+        <attr name="android:dropDownSelector" />
+        <!-- Background drawable to use for the dropdown in spinnerMode="dropdown". -->
+        <attr name="android:popupBackground" />
+        <!-- Vertical offset from the spinner widget for positioning the dropdown in
+             spinnerMode="dropdown". -->
+        <attr name="android:dropDownVerticalOffset" />
+        <!-- Horizontal offset from the spinner widget for positioning the dropdown
+             in spinnerMode="dropdown". -->
+        <attr name="android:dropDownHorizontalOffset" />
+        <!-- Width of the dropdown in spinnerMode="dropdown". -->
+        <attr name="android:dropDownWidth" />
+        <!-- Reference to a layout to use for displaying a prompt in the dropdown for
+             spinnerMode="dropdown". This layout must contain a TextView with the id
+             @android:id/text1 to be populated with the prompt text. -->
+        <attr name="android:popupPromptView" />
+        <!-- Gravity setting for positioning the currently selected item. -->
+        <attr name="android:gravity" />
+    </declare-styleable>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__bools.xml b/android-libraries/ActionBarSherlock/res/values/abs__bools.xml
new file mode 100644 (file)
index 0000000..0b43244
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <bool name="abs__action_bar_embed_tabs">false</bool>
+    <bool name="abs__split_action_bar_is_narrow">true</bool>
+    <bool name="abs__action_bar_expanded_action_views_exclusive">true</bool>
+    <!--bool name="target_honeycomb_needs_options_menu">true</bool-->
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__colors.xml b/android-libraries/ActionBarSherlock/res/values/abs__colors.xml
new file mode 100644 (file)
index 0000000..625c632
--- /dev/null
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <color name="abs__background_holo_dark">#ff000000</color>
+    <color name="abs__background_holo_light">#fff3f3f3</color>
+    <color name="abs__bright_foreground_holo_dark">@color/abs__background_holo_light</color>
+    <color name="abs__bright_foreground_holo_light">@color/abs__background_holo_dark</color>
+    <color name="abs__bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
+    <color name="abs__bright_foreground_disabled_holo_light">#ffb2b2b2</color>
+    <color name="abs__bright_foreground_inverse_holo_dark">@color/abs__bright_foreground_holo_light</color>
+    <color name="abs__bright_foreground_inverse_holo_light">@color/abs__bright_foreground_holo_dark</color>
+    <color name="abs__holo_blue_light">#ff33b5e5</color>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__config.xml b/android-libraries/ActionBarSherlock/res/values/abs__config.xml
new file mode 100644 (file)
index 0000000..4c7b5d4
--- /dev/null
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- The maximum width we would prefer dialogs to be.  0 if there is no
+         maximum (let them grow as large as the screen).  Actual values are
+         specified for -large and -xlarge configurations. -->
+    <dimen name="abs__config_prefDialogWidth">320dp</dimen>
+
+    <!-- Sets whether menu shortcuts should be displayed on panel menus when
+         a keyboard is present. -->
+    <bool name="abs__config_showMenuShortcutsWhenKeyboardPresent">false</bool>
+
+    <!-- Whether action menu items should be displayed in ALLCAPS or not.
+         Defaults to true. If this is not appropriate for specific locales
+         it should be disabled in that locale's resources. -->
+    <bool name="abs__config_actionMenuItemAllCaps">true</bool>
+
+    <!-- Whether action menu items should obey the "withText" showAsAction
+         flag. This may be set to false for situations where space is
+         extremely limited. -->
+    <bool name="abs__config_allowActionMenuItemTextWithIcon">false</bool>
+
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__dimens.xml b/android-libraries/ActionBarSherlock/res/values/abs__dimens.xml
new file mode 100644 (file)
index 0000000..0a40975
--- /dev/null
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/dimens.xml
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <!-- Default height of an action bar. -->
+    <dimen name="abs__action_bar_default_height">48dip</dimen>
+    <!-- Vertical padding around action bar icons. -->
+    <dimen name="abs__action_bar_icon_vertical_padding">8dip</dimen>
+    <!-- Text size for action bar titles -->
+    <dimen name="abs__action_bar_title_text_size">18dp</dimen>
+    <!-- Text size for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_text_size">14dp</dimen>
+    <!-- Top margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_top_margin">-3dp</dimen>
+    <!-- Bottom margin for action bar subtitles -->
+    <dimen name="abs__action_bar_subtitle_bottom_margin">5dip</dimen>
+    
+    <integer name="abs__max_action_buttons">2</integer>
+
+    <!-- Minimum width for an action button in the menu area of an action bar -->
+    <dimen name="abs__action_button_min_width">56dip</dimen>
+    
+    <!-- Dialog title height -->
+    <dimen name="abs__alert_dialog_title_height">64dip</dimen>
+    
+    <!-- The platform's desired minimum size for a dialog's width when it
+         is along the major axis (that is the screen is landscape).  This may
+         be either a fraction or a dimension. -->
+    <item type="dimen" name="abs__dialog_min_width_major">65%</item>
+    <!-- The platform's desired minimum size for a dialog's width when it
+         is along the minor axis (that is the screen is portrait).  This may
+         be either a fraction or a dimension. -->
+    <item type="dimen" name="abs__dialog_min_width_minor">95%</item>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__ids.xml b/android-libraries/ActionBarSherlock/res/values/abs__ids.xml
new file mode 100644 (file)
index 0000000..f9f5604
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+  <item type="id" name="abs__home" />
+  <item type="id" name="abs__up" />
+  <item type="id" name="abs__action_menu_divider" />
+  <item type="id" name="abs__action_menu_presenter" />
+  <item type="id" name="abs__progress_circular" />
+  <item type="id" name="abs__progress_horizontal" />
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__strings.xml b/android-libraries/ActionBarSherlock/res/values/abs__strings.xml
new file mode 100644 (file)
index 0000000..1e1c702
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Content description for the action bar "home" affordance. [CHAR LIMIT=NONE] -->
+    <string name="abs__action_bar_home_description">Navigate home</string>
+    <!-- Content description for the action bar "up" affordance. [CHAR LIMIT=NONE] -->
+    <string name="abs__action_bar_up_description">Navigate up</string>
+    <!-- Content description for the action menu overflow button. [CHAR LIMIT=NONE] -->
+    <string name="abs__action_menu_overflow_description">More options</string>
+
+    <!-- Label for the "Done" button on the far left of action mode toolbars. -->
+    <string name="abs__action_mode_done">Done</string>
+
+    <!-- Title for a button to expand the list of activities in ActivityChooserView [CHAR LIMIT=25] -->
+    <string name="abs__activity_chooser_view_see_all">See all...</string>
+    <!-- Title default for a dialog showing possible activities in ActivityChooserView [CHAR LIMIT=25] -->
+    <string name="abs__activity_chooser_view_dialog_title_default">Select activity</string>
+    <!-- Title for a dialog showing possible activities for sharing in ShareActionProvider [CHAR LIMIT=25] -->
+    <string name="abs__share_action_provider_share_with">Share with...</string>
+    <!-- Description of the shwoing of a popup window with activities to choose from. [CHAR LIMIT=NONE] -->
+    <string name="abs__activitychooserview_choose_application">Choose an application</string>
+    <!-- Description of the choose target button in a ShareActionProvider (share UI). [CHAR LIMIT=NONE] -->
+    <string name="abs__shareactionprovider_share_with">Share with</string>
+    <!-- Description of a share target (both in the list of such or the default share button) in a ShareActionProvider (share UI). [CHAR LIMIT=NONE] -->
+    <string name="abs__shareactionprovider_share_with_application">Share with <xliff:g id="application_name" example="Bluetooth">%s</xliff:g></string>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__styles.xml b/android-libraries/ActionBarSherlock/res/values/abs__styles.xml
new file mode 100644 (file)
index 0000000..8cbd364
--- /dev/null
@@ -0,0 +1,384 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+    <style name="Widget">
+    </style>
+
+    <style name="Sherlock.__Widget.ActionBar" parent="Widget">
+        <item name="displayOptions">useLogo|showHome|showTitle</item>
+        <item name="height">?attr/actionBarSize</item>
+        <item name="android:paddingLeft">0dip</item>
+        <item name="android:paddingTop">0dip</item>
+        <item name="android:paddingRight">0dip</item>
+        <item name="android:paddingBottom">0dip</item>
+        <item name="homeLayout">@layout/abs__action_bar_home</item>
+    </style>
+    <style name="Widget.Sherlock.ActionBar" parent="Sherlock.__Widget.ActionBar">
+        <item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Title</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Subtitle</item>
+        <item name="background">@drawable/abs__ab_transparent_dark_holo</item>
+        <item name="backgroundStacked">@drawable/abs__ab_stacked_transparent_dark_holo</item>
+        <item name="backgroundSplit">@drawable/abs__ab_bottom_transparent_dark_holo</item>
+        <item name="divider">?attr/dividerVertical</item>
+        <item name="progressBarStyle">@style/Widget.Sherlock.ProgressBar.Horizontal</item>
+        <item name="indeterminateProgressStyle">@style/Widget.Sherlock.ProgressBar</item>
+        <item name="progressBarPadding">32dip</item>
+        <item name="itemPadding">8dip</item>
+    </style>
+    <style name="Widget.Sherlock.ActionBar.Solid" parent="Sherlock.__Widget.ActionBar">
+        <item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Title</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Subtitle</item>
+        <item name="background">@drawable/abs__ab_solid_dark_holo</item>
+        <item name="backgroundStacked">@drawable/abs__ab_stacked_solid_dark_holo</item>
+        <item name="backgroundSplit">@drawable/abs__ab_bottom_solid_dark_holo</item>
+        <item name="divider">?attr/dividerVertical</item>
+        <item name="progressBarStyle">@style/Widget.Sherlock.ProgressBar.Horizontal</item>
+        <item name="indeterminateProgressStyle">@style/Widget.Sherlock.ProgressBar</item>
+        <item name="progressBarPadding">32dip</item>
+        <item name="itemPadding">8dip</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar" parent="Widget.Sherlock.ActionBar">
+        <item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Title</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Subtitle</item>
+        <item name="background">@drawable/abs__ab_transparent_light_holo</item>
+        <item name="backgroundStacked">@drawable/abs__ab_stacked_transparent_light_holo</item>
+        <item name="backgroundSplit">@drawable/abs__ab_bottom_transparent_light_holo</item>
+        <item name="homeAsUpIndicator">@drawable/abs__ic_ab_back_holo_light</item>
+        <item name="progressBarStyle">@style/Widget.Sherlock.Light.ProgressBar.Horizontal</item>
+        <item name="indeterminateProgressStyle">@style/Widget.Sherlock.Light.ProgressBar</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.Solid">
+        <item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Title</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Subtitle</item>
+        <item name="background">@drawable/abs__ab_solid_light_holo</item>
+        <item name="backgroundStacked">@drawable/abs__ab_stacked_solid_light_holo</item>
+        <item name="backgroundSplit">@drawable/abs__ab_bottom_solid_light_holo</item>
+        <item name="divider">?attr/dividerVertical</item>
+        <item name="progressBarStyle">@style/Widget.Sherlock.Light.ProgressBar.Horizontal</item>
+        <item name="indeterminateProgressStyle">@style/Widget.Sherlock.Light.ProgressBar</item>
+        <item name="progressBarPadding">32dip</item>
+        <item name="itemPadding">8dip</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.Solid.Inverse">
+        <item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Title.Inverse</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionBar.Subtitle.Inverse</item>
+        <item name="background">@drawable/abs__ab_solid_dark_holo</item>
+        <item name="backgroundStacked">@drawable/abs__ab_stacked_solid_dark_holo</item>
+        <item name="backgroundSplit">@drawable/abs__ab_bottom_solid_inverse_holo</item>
+        <item name="divider">@drawable/abs__list_divider_holo_dark</item>
+        <item name="progressBarStyle">@style/Widget.Sherlock.ProgressBar.Horizontal</item>
+        <item name="indeterminateProgressStyle">@style/Widget.Sherlock.ProgressBar</item>
+        <item name="progressBarPadding">32dip</item>
+        <item name="itemPadding">8dip</item>
+    </style>
+
+    <style name="Widget.Sherlock.ActionBar.TabView" parent="Widget">
+        <item name="android:gravity">center_horizontal</item>
+        <item name="android:background">@drawable/abs__tab_indicator_ab_holo</item>
+        <item name="android:paddingLeft">16dip</item>
+        <item name="android:paddingRight">16dip</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabView" parent="Widget.Sherlock.ActionBar.TabView">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabView.Inverse">
+    </style>
+
+    <style name="Widget.Sherlock.ActionBar.TabBar" parent="Widget">
+        <item name="android:divider">?attr/actionBarDivider</item>
+        <item name="android:showDividers">middle</item>
+        <item name="android:dividerPadding">12dip</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabBar" parent="Widget.Sherlock.ActionBar.TabBar">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabBar.Inverse">
+    </style>
+
+    <style name="Widget.Sherlock.ActionBar.TabText" parent="Widget">
+        <item name="android:textAppearance">@null</item>
+        <item name="android:textColor">?attr/textColorPrimary</item>
+        <item name="android:textSize">12sp</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textAllCaps">true</item>
+        <item name="android:ellipsize">marquee</item>
+        <item name="android:maxLines">2</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabText" parent="Widget.Sherlock.ActionBar.TabText">
+    </style>
+    <style name="Widget.Sherlock.Light.ActionBar.TabText.Inverse">
+        <item name="android:textColor">?attr/textColorPrimaryInverse</item>
+    </style>
+
+    <style name="Widget.Sherlock.ActionButton" parent="Widget">
+        <item name="android:background">?attr/actionBarItemBackground</item>
+        <item name="android:minHeight">?attr/actionBarSize</item>
+
+        <item name="android:minWidth">@dimen/abs__action_button_min_width</item>
+        <item name="android:gravity">center</item>
+        <item name="android:paddingLeft">12dip</item>
+        <item name="android:paddingRight">12dip</item>
+        <item name="android:scaleType">center</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionButton" parent="Widget.Sherlock.ActionButton">
+    </style>
+
+    <style name="Widget.Sherlock.ActionButton.CloseMode">
+        <item name="android:background">@drawable/abs__btn_cab_done_holo_dark</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionButton.CloseMode">
+        <item name="android:background">@drawable/abs__btn_cab_done_holo_light</item>
+    </style>
+
+    <style name="Widget.Sherlock.ActionButton.Overflow">
+        <item name="android:src">@drawable/abs__ic_menu_moreoverflow_holo_dark</item>
+        <item name="android:background">?attr/actionBarItemBackground</item>
+        <item name="android:contentDescription">@string/abs__action_menu_overflow_description</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionButton.Overflow">
+        <item name="android:src">@drawable/abs__ic_menu_moreoverflow_holo_light</item>
+    </style>
+
+    <style name="Sherlock.__Widget.ActionMode" parent="Widget">
+        <item name="background">?attr/actionModeBackground</item>
+        <item name="backgroundSplit">?attr/actionModeSplitBackground</item>
+        <item name="height">?attr/actionBarSize</item>
+    </style>
+    <style name="Widget.Sherlock.ActionMode" parent="Sherlock.__Widget.ActionMode">
+        <item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionMode.Title</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionMode.Subtitle</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionMode" parent="Widget.Sherlock.ActionMode">
+        <item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionMode.Title</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionMode.Subtitle</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ActionMode.Inverse" parent="Sherlock.__Widget.ActionMode">
+        <item name="titleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionMode.Title.Inverse</item>
+        <item name="subtitleTextStyle">@style/TextAppearance.Sherlock.Widget.ActionMode.Subtitle.Inverse</item>
+    </style>
+
+
+    <style name="Widget.Sherlock.ListPopupWindow" parent="Widget">
+        <item name="android:dropDownSelector">@drawable/abs__list_selector_holo_dark</item>
+        <item name="android:popupBackground">@drawable/abs__menu_dropdown_panel_holo_dark</item>
+        <item name="android:dropDownVerticalOffset">0dip</item>
+        <item name="android:dropDownHorizontalOffset">0dip</item>
+        <item name="android:dropDownWidth">wrap_content</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ListPopupWindow" parent="Widget">
+        <item name="android:dropDownSelector">@drawable/abs__list_selector_holo_light</item>
+        <item name="android:popupBackground">@drawable/abs__menu_dropdown_panel_holo_light</item>
+        <item name="android:dropDownVerticalOffset">0dip</item>
+        <item name="android:dropDownHorizontalOffset">0dip</item>
+        <item name="android:dropDownWidth">wrap_content</item>
+    </style>
+    <style name="Widget.Sherlock.PopupMenu" parent="Widget.Sherlock.ListPopupWindow">
+    </style>
+    <style name="Widget.Sherlock.Light.PopupMenu" parent="Widget.Sherlock.Light.ListPopupWindow">
+    </style>
+
+
+    <style name="Sherlock.__Widget.ActivityChooserView" parent="Widget">
+        <item name="android:gravity">center</item>
+        <item name="android:background">@drawable/abs__ab_share_pack_holo_dark</item>
+        <item name="android:divider">?attr/dividerVertical</item>
+        <item name="android:showDividers">middle</item>
+        <item name="android:dividerPadding">6dip</item>
+    </style>
+    <style name="Widget.Sherlock.ActivityChooserView" parent="Sherlock.__Widget.ActivityChooserView">
+    </style>
+    <style name="Widget.Sherlock.Light.ActivityChooserView" parent="Widget.Sherlock.ActivityChooserView">
+        <item name="android:background">@drawable/abs__ab_share_pack_holo_light</item>
+    </style>
+
+    <style name="Widget.Sherlock.Button.Small" parent="Widget">
+      <item name="android:textAppearance">?attr/textAppearanceSmall</item>
+      <item name="android:textColor">@color/abs__primary_text_holo_dark</item>
+      <item name="android:minHeight">48dip</item>
+      <item name="android:minWidth">48dip</item>
+    </style>
+    <style name="Widget.Sherlock.Light.Button.Small" parent="Widget">
+      <item name="android:textAppearance">?attr/textAppearanceSmall</item>
+      <item name="android:textColor">@color/abs__primary_text_holo_light</item>
+      <item name="android:minHeight">48dip</item>
+      <item name="android:minWidth">48dip</item>
+    </style>
+
+
+    <style name="Sherlock.__Widget.Holo.Spinner" parent="Widget">
+        <item name="android:dropDownSelector">@drawable/abs__list_selector_holo_dark</item>
+        <item name="android:popupBackground">@drawable/abs__menu_dropdown_panel_holo_dark</item>
+        <item name="android:dropDownVerticalOffset">0dip</item>
+        <item name="android:dropDownHorizontalOffset">0dip</item>
+        <item name="android:dropDownWidth">wrap_content</item>
+        <item name="android:gravity">left|center_vertical</item>
+        <item name="android:spinnerMode">dropdown</item>
+        <item name="android:clickable">true</item>
+    </style>
+    <style name="Widget.Sherlock.Spinner.DropDown.ActionBar" parent="Sherlock.__Widget.Holo.Spinner">
+        <item name="android:background">@drawable/abs__spinner_ab_holo_dark</item>
+    </style>
+    <style name="Widget.Sherlock.Light.Spinner.DropDown.ActionBar" parent="Sherlock.__Widget.Holo.Spinner">
+        <item name="android:background">@drawable/abs__spinner_ab_holo_light</item>
+        <item name="android:dropDownSelector">@drawable/abs__list_selector_holo_light</item>
+        <item name="android:popupBackground">@drawable/abs__menu_dropdown_panel_holo_light</item>
+    </style>
+
+    <style name="Sherlock.__Widget.Holo.ListView" parent="android:Widget.ListView">
+        <item name="android:divider">@drawable/abs__list_divider_holo_dark</item>
+        <item name="android:listSelector">@drawable/abs__list_selector_holo_dark</item>
+    </style>
+    <style name="Widget.Sherlock.ListView.DropDown" parent="Sherlock.__Widget.Holo.ListView">
+    </style>
+    <style name="Widget.Sherlock.Light.ListView.DropDown" parent="Sherlock.__Widget.Holo.ListView">
+        <item name="android:divider">@drawable/abs__list_divider_holo_light</item>
+        <item name="android:listSelector">@drawable/abs__list_selector_holo_light</item>
+    </style>
+
+    <style name="Sherlock.__Widget.Holo.DropDownItem" parent="Widget">
+        <item name="android:textAppearance">@style/TextAppearance.Sherlock.Widget.DropDownItem</item>
+        <item name="android:paddingLeft">8dp</item>
+        <item name="android:paddingRight">8dp</item>
+        <item name="android:gravity">center_vertical</item>
+    </style>
+    <style name="Widget.Sherlock.DropDownItem.Spinner" parent="Sherlock.__Widget.Holo.DropDownItem">
+    </style>
+    <style name="Widget.Sherlock.Light.DropDownItem.Spinner" parent="Sherlock.__Widget.Holo.DropDownItem">
+    </style>
+
+    <style name="Widget.Sherlock.PopupWindow.ActionMode" parent="Widget">
+    </style>
+    <style name="Widget.Sherlock.Light.PopupWindow.ActionMode" parent="Widget">
+        <item name="android:popupBackground">@android:color/white</item>
+    </style>
+
+
+
+    <style name="Widget.Sherlock.ProgressBar" parent="android:Widget.ProgressBar">
+        <item name="android:indeterminateDrawable">@drawable/abs__progress_medium_holo</item>
+        <item name="android:animationResolution">33</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ProgressBar" parent="Widget.Sherlock.ProgressBar">
+    </style>
+
+    <style name="Widget.Sherlock.ProgressBar.Horizontal" parent="android:Widget.ProgressBar.Horizontal">
+        <item name="android:progressDrawable">@drawable/abs__progress_horizontal_holo_dark</item>
+        <!--item name="android:indeterminateDrawable">@drawable/abs__progress_indeterminate_horizontal_holo</item-->
+        <item name="android:minHeight">16dip</item>
+        <item name="android:maxHeight">16dip</item>
+    </style>
+    <style name="Widget.Sherlock.Light.ProgressBar.Horizontal" parent="Widget.Sherlock.ProgressBar.Horizontal">
+        <item name="android:progressDrawable">@drawable/abs__progress_horizontal_holo_light</item>
+    </style>
+
+
+
+    <style name="Widget.Sherlock.TextView.SpinnerItem" parent="Widget">
+        <item name="android:textAppearance">@style/TextAppearance.Sherlock.Widget.TextView.SpinnerItem</item>
+        <item name="android:paddingLeft">8dp</item>
+        <item name="android:paddingRight">8dp</item>
+    </style>
+
+
+
+    <style name="DialogWindowTitle.Sherlock" parent="Widget">
+        <item name="android:maxLines">1</item>
+        <item name="android:scrollHorizontally">true</item>
+        <item name="android:textAppearance">@style/TextAppearance.Sherlock.DialogWindowTitle</item>
+        <item name="android:minHeight">@dimen/abs__alert_dialog_title_height</item>
+        <item name="android:paddingLeft">16dip</item>
+        <item name="android:paddingRight">16dip</item>
+    </style>
+    <style name="DialogWindowTitle.Sherlock.Light" parent="Widget">
+        <item name="android:maxLines">1</item>
+        <item name="android:scrollHorizontally">true</item>
+        <item name="android:textAppearance">@style/TextAppearance.Sherlock.Light.DialogWindowTitle</item>
+        <item name="android:minHeight">@dimen/abs__alert_dialog_title_height</item>
+        <item name="android:paddingLeft">16dip</item>
+        <item name="android:paddingRight">16dip</item>
+    </style>
+
+
+
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Menu" parent="Widget">
+        <item name="android:textSize">12sp</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textColor">?attr/actionMenuTextColor</item>
+        <item name="android:textAllCaps">@bool/abs__config_actionMenuItemAllCaps</item>
+    </style>
+
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Title" parent="Widget">
+        <item name="android:textSize">@dimen/abs__action_bar_title_text_size</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Title.Inverse" parent="Widget">
+        <item name="android:textSize">@dimen/abs__action_bar_title_text_size</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Subtitle" parent="Widget">
+        <item name="android:textSize">@dimen/abs__action_bar_subtitle_text_size</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionBar.Subtitle.Inverse" parent="Widget">
+        <item name="android:textSize">@dimen/abs__action_bar_subtitle_text_size</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionMode.Title" parent="Widget">
+        <item name="android:textSize">@dimen/abs__action_bar_title_text_size</item>
+        <item name="android:textColor">?android:attr/textColorPrimary</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionMode.Title.Inverse" parent="Widget">
+        <item name="android:textSize">@dimen/abs__action_bar_title_text_size</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionMode.Subtitle" parent="Widget">
+        <item name="android:textSize">@dimen/abs__action_bar_subtitle_text_size</item>
+        <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.ActionMode.Subtitle.Inverse" parent="Widget">
+        <item name="android:textSize">@dimen/abs__action_bar_subtitle_text_size</item>
+        <item name="android:textColor">?android:attr/textColorPrimaryInverse</item>
+    </style>
+
+    <style name="TextAppearance.Sherlock.Widget.PopupMenu" parent="Widget">
+        <item name="android:textColor">?attr/textColorPrimary</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.PopupMenu.Large">
+        <item name="android:textSize">18sp</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Light.Widget.PopupMenu.Large" parent="TextAppearance.Sherlock.Widget.PopupMenu.Large">
+    </style>
+    <style name="TextAppearance.Sherlock.Widget.PopupMenu.Small">
+        <item name="android:textSize">14sp</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Light.Widget.PopupMenu.Small" parent="TextAppearance.Sherlock.Widget.PopupMenu.Small">
+    </style>
+
+    <style name="TextAppearance.Sherlock.Widget.TextView.SpinnerItem" parent="Widget">
+        <item name="android:textColor">?textColorPrimary</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+
+    <style name="TextAppearance.Sherlock.Widget.DropDownItem" parent="Widget">
+        <item name="android:textColor">?textColorPrimaryDisableOnly</item>
+        <item name="android:textSize">16sp</item>
+        <item name="android:textStyle">normal</item>
+    </style>
+
+    <style name="TextAppearance.Sherlock.DialogWindowTitle" parent="Widget">
+        <item name="android:textSize">22sp</item>
+        <item name="android:textColor">@color/abs__holo_blue_light</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Light.DialogWindowTitle" parent="Widget">
+        <item name="android:textSize">22sp</item>
+        <item name="android:textColor">@color/abs__holo_blue_light</item>
+    </style>
+
+    <style name="Sherlock.__TextAppearance.Small" parent="Widget">
+      <item name="android:textSize">14sp</item>
+      <item name="android:textColor">?android:attr/textColorSecondary</item>
+    </style>
+    <style name="TextAppearance.Sherlock.Small" parent="Sherlock.__TextAppearance.Small">
+    </style>
+    <style name="TextAppearance.Sherlock.Light.Small" parent="TextAppearance.Sherlock.Small">
+    </style>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/abs__themes.xml b/android-libraries/ActionBarSherlock/res/values/abs__themes.xml
new file mode 100644 (file)
index 0000000..5300ded
--- /dev/null
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+    <style name="Sherlock.__Theme" parent="android:Theme.NoTitleBar">
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+    <style name="Sherlock.__Theme.Light" parent="android:Theme.Light.NoTitleBar">
+        <item name="android:windowContentOverlay">@null</item>
+    </style>
+    <style name="Sherlock.__Theme.DarkActionBar" parent="Theme.Sherlock.Light">
+    </style>
+    <style name="Sherlock.__Theme.Dialog" parent="android:Theme.Dialog">
+    </style>
+    
+    <style name="Theme.Sherlock" parent="Sherlock.__Theme">
+        <!-- Action bar styles (from Theme.Holo) -->
+        <item name="actionDropDownStyle">@style/Widget.Sherlock.Spinner.DropDown.ActionBar</item>
+        <item name="actionButtonStyle">@style/Widget.Sherlock.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@style/Widget.Sherlock.ActionButton.Overflow</item>
+        <item name="actionModeBackground">@drawable/abs__cab_background_top_holo_dark</item>
+        <item name="actionModeSplitBackground">@drawable/abs__cab_background_bottom_holo_dark</item>
+        <item name="actionModeCloseDrawable">@drawable/abs__ic_cab_done_holo_dark</item>
+        <item name="actionBarTabStyle">@style/Widget.Sherlock.ActionBar.TabView</item>
+        <item name="actionBarTabBarStyle">@style/Widget.Sherlock.ActionBar.TabBar</item>
+        <item name="actionBarTabTextStyle">@style/Widget.Sherlock.ActionBar.TabText</item>
+        <item name="actionModeStyle">@style/Widget.Sherlock.ActionMode</item>
+        <item name="actionModeCloseButtonStyle">@style/Widget.Sherlock.ActionButton.CloseMode</item>
+        <item name="actionBarStyle">@style/Widget.Sherlock.ActionBar</item>
+        <item name="actionBarSize">@dimen/abs__action_bar_default_height</item>
+        <!-- Internal --><item name="actionModePopupWindowStyle">@style/Widget.Sherlock.PopupWindow.ActionMode</item>
+        <item name="actionBarWidgetTheme">@null</item>
+        
+        <!-- Action bar styles (defaults from Theme) -->
+        <item name="actionBarSplitStyle">?attr/actionBarStyle</item>
+        <item name="actionMenuTextAppearance">@style/TextAppearance.Sherlock.Widget.ActionBar.Menu</item>
+        <item name="actionMenuTextColor">?attr/textColorPrimary</item>
+        <item name="actionBarDivider">?attr/dividerVertical</item>
+        <item name="actionBarItemBackground">@drawable/abs__item_background_holo_dark</item>
+
+        <item name="buttonStyleSmall">@style/Widget.Sherlock.Button.Small</item>
+        
+        <item name="activatedBackgroundIndicator">@drawable/abs__activated_background_holo_dark</item>
+        <item name="actionModeShareDrawable">@drawable/abs__ic_menu_share_holo_dark</item>
+        <item name="activityChooserViewStyle">@style/Widget.Sherlock.ActivityChooserView</item>
+        
+        <item name="homeAsUpIndicator">@drawable/abs__ic_ab_back_holo_dark</item>
+        
+        <item name="dividerVertical">@drawable/abs__list_divider_holo_dark</item>
+        
+        <item name="spinnerDropDownItemStyle">@style/Widget.Sherlock.DropDownItem.Spinner</item>
+        <item name="spinnerItemStyle">@style/Widget.Sherlock.TextView.SpinnerItem</item>
+        
+        <item name="textColorPrimary">@color/abs__primary_text_holo_dark</item>
+        <item name="textColorPrimaryDisableOnly">@color/abs__primary_text_disable_only_holo_dark</item>
+        <item name="textColorPrimaryInverse">@color/abs__primary_text_holo_light</item>
+        
+        <!-- Internal --><item name="dropdownListPreferredItemHeight">48dip</item>
+        <item name="dropDownListViewStyle">@style/Widget.Sherlock.ListView.DropDown</item>
+
+        <item name="textAppearanceSmall">@style/TextAppearance.Sherlock.Small</item>
+        <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Sherlock.Widget.PopupMenu.Large</item>
+        <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Sherlock.Widget.PopupMenu.Small</item>
+        
+        <item name="popupMenuStyle">@style/Widget.Sherlock.PopupMenu</item>
+        <!-- Internal --><item name="listPopupWindowStyle">@style/Widget.Sherlock.ListPopupWindow</item>
+        
+        <item name="windowActionBar">true</item>
+        <item name="windowActionModeOverlay">false</item>
+        <item name="windowContentOverlay">@null</item>
+    </style>
+    <style name="Theme.Sherlock.Light" parent="Sherlock.__Theme.Light">
+        <!-- Action bar styles (from Theme.Holo) -->
+        <item name="actionDropDownStyle">@style/Widget.Sherlock.Light.Spinner.DropDown.ActionBar</item>
+        <item name="actionButtonStyle">@style/Widget.Sherlock.Light.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@style/Widget.Sherlock.Light.ActionButton.Overflow</item>
+        <item name="actionModeBackground">@drawable/abs__cab_background_top_holo_light</item>
+        <item name="actionModeSplitBackground">@drawable/abs__cab_background_bottom_holo_light</item>
+        <item name="actionModeCloseDrawable">@drawable/abs__ic_cab_done_holo_light</item>
+        <item name="actionBarTabStyle">@style/Widget.Sherlock.Light.ActionBar.TabView</item>
+        <item name="actionBarTabBarStyle">@style/Widget.Sherlock.Light.ActionBar.TabBar</item>
+        <item name="actionBarTabTextStyle">@style/Widget.Sherlock.Light.ActionBar.TabText</item>
+        <item name="actionModeStyle">@style/Widget.Sherlock.Light.ActionMode</item>
+        <item name="actionModeCloseButtonStyle">@style/Widget.Sherlock.Light.ActionButton.CloseMode</item>
+        <item name="actionBarStyle">@style/Widget.Sherlock.Light.ActionBar.Solid</item>
+        <item name="actionBarSize">@dimen/abs__action_bar_default_height</item>
+        <!-- Internal --><item name="actionModePopupWindowStyle">@style/Widget.Sherlock.Light.PopupWindow.ActionMode</item>
+        <item name="actionBarWidgetTheme">@null</item>
+        
+        <!-- Action bar styles (defaults from Theme) -->
+        <item name="actionBarSplitStyle">?attr/actionBarStyle</item>
+        <item name="actionMenuTextAppearance">@style/TextAppearance.Sherlock.Widget.ActionBar.Menu</item>
+        <item name="actionMenuTextColor">?attr/textColorPrimary</item>
+        <item name="actionBarDivider">?attr/dividerVertical</item>
+        <item name="actionBarItemBackground">@drawable/abs__item_background_holo_light</item>
+
+        <item name="buttonStyleSmall">@style/Widget.Sherlock.Light.Button.Small</item>
+        
+        <item name="activatedBackgroundIndicator">@drawable/abs__activated_background_holo_light</item>
+        <item name="actionModeShareDrawable">@drawable/abs__ic_menu_share_holo_light</item>
+        <item name="activityChooserViewStyle">@style/Widget.Sherlock.Light.ActivityChooserView</item>
+        
+        <item name="homeAsUpIndicator">@drawable/abs__ic_ab_back_holo_light</item>
+        
+        <item name="dividerVertical">@drawable/abs__list_divider_holo_light</item>
+        
+        <item name="spinnerDropDownItemStyle">@style/Widget.Sherlock.Light.DropDownItem.Spinner</item>
+        <item name="spinnerItemStyle">@style/Widget.Sherlock.TextView.SpinnerItem</item>
+        
+        <item name="textColorPrimary">@color/abs__primary_text_holo_light</item>
+        <item name="textColorPrimaryDisableOnly">@color/abs__primary_text_disable_only_holo_light</item>
+        <item name="textColorPrimaryInverse">@color/abs__primary_text_holo_dark</item>
+        
+        <!-- Internal --><item name="dropdownListPreferredItemHeight">48dip</item>
+        <item name="dropDownListViewStyle">@style/Widget.Sherlock.Light.ListView.DropDown</item>
+
+        <item name="textAppearanceSmall">@style/TextAppearance.Sherlock.Light.Small</item>
+        <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Sherlock.Light.Widget.PopupMenu.Large</item>
+        <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Sherlock.Light.Widget.PopupMenu.Small</item>
+        
+        <item name="popupMenuStyle">@style/Widget.Sherlock.Light.PopupMenu</item>
+        <!-- Internal --><item name="listPopupWindowStyle">@style/Widget.Sherlock.Light.ListPopupWindow</item>
+        
+        <item name="windowActionBar">true</item>
+        <item name="windowActionModeOverlay">false</item>
+        <item name="windowContentOverlay">@null</item>
+    </style>
+    <style name="Theme.Sherlock.Light.DarkActionBar" parent="Sherlock.__Theme.DarkActionBar">
+        <item name="windowContentOverlay">@drawable/abs__ab_solid_shadow_holo</item>
+        <item name="actionBarStyle">@style/Widget.Sherlock.Light.ActionBar.Solid.Inverse</item>
+        <item name="actionBarWidgetTheme">@style/Theme.Sherlock</item>
+
+        <item name="actionDropDownStyle">@style/Widget.Sherlock.Spinner.DropDown.ActionBar</item>
+        <item name="actionButtonStyle">@style/Widget.Sherlock.ActionButton</item>
+        <item name="actionOverflowButtonStyle">@style/Widget.Sherlock.ActionButton.Overflow</item>
+        <item name="actionModeBackground">@drawable/abs__cab_background_top_holo_dark</item>
+        <item name="actionModeSplitBackground">@drawable/abs__cab_background_bottom_holo_dark</item>
+        <item name="actionModeCloseDrawable">@drawable/abs__ic_cab_done_holo_dark</item>
+        <item name="homeAsUpIndicator">@drawable/abs__ic_ab_back_holo_dark</item>
+        <item name="actionBarTabStyle">@style/Widget.Sherlock.Light.ActionBar.TabView.Inverse</item>
+        <item name="actionBarTabBarStyle">@style/Widget.Sherlock.Light.ActionBar.TabBar.Inverse</item>
+        <item name="actionBarTabTextStyle">@style/Widget.Sherlock.Light.ActionBar.TabText.Inverse</item>
+        <item name="actionBarDivider">@drawable/abs__list_divider_holo_dark</item>
+        <item name="actionBarItemBackground">@drawable/abs__item_background_holo_dark</item>
+        <item name="actionMenuTextColor">?attr/textColorPrimaryInverse</item>
+        <item name="actionModeStyle">@style/Widget.Sherlock.Light.ActionMode.Inverse</item>
+        <item name="actionModeCloseButtonStyle">@style/Widget.Sherlock.ActionButton.CloseMode</item>
+        <item name="actionModePopupWindowStyle">@style/Widget.Sherlock.PopupWindow.ActionMode</item>
+        
+        <item name="actionModeShareDrawable">@drawable/abs__ic_menu_share_holo_dark</item>
+    </style>
+    
+    
+    <style name="Theme.Sherlock.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+    <style name="Theme.Sherlock.Light.NoActionBar">
+        <item name="windowActionBar">false</item>
+        <item name="windowNoTitle">true</item>
+    </style>
+    
+    
+    <style name="Theme.Sherlock.ForceOverflow">
+        <item name="absForceOverflow">true</item>
+    </style>
+    <style name="Theme.Sherlock.Light.ForceOverflow">
+        <item name="absForceOverflow">true</item>
+    </style>
+    <style name="Theme.Sherlock.Light.DarkActionBar.ForceOverflow">
+        <item name="absForceOverflow">true</item>
+    </style>
+    
+    
+    <style name="Theme.Sherlock.Dialog" parent="android:Theme">
+        <item name="android:windowFrame">@null</item>
+        <item name="android:windowTitleStyle">@style/DialogWindowTitle.Sherlock</item>
+        <item name="android:windowBackground">@drawable/abs__dialog_full_holo_dark</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+        <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
+        
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowActionModeOverlay">true</item>
+        <item name="android:windowCloseOnTouchOutside">true</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:backgroundDimAmount">0.6</item>
+        
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        
+        <item name="android:textColorPrimary">@color/abs__primary_text_holo_dark</item>
+        <item name="android:textColorPrimaryInverse">@color/abs__primary_text_holo_light</item>
+        
+        <item name="windowMinWidthMajor">@dimen/abs__dialog_min_width_major</item>
+        <item name="windowMinWidthMinor">@dimen/abs__dialog_min_width_minor</item>
+        
+        <item name="windowActionBar">false</item>
+        <item name="windowContentOverlay">@null</item>
+    </style>
+    <style name="Theme.Sherlock.Light.Dialog" parent="android:Theme.Light">
+        <item name="android:windowFrame">@null</item>
+        <item name="android:windowTitleStyle">@style/DialogWindowTitle.Sherlock.Light</item>
+        <item name="android:windowBackground">@drawable/abs__dialog_full_holo_light</item>
+        <item name="android:windowIsFloating">true</item>
+        <item name="android:windowContentOverlay">@null</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
+        <item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
+        
+        <item name="android:windowActionBar">false</item>
+        <item name="android:windowActionModeOverlay">true</item>
+        <item name="android:windowCloseOnTouchOutside">true</item>
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:backgroundDimAmount">0.6</item>
+        
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        
+        <item name="android:textColorPrimary">@color/abs__primary_text_holo_light</item>
+        <item name="android:textColorPrimaryInverse">@color/abs__primary_text_holo_dark</item>
+        
+        <item name="windowMinWidthMajor">@dimen/abs__dialog_min_width_major</item>
+        <item name="windowMinWidthMinor">@dimen/abs__dialog_min_width_minor</item>
+        
+        <item name="windowActionBar">false</item>
+        <item name="windowContentOverlay">@null</item>
+    </style>
+</resources>
diff --git a/android-libraries/ActionBarSherlock/res/values/strings.xml b/android-libraries/ActionBarSherlock/res/values/strings.xml
new file mode 100644 (file)
index 0000000..43d1652
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<resources>\r
+\r
+    <string name="hello">Hello World!</string>\r
+    <string name="app_name">ActionBarSherlock</string>\r
+\r
+</resources>
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/src/android/support/v4/app/_ActionBarSherlockTrojanHorse.java b/android-libraries/ActionBarSherlock/src/android/support/v4/app/_ActionBarSherlockTrojanHorse.java
new file mode 100644 (file)
index 0000000..3e3db62
--- /dev/null
@@ -0,0 +1,144 @@
+package android.support.v4.app;
+
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
+import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
+import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+
+import java.util.ArrayList;
+
+/** I'm in ur package. Stealing ur variables. */
+public abstract class _ActionBarSherlockTrojanHorse extends FragmentActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "_ActionBarSherlockTrojanHorse";
+
+    /** Fragment interface for menu creation callback. */
+    public interface OnCreateOptionsMenuListener {
+        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater);
+    }
+    /** Fragment interface for menu preparation callback. */
+    public interface OnPrepareOptionsMenuListener {
+        public void onPrepareOptionsMenu(Menu menu);
+    }
+    /** Fragment interface for menu item selection callback. */
+    public interface OnOptionsItemSelectedListener {
+      public boolean onOptionsItemSelected(MenuItem item);
+    }
+
+    private ArrayList<Fragment> mCreatedMenus;
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Sherlock menu handling
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {
+        if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] featureId: " + featureId + ", menu: " + menu);
+
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {
+            boolean result = onCreateOptionsMenu(menu);
+            if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] activity create result: " + result);
+
+            MenuInflater inflater = getSupportMenuInflater();
+            boolean show = false;
+            ArrayList<Fragment> newMenus = null;
+            if (mFragments.mActive != null) {
+                for (int i = 0; i < mFragments.mAdded.size(); i++) {
+                    Fragment f = mFragments.mAdded.get(i);
+                    if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnCreateOptionsMenuListener) {
+                        show = true;
+                        ((OnCreateOptionsMenuListener)f).onCreateOptionsMenu(menu, inflater);
+                        if (newMenus == null) {
+                            newMenus = new ArrayList<Fragment>();
+                        }
+                        newMenus.add(f);
+                    }
+                }
+            }
+
+            if (mCreatedMenus != null) {
+                for (int i = 0; i < mCreatedMenus.size(); i++) {
+                    Fragment f = mCreatedMenus.get(i);
+                    if (newMenus == null || !newMenus.contains(f)) {
+                        f.onDestroyOptionsMenu();
+                    }
+                }
+            }
+
+            mCreatedMenus = newMenus;
+
+            if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] fragments create result: " + show);
+            result |= show;
+
+            if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result);
+            return result;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onPreparePanel(int featureId, View view, Menu menu) {
+        if (DEBUG) Log.d(TAG, "[onPreparePanel] featureId: " + featureId + ", view: " + view + " menu: " + menu);
+
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {
+            boolean result = onPrepareOptionsMenu(menu);
+            if (DEBUG) Log.d(TAG, "[onPreparePanel] activity prepare result: " + result);
+
+            boolean show = false;
+            if (mFragments.mActive != null) {
+                for (int i = 0; i < mFragments.mAdded.size(); i++) {
+                    Fragment f = mFragments.mAdded.get(i);
+                    if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnPrepareOptionsMenuListener) {
+                        show = true;
+                        ((OnPrepareOptionsMenuListener)f).onPrepareOptionsMenu(menu);
+                    }
+                }
+            }
+
+            if (DEBUG) Log.d(TAG, "[onPreparePanel] fragments prepare result: " + show);
+            result |= show;
+
+            result &= menu.hasVisibleItems();
+            if (DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result);
+            return result;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        if (DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item);
+
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {
+            if (onOptionsItemSelected(item)) {
+                return true;
+            }
+
+            if (mFragments.mActive != null) {
+                for (int i = 0; i < mFragments.mAdded.size(); i++) {
+                    Fragment f = mFragments.mAdded.get(i);
+                    if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnOptionsItemSelectedListener) {
+                        if (((OnOptionsItemSelectedListener)f).onOptionsItemSelected(item)) {
+                            return true;
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    public abstract boolean onCreateOptionsMenu(Menu menu);
+
+    public abstract boolean onPrepareOptionsMenu(Menu menu);
+
+    public abstract boolean onOptionsItemSelected(MenuItem item);
+
+    public abstract MenuInflater getSupportMenuInflater();
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/ActionBarSherlock.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/ActionBarSherlock.java
new file mode 100644 (file)
index 0000000..8340fb5
--- /dev/null
@@ -0,0 +1,791 @@
+package com.actionbarsherlock;\r
+\r
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;\r
+import java.lang.annotation.ElementType;\r
+import java.lang.annotation.Retention;\r
+import java.lang.annotation.RetentionPolicy;\r
+import java.lang.annotation.Target;\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.InvocationTargetException;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import android.app.Activity;\r
+import android.content.Context;\r
+import android.content.res.Configuration;\r
+import android.os.Build;\r
+import android.os.Bundle;\r
+import android.util.DisplayMetrics;\r
+import android.util.Log;\r
+import android.view.KeyEvent;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.view.Window;\r
+import com.actionbarsherlock.app.ActionBar;\r
+import com.actionbarsherlock.internal.ActionBarSherlockCompat;\r
+import com.actionbarsherlock.internal.ActionBarSherlockNative;\r
+import com.actionbarsherlock.view.ActionMode;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+/**\r
+ * <p>Helper for implementing the action bar design pattern across all versions\r
+ * of Android.</p>\r
+ *\r
+ * <p>This class will manage interaction with a custom action bar based on the\r
+ * Android 4.0 source code. The exposed API mirrors that of its native\r
+ * counterpart and you should refer to its documentation for instruction.</p>\r
+ *\r
+ * @author Jake Wharton <jakewharton@gmail.com>\r
+ */\r
+public abstract class ActionBarSherlock {\r
+    protected static final String TAG = "ActionBarSherlock";\r
+    protected static final boolean DEBUG = false;\r
+\r
+    private static final Class<?>[] CONSTRUCTOR_ARGS = new Class[] { Activity.class, int.class };\r
+    private static final HashMap<Implementation, Class<? extends ActionBarSherlock>> IMPLEMENTATIONS =\r
+            new HashMap<Implementation, Class<? extends ActionBarSherlock>>();\r
+\r
+    static {\r
+        //Register our two built-in implementations\r
+        registerImplementation(ActionBarSherlockCompat.class);\r
+        registerImplementation(ActionBarSherlockNative.class);\r
+    }\r
+\r
+\r
+    /**\r
+     * <p>Denotes an implementation of ActionBarSherlock which provides an\r
+     * action bar-enhanced experience.</p>\r
+     */\r
+    @Target(ElementType.TYPE)\r
+    @Retention(RetentionPolicy.RUNTIME)\r
+    public @interface Implementation {\r
+        static final int DEFAULT_API = -1;\r
+        static final int DEFAULT_DPI = -1;\r
+\r
+        int api() default DEFAULT_API;\r
+        int dpi() default DEFAULT_DPI;\r
+    }\r
+\r
+\r
+    /** Activity interface for menu creation callback. */\r
+    public interface OnCreatePanelMenuListener {\r
+        public boolean onCreatePanelMenu(int featureId, Menu menu);\r
+    }\r
+    /** Activity interface for menu creation callback. */\r
+    public interface OnCreateOptionsMenuListener {\r
+        public boolean onCreateOptionsMenu(Menu menu);\r
+    }\r
+    /** Activity interface for menu item selection callback. */\r
+    public interface OnMenuItemSelectedListener {\r
+        public boolean onMenuItemSelected(int featureId, MenuItem item);\r
+    }\r
+    /** Activity interface for menu item selection callback. */\r
+    public interface OnOptionsItemSelectedListener {\r
+        public boolean onOptionsItemSelected(MenuItem item);\r
+    }\r
+    /** Activity interface for menu preparation callback. */\r
+    public interface OnPreparePanelListener {\r
+        public boolean onPreparePanel(int featureId, View view, Menu menu);\r
+    }\r
+    /** Activity interface for menu preparation callback. */\r
+    public interface OnPrepareOptionsMenuListener {\r
+        public boolean onPrepareOptionsMenu(Menu menu);\r
+    }\r
+    /** Activity interface for action mode finished callback. */\r
+    public interface OnActionModeFinishedListener {\r
+        public void onActionModeFinished(ActionMode mode);\r
+    }\r
+    /** Activity interface for action mode started callback. */\r
+    public interface OnActionModeStartedListener {\r
+        public void onActionModeStarted(ActionMode mode);\r
+    }\r
+\r
+\r
+    /**\r
+     * If set, the logic in these classes will assume that an {@link Activity}\r
+     * is dispatching all of the required events to the class. This flag should\r
+     * only be used internally or if you are creating your own base activity\r
+     * modeled after one of the included types (e.g., {@code SherlockActivity}).\r
+     */\r
+    public static final int FLAG_DELEGATE = 1;\r
+\r
+\r
+    /**\r
+     * Register an ActionBarSherlock implementation.\r
+     *\r
+     * @param implementationClass Target implementation class which extends\r
+     * {@link ActionBarSherlock}. This class must also be annotated with\r
+     * {@link Implementation}.\r
+     */\r
+    public static void registerImplementation(Class<? extends ActionBarSherlock> implementationClass) {\r
+        if (!implementationClass.isAnnotationPresent(Implementation.class)) {\r
+            throw new IllegalArgumentException("Class " + implementationClass.getSimpleName() + " is not annotated with @Implementation");\r
+        } else if (IMPLEMENTATIONS.containsValue(implementationClass)) {\r
+            if (DEBUG) Log.w(TAG, "Class " + implementationClass.getSimpleName() + " already registered");\r
+            return;\r
+        }\r
+\r
+        Implementation impl = implementationClass.getAnnotation(Implementation.class);\r
+        if (DEBUG) Log.i(TAG, "Registering " + implementationClass.getSimpleName() + " with qualifier " + impl);\r
+        IMPLEMENTATIONS.put(impl, implementationClass);\r
+    }\r
+\r
+    /**\r
+     * Unregister an ActionBarSherlock implementation. <strong>This should be\r
+     * considered very volatile and you should only use it if you know what\r
+     * you are doing.</strong> You have been warned.\r
+     *\r
+     * @param implementationClass Target implementation class.\r
+     * @return Boolean indicating whether the class was removed.\r
+     */\r
+    public static boolean unregisterImplementation(Class<? extends ActionBarSherlock> implementationClass) {\r
+        return IMPLEMENTATIONS.values().remove(implementationClass);\r
+    }\r
+\r
+    /**\r
+     * Wrap an activity with an action bar abstraction which will enable the\r
+     * use of a custom implementation on platforms where a native version does\r
+     * not exist.\r
+     *\r
+     * @param activity Activity to wrap.\r
+     * @return Instance to interact with the action bar.\r
+     */\r
+    public static ActionBarSherlock wrap(Activity activity) {\r
+        return wrap(activity, 0);\r
+    }\r
+\r
+    /**\r
+     * Wrap an activity with an action bar abstraction which will enable the\r
+     * use of a custom implementation on platforms where a native version does\r
+     * not exist.\r
+     *\r
+     * @param activity Owning activity.\r
+     * @param flags Option flags to control behavior.\r
+     * @return Instance to interact with the action bar.\r
+     */\r
+    public static ActionBarSherlock wrap(Activity activity, int flags) {\r
+        //Create a local implementation map we can modify\r
+        HashMap<Implementation, Class<? extends ActionBarSherlock>> impls =\r
+                new HashMap<Implementation, Class<? extends ActionBarSherlock>>(IMPLEMENTATIONS);\r
+        boolean hasQualfier;\r
+\r
+        /* DPI FILTERING */\r
+        hasQualfier = false;\r
+        for (Implementation key : impls.keySet()) {\r
+            //Only honor TVDPI as a specific qualifier\r
+            if (key.dpi() == DisplayMetrics.DENSITY_TV) {\r
+                hasQualfier = true;\r
+                break;\r
+            }\r
+        }\r
+        if (hasQualfier) {\r
+            final boolean isTvDpi = activity.getResources().getDisplayMetrics().densityDpi == DisplayMetrics.DENSITY_TV;\r
+            for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {\r
+                int keyDpi = keys.next().dpi();\r
+                if ((isTvDpi && keyDpi != DisplayMetrics.DENSITY_TV)\r
+                        || (!isTvDpi && keyDpi == DisplayMetrics.DENSITY_TV)) {\r
+                    keys.remove();\r
+                }\r
+            }\r
+        }\r
+\r
+        /* API FILTERING */\r
+        hasQualfier = false;\r
+        for (Implementation key : impls.keySet()) {\r
+            if (key.api() != Implementation.DEFAULT_API) {\r
+                hasQualfier = true;\r
+                break;\r
+            }\r
+        }\r
+        if (hasQualfier) {\r
+            final int runtimeApi = Build.VERSION.SDK_INT;\r
+            int bestApi = 0;\r
+            for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {\r
+                int keyApi = keys.next().api();\r
+                if (keyApi > runtimeApi) {\r
+                    keys.remove();\r
+                } else if (keyApi > bestApi) {\r
+                    bestApi = keyApi;\r
+                }\r
+            }\r
+            for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {\r
+                if (keys.next().api() != bestApi) {\r
+                    keys.remove();\r
+                }\r
+            }\r
+        }\r
+\r
+        if (impls.size() > 1) {\r
+            throw new IllegalStateException("More than one implementation matches configuration.");\r
+        }\r
+        if (impls.isEmpty()) {\r
+            throw new IllegalStateException("No implementations match configuration.");\r
+        }\r
+        Class<? extends ActionBarSherlock> impl = impls.values().iterator().next();\r
+        if (DEBUG) Log.i(TAG, "Using implementation: " + impl.getSimpleName());\r
+\r
+        try {\r
+            Constructor<? extends ActionBarSherlock> ctor = impl.getConstructor(CONSTRUCTOR_ARGS);\r
+            return ctor.newInstance(activity, flags);\r
+        } catch (NoSuchMethodException e) {\r
+            throw new RuntimeException(e);\r
+        } catch (IllegalArgumentException e) {\r
+            throw new RuntimeException(e);\r
+        } catch (InstantiationException e) {\r
+            throw new RuntimeException(e);\r
+        } catch (IllegalAccessException e) {\r
+            throw new RuntimeException(e);\r
+        } catch (InvocationTargetException e) {\r
+            throw new RuntimeException(e);\r
+        }\r
+    }\r
+\r
+\r
+    /** Activity which is displaying the action bar. Also used for context. */\r
+    protected final Activity mActivity;\r
+    /** Whether delegating actions for the activity or managing ourselves. */\r
+    protected final boolean mIsDelegate;\r
+\r
+    /** Reference to our custom menu inflater which supports action items. */\r
+    protected MenuInflater mMenuInflater;\r
+\r
+\r
+\r
+    protected ActionBarSherlock(Activity activity, int flags) {\r
+        if (DEBUG) Log.d(TAG, "[<ctor>] activity: " + activity + ", flags: " + flags);\r
+\r
+        mActivity = activity;\r
+        mIsDelegate = (flags & FLAG_DELEGATE) != 0;\r
+    }\r
+\r
+\r
+    /**\r
+     * Get the current action bar instance.\r
+     *\r
+     * @return Action bar instance.\r
+     */\r
+    public abstract ActionBar getActionBar();\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Lifecycle and interaction callbacks when delegating\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    /**\r
+     * Notify action bar of a configuration change event. Should be dispatched\r
+     * after the call to the superclass implementation.\r
+     *\r
+     * <blockquote><pre>\r
+     * @Override\r
+     * public void onConfigurationChanged(Configuration newConfig) {\r
+     *     super.onConfigurationChanged(newConfig);\r
+     *     mSherlock.dispatchConfigurationChanged(newConfig);\r
+     * }\r
+     * </pre></blockquote>\r
+     *\r
+     * @param newConfig The new device configuration.\r
+     */\r
+    public void dispatchConfigurationChanged(Configuration newConfig) {}\r
+\r
+    /**\r
+     * Notify the action bar that the activity has finished its resuming. This\r
+     * should be dispatched after the call to the superclass implementation.\r
+     *\r
+     * <blockquote><pre>\r
+     * @Override\r
+     * protected void onPostResume() {\r
+     *     super.onPostResume();\r
+     *     mSherlock.dispatchPostResume();\r
+     * }\r
+     * </pre></blockquote>\r
+     */\r
+    public void dispatchPostResume() {}\r
+\r
+    /**\r
+     * Notify the action bar that the activity is pausing. This should be\r
+     * dispatched before the call to the superclass implementation.\r
+     *\r
+     * <blockquote><pre>\r
+     * @Override\r
+     * protected void onPause() {\r
+     *     mSherlock.dispatchPause();\r
+     *     super.onPause();\r
+     * }\r
+     * </pre></blockquote>\r
+     */\r
+    public void dispatchPause() {}\r
+\r
+    /**\r
+     * Notify the action bar that the activity is stopping. This should be\r
+     * called before the superclass implementation.\r
+     *\r
+     * <blockquote><p>\r
+     * @Override\r
+     * protected void onStop() {\r
+     *     mSherlock.dispatchStop();\r
+     *     super.onStop();\r
+     * }\r
+     * </p></blockquote>\r
+     */\r
+    public void dispatchStop() {}\r
+\r
+    /**\r
+     * Indicate that the menu should be recreated by calling\r
+     * {@link OnCreateOptionsMenuListener#onCreateOptionsMenu(com.actionbarsherlock.view.Menu)}.\r
+     */\r
+    public abstract void dispatchInvalidateOptionsMenu();\r
+\r
+    /**\r
+     * Notify the action bar that it should display its overflow menu if it is\r
+     * appropriate for the device. The implementation should conditionally\r
+     * call the superclass method only if this method returns {@code false}.\r
+     *\r
+     * <blockquote><p>\r
+     * @Override\r
+     * public void openOptionsMenu() {\r
+     *     if (!mSherlock.dispatchOpenOptionsMenu()) {\r
+     *         super.openOptionsMenu();\r
+     *     }\r
+     * }\r
+     * </p></blockquote>\r
+     *\r
+     * @return {@code true} if the opening of the menu was handled internally.\r
+     */\r
+    public boolean dispatchOpenOptionsMenu() {\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Notify the action bar that it should close its overflow menu if it is\r
+     * appropriate for the device. This implementation should conditionally\r
+     * call the superclass method only if this method returns {@code false}.\r
+     *\r
+     * <blockquote><pre>\r
+     * @Override\r
+     * public void closeOptionsMenu() {\r
+     *     if (!mSherlock.dispatchCloseOptionsMenu()) {\r
+     *         super.closeOptionsMenu();\r
+     *     }\r
+     * }\r
+     * </pre></blockquote>\r
+     *\r
+     * @return {@code true} if the closing of the menu was handled internally.\r
+     */\r
+    public boolean dispatchCloseOptionsMenu() {\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Notify the class that the activity has finished its creation. This\r
+     * should be called after the superclass implementation.\r
+     *\r
+     * <blockquote><pre>\r
+     * @Override\r
+     * protected void onPostCreate(Bundle savedInstanceState) {\r
+     *     mSherlock.dispatchPostCreate(savedInstanceState);\r
+     *     super.onPostCreate(savedInstanceState);\r
+     * }\r
+     * </pre></blockquote>\r
+     *\r
+     * @param savedInstanceState If the activity is being re-initialized after\r
+     *                           previously being shut down then this Bundle\r
+     *                           contains the data it most recently supplied in\r
+     *                           {@link Activity#}onSaveInstanceState(Bundle)}.\r
+     *                           <strong>Note: Otherwise it is null.</strong>\r
+     */\r
+    public void dispatchPostCreate(Bundle savedInstanceState) {}\r
+\r
+    /**\r
+     * Notify the action bar that the title has changed and the action bar\r
+     * should be updated to reflect the change. This should be called before\r
+     * the superclass implementation.\r
+     *\r
+     * <blockquote><pre>\r
+     *  @Override\r
+     *  protected void onTitleChanged(CharSequence title, int color) {\r
+     *      mSherlock.dispatchTitleChanged(title, color);\r
+     *      super.onTitleChanged(title, color);\r
+     *  }\r
+     * </pre></blockquote>\r
+     *\r
+     * @param title New activity title.\r
+     * @param color New activity color.\r
+     */\r
+    public void dispatchTitleChanged(CharSequence title, int color) {}\r
+\r
+    /**\r
+     * Notify the action bar the user has created a key event. This is used to\r
+     * toggle the display of the overflow action item with the menu key and to\r
+     * close the action mode or expanded action item with the back key.\r
+     *\r
+     * <blockquote><pre>\r
+     * @Override\r
+     * public boolean dispatchKeyEvent(KeyEvent event) {\r
+     *     if (mSherlock.dispatchKeyEvent(event)) {\r
+     *         return true;\r
+     *     }\r
+     *     return super.dispatchKeyEvent(event);\r
+     * }\r
+     * </pre></blockquote>\r
+     *\r
+     * @param event Description of the key event.\r
+     * @return {@code true} if the event was handled.\r
+     */\r
+    public boolean dispatchKeyEvent(KeyEvent event) {\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Notify the action bar that the Activity has triggered a menu creation\r
+     * which should happen on the conclusion of {@link Activity#onCreate}. This\r
+     * will be used to gain a reference to the native menu for native and\r
+     * overflow binding as well as to indicate when compatibility create should\r
+     * occur for the first time.\r
+     *\r
+     * @param menu Activity native menu.\r
+     * @return {@code true} since we always want to say that we have a native\r
+     */\r
+    public abstract boolean dispatchCreateOptionsMenu(android.view.Menu menu);\r
+\r
+    /**\r
+     * Notify the action bar that the Activity has triggered a menu preparation\r
+     * which usually means that the user has requested the overflow menu via a\r
+     * hardware menu key. You should return the result of this method call and\r
+     * not call the superclass implementation.\r
+     *\r
+     * <blockquote><p>\r
+     * @Override\r
+     * public final boolean onPrepareOptionsMenu(android.view.Menu menu) {\r
+     *     return mSherlock.dispatchPrepareOptionsMenu(menu);\r
+     * }\r
+     * </p></blockquote>\r
+     *\r
+     * @param menu Activity native menu.\r
+     * @return {@code true} if menu display should proceed.\r
+     */\r
+    public abstract boolean dispatchPrepareOptionsMenu(android.view.Menu menu);\r
+\r
+    /**\r
+     * Notify the action bar that a native options menu item has been selected.\r
+     * The implementation should return the result of this method call.\r
+     *\r
+     * <blockquote><p>\r
+     * @Override\r
+     * public final boolean onOptionsItemSelected(android.view.MenuItem item) {\r
+     *     return mSherlock.dispatchOptionsItemSelected(item);\r
+     * }\r
+     * </p></blockquote>\r
+     *\r
+     * @param item Options menu item.\r
+     * @return @{code true} if the selection was handled.\r
+     */\r
+    public abstract boolean dispatchOptionsItemSelected(android.view.MenuItem item);\r
+\r
+    /**\r
+     * Notify the action bar that the overflow menu has been opened. The\r
+     * implementation should conditionally return {@code true} if this method\r
+     * returns {@code true}, otherwise return the result of the superclass\r
+     * method.\r
+     *\r
+     * <blockquote><p>\r
+     * @Override\r
+     * public final boolean onMenuOpened(int featureId, android.view.Menu menu) {\r
+     *     if (mSherlock.dispatchMenuOpened(featureId, menu)) {\r
+     *         return true;\r
+     *     }\r
+     *     return super.onMenuOpened(featureId, menu);\r
+     * }\r
+     * </p></blockquote>\r
+     *\r
+     * @param featureId Window feature which triggered the event.\r
+     * @param menu Activity native menu.\r
+     * @return {@code true} if the event was handled by this method.\r
+     */\r
+    public boolean dispatchMenuOpened(int featureId, android.view.Menu menu) {\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Notify the action bar that the overflow menu has been closed. This\r
+     * method should be called before the superclass implementation.\r
+     *\r
+     * <blockquote><p>\r
+     * @Override\r
+     * public void onPanelClosed(int featureId, android.view.Menu menu) {\r
+     *     mSherlock.dispatchPanelClosed(featureId, menu);\r
+     *     super.onPanelClosed(featureId, menu);\r
+     * }\r
+     * </p></blockquote>\r
+     *\r
+     * @param featureId\r
+     * @param menu\r
+     */\r
+    public void dispatchPanelClosed(int featureId, android.view.Menu menu) {}\r
+\r
+    /**\r
+     * Notify the action bar that the activity has been destroyed. This method\r
+     * should be called before the superclass implementation.\r
+     *\r
+     * <blockquote><p>\r
+     * @Override\r
+     * public void onDestroy() {\r
+     *     mSherlock.dispatchDestroy();\r
+     *     super.onDestroy();\r
+     * }\r
+     * </p></blockquote>\r
+     */\r
+    public void dispatchDestroy() {}\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+    /**\r
+     * Internal method to trigger the menu creation process.\r
+     *\r
+     * @return {@code true} if menu creation should proceed.\r
+     */\r
+    protected final boolean callbackCreateOptionsMenu(Menu menu) {\r
+        if (DEBUG) Log.d(TAG, "[callbackCreateOptionsMenu] menu: " + menu);\r
+\r
+        boolean result = true;\r
+        if (mActivity instanceof OnCreatePanelMenuListener) {\r
+            OnCreatePanelMenuListener listener = (OnCreatePanelMenuListener)mActivity;\r
+            result = listener.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);\r
+        } else if (mActivity instanceof OnCreateOptionsMenuListener) {\r
+            OnCreateOptionsMenuListener listener = (OnCreateOptionsMenuListener)mActivity;\r
+            result = listener.onCreateOptionsMenu(menu);\r
+        }\r
+\r
+        if (DEBUG) Log.d(TAG, "[callbackCreateOptionsMenu] returning " + result);\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * Internal method to trigger the menu preparation process.\r
+     *\r
+     * @return {@code true} if menu preparation should proceed.\r
+     */\r
+    protected final boolean callbackPrepareOptionsMenu(Menu menu) {\r
+        if (DEBUG) Log.d(TAG, "[callbackPrepareOptionsMenu] menu: " + menu);\r
+\r
+        boolean result = true;\r
+        if (mActivity instanceof OnPreparePanelListener) {\r
+            OnPreparePanelListener listener = (OnPreparePanelListener)mActivity;\r
+            result = listener.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, menu);\r
+        } else if (mActivity instanceof OnPrepareOptionsMenuListener) {\r
+            OnPrepareOptionsMenuListener listener = (OnPrepareOptionsMenuListener)mActivity;\r
+            result = listener.onPrepareOptionsMenu(menu);\r
+        }\r
+\r
+        if (DEBUG) Log.d(TAG, "[callbackPrepareOptionsMenu] returning " + result);\r
+        return result;\r
+    }\r
+\r
+    /**\r
+     * Internal method for dispatching options menu selection to the owning\r
+     * activity callback.\r
+     *\r
+     * @param item Selected options menu item.\r
+     * @return {@code true} if the item selection was handled in the callback.\r
+     */\r
+    protected final boolean callbackOptionsItemSelected(MenuItem item) {\r
+        if (DEBUG) Log.d(TAG, "[callbackOptionsItemSelected] item: " + item.getTitleCondensed());\r
+\r
+        boolean result = false;\r
+        if (mActivity instanceof OnMenuItemSelectedListener) {\r
+            OnMenuItemSelectedListener listener = (OnMenuItemSelectedListener)mActivity;\r
+            result = listener.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);\r
+        } else if (mActivity instanceof OnOptionsItemSelectedListener) {\r
+            OnOptionsItemSelectedListener listener = (OnOptionsItemSelectedListener)mActivity;\r
+            result = listener.onOptionsItemSelected(item);\r
+        }\r
+\r
+        if (DEBUG) Log.d(TAG, "[callbackOptionsItemSelected] returning " + result);\r
+        return result;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+\r
+    /**\r
+     * Query for the availability of a certain feature.\r
+     *\r
+     * @param featureId The feature ID to check.\r
+     * @return {@code true} if feature is enabled, {@code false} otherwise.\r
+     */\r
+    public abstract boolean hasFeature(int featureId);\r
+\r
+    /**\r
+     * Enable extended screen features. This must be called before\r
+     * {@code setContentView()}. May be called as many times as desired as long\r
+     * as it is before {@code setContentView()}. If not called, no extended\r
+     * features will be available. You can not turn off a feature once it is\r
+     * requested.\r
+     *\r
+     * @param featureId The desired features, defined as constants by Window.\r
+     * @return Returns true if the requested feature is supported and now\r
+     * enabled.\r
+     */\r
+    public abstract boolean requestFeature(int featureId);\r
+\r
+    /**\r
+     * Set extra options that will influence the UI for this window.\r
+     *\r
+     * @param uiOptions Flags specifying extra options for this window.\r
+     */\r
+    public abstract void setUiOptions(int uiOptions);\r
+\r
+    /**\r
+     * Set extra options that will influence the UI for this window. Only the\r
+     * bits filtered by mask will be modified.\r
+     *\r
+     * @param uiOptions Flags specifying extra options for this window.\r
+     * @param mask Flags specifying which options should be modified. Others\r
+     *             will remain unchanged.\r
+     */\r
+    public abstract void setUiOptions(int uiOptions, int mask);\r
+\r
+    /**\r
+     * Set the content of the activity inside the action bar.\r
+     *\r
+     * @param layoutResId Layout resource ID.\r
+     */\r
+    public abstract void setContentView(int layoutResId);\r
+\r
+    /**\r
+     * Set the content of the activity inside the action bar.\r
+     *\r
+     * @param view The desired content to display.\r
+     */\r
+    public void setContentView(View view) {\r
+        if (DEBUG) Log.d(TAG, "[setContentView] view: " + view);\r
+\r
+        setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));\r
+    }\r
+\r
+    /**\r
+     * Set the content of the activity inside the action bar.\r
+     *\r
+     * @param view The desired content to display.\r
+     * @param params Layout parameters to apply to the view.\r
+     */\r
+    public abstract void setContentView(View view, ViewGroup.LayoutParams params);\r
+\r
+    /**\r
+     * Variation on {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}\r
+     * to add an additional content view to the screen. Added after any\r
+     * existing ones on the screen -- existing views are NOT removed.\r
+     *\r
+     * @param view The desired content to display.\r
+     * @param params Layout parameters for the view.\r
+     */\r
+    public abstract void addContentView(View view, ViewGroup.LayoutParams params);\r
+\r
+    /**\r
+     * Change the title associated with this activity.\r
+     */\r
+    public abstract void setTitle(CharSequence title);\r
+\r
+    /**\r
+     * Change the title associated with this activity.\r
+     */\r
+    public void setTitle(int resId) {\r
+        if (DEBUG) Log.d(TAG, "[setTitle] resId: " + resId);\r
+\r
+        setTitle(mActivity.getString(resId));\r
+    }\r
+\r
+    /**\r
+     * Sets the visibility of the progress bar in the title.\r
+     * <p>\r
+     * In order for the progress bar to be shown, the feature must be requested\r
+     * via {@link #requestWindowFeature(int)}.\r
+     *\r
+     * @param visible Whether to show the progress bars in the title.\r
+     */\r
+    public abstract void setProgressBarVisibility(boolean visible);\r
+\r
+    /**\r
+     * Sets the visibility of the indeterminate progress bar in the title.\r
+     * <p>\r
+     * In order for the progress bar to be shown, the feature must be requested\r
+     * via {@link #requestWindowFeature(int)}.\r
+     *\r
+     * @param visible Whether to show the progress bars in the title.\r
+     */\r
+    public abstract void setProgressBarIndeterminateVisibility(boolean visible);\r
+\r
+    /**\r
+     * Sets whether the horizontal progress bar in the title should be indeterminate (the circular\r
+     * is always indeterminate).\r
+     * <p>\r
+     * In order for the progress bar to be shown, the feature must be requested\r
+     * via {@link #requestWindowFeature(int)}.\r
+     *\r
+     * @param indeterminate Whether the horizontal progress bar should be indeterminate.\r
+     */\r
+    public abstract void setProgressBarIndeterminate(boolean indeterminate);\r
+\r
+    /**\r
+     * Sets the progress for the progress bars in the title.\r
+     * <p>\r
+     * In order for the progress bar to be shown, the feature must be requested\r
+     * via {@link #requestWindowFeature(int)}.\r
+     *\r
+     * @param progress The progress for the progress bar. Valid ranges are from\r
+     *            0 to 10000 (both inclusive). If 10000 is given, the progress\r
+     *            bar will be completely filled and will fade out.\r
+     */\r
+    public abstract void setProgress(int progress);\r
+\r
+    /**\r
+     * Sets the secondary progress for the progress bar in the title. This\r
+     * progress is drawn between the primary progress (set via\r
+     * {@link #setProgress(int)} and the background. It can be ideal for media\r
+     * scenarios such as showing the buffering progress while the default\r
+     * progress shows the play progress.\r
+     * <p>\r
+     * In order for the progress bar to be shown, the feature must be requested\r
+     * via {@link #requestWindowFeature(int)}.\r
+     *\r
+     * @param secondaryProgress The secondary progress for the progress bar. Valid ranges are from\r
+     *            0 to 10000 (both inclusive).\r
+     */\r
+    public abstract void setSecondaryProgress(int secondaryProgress);\r
+\r
+    /**\r
+     * Get a menu inflater instance which supports the newer menu attributes.\r
+     *\r
+     * @return Menu inflater instance.\r
+     */\r
+    public MenuInflater getMenuInflater() {\r
+        if (DEBUG) Log.d(TAG, "[getMenuInflater]");\r
+\r
+        // Make sure that action views can get an appropriate theme.\r
+        if (mMenuInflater == null) {\r
+            if (getActionBar() != null) {\r
+                mMenuInflater = new MenuInflater(getThemedContext());\r
+            } else {\r
+                mMenuInflater = new MenuInflater(mActivity);\r
+            }\r
+        }\r
+        return mMenuInflater;\r
+    }\r
+\r
+    protected abstract Context getThemedContext();\r
+\r
+    /**\r
+     * Start an action mode.\r
+     *\r
+     * @param callback Callback that will manage lifecycle events for this\r
+     *                 context mode.\r
+     * @return The ContextMode that was started, or null if it was canceled.\r
+     * @see ActionMode\r
+     */\r
+    public abstract ActionMode startActionMode(ActionMode.Callback callback);\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/ActionBar.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/ActionBar.java
new file mode 100644 (file)
index 0000000..2497d24
--- /dev/null
@@ -0,0 +1,947 @@
+/*\r
+ * Copyright (C) 2010 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.actionbarsherlock.app;\r
+\r
+import android.content.Context;\r
+import android.graphics.drawable.Drawable;\r
+import android.support.v4.app.FragmentTransaction;\r
+import android.util.AttributeSet;\r
+import android.view.Gravity;\r
+import android.view.View;\r
+import android.view.ViewDebug;\r
+import android.view.ViewGroup;\r
+import android.view.ViewGroup.MarginLayoutParams;\r
+import android.widget.SpinnerAdapter;\r
+\r
+/**\r
+ * A window feature at the top of the activity that may display the activity title, navigation\r
+ * modes, and other interactive items.\r
+ * <p>Beginning with Android 3.0 (API level 11), the action bar appears at the top of an\r
+ * activity's window when the activity uses the system's {@link\r
+ * android.R.style#Theme_Holo Holo} theme (or one of its descendant themes), which is the default.\r
+ * You may otherwise add the action bar by calling {@link\r
+ * android.view.Window#requestFeature requestFeature(FEATURE_ACTION_BAR)} or by declaring it in a\r
+ * custom theme with the {@link android.R.styleable#Theme_windowActionBar windowActionBar} property.\r
+ * <p>By default, the action bar shows the application icon on\r
+ * the left, followed by the activity title. If your activity has an options menu, you can make\r
+ * select items accessible directly from the action bar as "action items". You can also\r
+ * modify various characteristics of the action bar or remove it completely.</p>\r
+ * <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link\r
+ * android.app.Activity#getActionBar getActionBar()}.</p>\r
+ * <p>In some cases, the action bar may be overlayed by another bar that enables contextual actions,\r
+ * using an {@link android.view.ActionMode}. For example, when the user selects one or more items in\r
+ * your activity, you can enable an action mode that offers actions specific to the selected\r
+ * items, with a UI that temporarily replaces the action bar. Although the UI may occupy the\r
+ * same space, the {@link android.view.ActionMode} APIs are distinct and independent from those for\r
+ * {@link ActionBar}.\r
+ * <div class="special reference">\r
+ * <h3>Developer Guides</h3>\r
+ * <p>For information about how to use the action bar, including how to add action items, navigation\r
+ * modes and more, read the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action\r
+ * Bar</a> developer guide.</p>\r
+ * </div>\r
+ */\r
+public abstract class ActionBar {\r
+    /**\r
+     * Standard navigation mode. Consists of either a logo or icon\r
+     * and title text with an optional subtitle. Clicking any of these elements\r
+     * will dispatch onOptionsItemSelected to the host Activity with\r
+     * a MenuItem with item ID android.R.id.home.\r
+     */\r
+    public static final int NAVIGATION_MODE_STANDARD = android.app.ActionBar.NAVIGATION_MODE_STANDARD;\r
+\r
+    /**\r
+     * List navigation mode. Instead of static title text this mode\r
+     * presents a list menu for navigation within the activity.\r
+     * e.g. this might be presented to the user as a dropdown list.\r
+     */\r
+    public static final int NAVIGATION_MODE_LIST = android.app.ActionBar.NAVIGATION_MODE_LIST;\r
+\r
+    /**\r
+     * Tab navigation mode. Instead of static title text this mode\r
+     * presents a series of tabs for navigation within the activity.\r
+     */\r
+    public static final int NAVIGATION_MODE_TABS = android.app.ActionBar.NAVIGATION_MODE_TABS;\r
+\r
+    /**\r
+     * Use logo instead of icon if available. This flag will cause appropriate\r
+     * navigation modes to use a wider logo in place of the standard icon.\r
+     *\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public static final int DISPLAY_USE_LOGO = android.app.ActionBar.DISPLAY_USE_LOGO;\r
+\r
+    /**\r
+     * Show 'home' elements in this action bar, leaving more space for other\r
+     * navigation elements. This includes logo and icon.\r
+     *\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public static final int DISPLAY_SHOW_HOME = android.app.ActionBar.DISPLAY_SHOW_HOME;\r
+\r
+    /**\r
+     * Display the 'home' element such that it appears as an 'up' affordance.\r
+     * e.g. show an arrow to the left indicating the action that will be taken.\r
+     *\r
+     * Set this flag if selecting the 'home' button in the action bar to return\r
+     * up by a single level in your UI rather than back to the top level or front page.\r
+     *\r
+     * <p>Setting this option will implicitly enable interaction with the home/up\r
+     * button. See {@link #setHomeButtonEnabled(boolean)}.\r
+     *\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public static final int DISPLAY_HOME_AS_UP = android.app.ActionBar.DISPLAY_HOME_AS_UP;\r
+\r
+    /**\r
+     * Show the activity title and subtitle, if present.\r
+     *\r
+     * @see #setTitle(CharSequence)\r
+     * @see #setTitle(int)\r
+     * @see #setSubtitle(CharSequence)\r
+     * @see #setSubtitle(int)\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public static final int DISPLAY_SHOW_TITLE = android.app.ActionBar.DISPLAY_SHOW_TITLE;\r
+\r
+    /**\r
+     * Show the custom view if one has been set.\r
+     * @see #setCustomView(View)\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public static final int DISPLAY_SHOW_CUSTOM = android.app.ActionBar.DISPLAY_SHOW_CUSTOM;\r
+\r
+    /**\r
+     * Set the action bar into custom navigation mode, supplying a view\r
+     * for custom navigation.\r
+     *\r
+     * Custom navigation views appear between the application icon and\r
+     * any action buttons and may use any space available there. Common\r
+     * use cases for custom navigation views might include an auto-suggesting\r
+     * address bar for a browser or other navigation mechanisms that do not\r
+     * translate well to provided navigation modes.\r
+     *\r
+     * @param view Custom navigation view to place in the ActionBar.\r
+     */\r
+    public abstract void setCustomView(View view);\r
+\r
+    /**\r
+     * Set the action bar into custom navigation mode, supplying a view\r
+     * for custom navigation.\r
+     *\r
+     * <p>Custom navigation views appear between the application icon and\r
+     * any action buttons and may use any space available there. Common\r
+     * use cases for custom navigation views might include an auto-suggesting\r
+     * address bar for a browser or other navigation mechanisms that do not\r
+     * translate well to provided navigation modes.</p>\r
+     *\r
+     * <p>The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for\r
+     * the custom view to be displayed.</p>\r
+     *\r
+     * @param view Custom navigation view to place in the ActionBar.\r
+     * @param layoutParams How this custom view should layout in the bar.\r
+     *\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setCustomView(View view, LayoutParams layoutParams);\r
+\r
+    /**\r
+     * Set the action bar into custom navigation mode, supplying a view\r
+     * for custom navigation.\r
+     *\r
+     * <p>Custom navigation views appear between the application icon and\r
+     * any action buttons and may use any space available there. Common\r
+     * use cases for custom navigation views might include an auto-suggesting\r
+     * address bar for a browser or other navigation mechanisms that do not\r
+     * translate well to provided navigation modes.</p>\r
+     *\r
+     * <p>The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for\r
+     * the custom view to be displayed.</p>\r
+     *\r
+     * @param resId Resource ID of a layout to inflate into the ActionBar.\r
+     *\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setCustomView(int resId);\r
+\r
+    /**\r
+     * Set the icon to display in the 'home' section of the action bar.\r
+     * The action bar will use an icon specified by its style or the\r
+     * activity icon by default.\r
+     *\r
+     * Whether the home section shows an icon or logo is controlled\r
+     * by the display option {@link #DISPLAY_USE_LOGO}.\r
+     *\r
+     * @param resId Resource ID of a drawable to show as an icon.\r
+     *\r
+     * @see #setDisplayUseLogoEnabled(boolean)\r
+     * @see #setDisplayShowHomeEnabled(boolean)\r
+     */\r
+    public abstract void setIcon(int resId);\r
+\r
+    /**\r
+     * Set the icon to display in the 'home' section of the action bar.\r
+     * The action bar will use an icon specified by its style or the\r
+     * activity icon by default.\r
+     *\r
+     * Whether the home section shows an icon or logo is controlled\r
+     * by the display option {@link #DISPLAY_USE_LOGO}.\r
+     *\r
+     * @param icon Drawable to show as an icon.\r
+     *\r
+     * @see #setDisplayUseLogoEnabled(boolean)\r
+     * @see #setDisplayShowHomeEnabled(boolean)\r
+     */\r
+    public abstract void setIcon(Drawable icon);\r
+\r
+    /**\r
+     * Set the logo to display in the 'home' section of the action bar.\r
+     * The action bar will use a logo specified by its style or the\r
+     * activity logo by default.\r
+     *\r
+     * Whether the home section shows an icon or logo is controlled\r
+     * by the display option {@link #DISPLAY_USE_LOGO}.\r
+     *\r
+     * @param resId Resource ID of a drawable to show as a logo.\r
+     *\r
+     * @see #setDisplayUseLogoEnabled(boolean)\r
+     * @see #setDisplayShowHomeEnabled(boolean)\r
+     */\r
+    public abstract void setLogo(int resId);\r
+\r
+    /**\r
+     * Set the logo to display in the 'home' section of the action bar.\r
+     * The action bar will use a logo specified by its style or the\r
+     * activity logo by default.\r
+     *\r
+     * Whether the home section shows an icon or logo is controlled\r
+     * by the display option {@link #DISPLAY_USE_LOGO}.\r
+     *\r
+     * @param logo Drawable to show as a logo.\r
+     *\r
+     * @see #setDisplayUseLogoEnabled(boolean)\r
+     * @see #setDisplayShowHomeEnabled(boolean)\r
+     */\r
+    public abstract void setLogo(Drawable logo);\r
+\r
+    /**\r
+     * Set the adapter and navigation callback for list navigation mode.\r
+     *\r
+     * The supplied adapter will provide views for the expanded list as well as\r
+     * the currently selected item. (These may be displayed differently.)\r
+     *\r
+     * The supplied OnNavigationListener will alert the application when the user\r
+     * changes the current list selection.\r
+     *\r
+     * @param adapter An adapter that will provide views both to display\r
+     *                the current navigation selection and populate views\r
+     *                within the dropdown navigation menu.\r
+     * @param callback An OnNavigationListener that will receive events when the user\r
+     *                 selects a navigation item.\r
+     */\r
+    public abstract void setListNavigationCallbacks(SpinnerAdapter adapter,\r
+            OnNavigationListener callback);\r
+\r
+    /**\r
+     * Set the selected navigation item in list or tabbed navigation modes.\r
+     *\r
+     * @param position Position of the item to select.\r
+     */\r
+    public abstract void setSelectedNavigationItem(int position);\r
+\r
+    /**\r
+     * Get the position of the selected navigation item in list or tabbed navigation modes.\r
+     *\r
+     * @return Position of the selected item.\r
+     */\r
+    public abstract int getSelectedNavigationIndex();\r
+\r
+    /**\r
+     * Get the number of navigation items present in the current navigation mode.\r
+     *\r
+     * @return Number of navigation items.\r
+     */\r
+    public abstract int getNavigationItemCount();\r
+\r
+    /**\r
+     * Set the action bar's title. This will only be displayed if\r
+     * {@link #DISPLAY_SHOW_TITLE} is set.\r
+     *\r
+     * @param title Title to set\r
+     *\r
+     * @see #setTitle(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setTitle(CharSequence title);\r
+\r
+    /**\r
+     * Set the action bar's title. This will only be displayed if\r
+     * {@link #DISPLAY_SHOW_TITLE} is set.\r
+     *\r
+     * @param resId Resource ID of title string to set\r
+     *\r
+     * @see #setTitle(CharSequence)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setTitle(int resId);\r
+\r
+    /**\r
+     * Set the action bar's subtitle. This will only be displayed if\r
+     * {@link #DISPLAY_SHOW_TITLE} is set. Set to null to disable the\r
+     * subtitle entirely.\r
+     *\r
+     * @param subtitle Subtitle to set\r
+     *\r
+     * @see #setSubtitle(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setSubtitle(CharSequence subtitle);\r
+\r
+    /**\r
+     * Set the action bar's subtitle. This will only be displayed if\r
+     * {@link #DISPLAY_SHOW_TITLE} is set.\r
+     *\r
+     * @param resId Resource ID of subtitle string to set\r
+     *\r
+     * @see #setSubtitle(CharSequence)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setSubtitle(int resId);\r
+\r
+    /**\r
+     * Set display options. This changes all display option bits at once. To change\r
+     * a limited subset of display options, see {@link #setDisplayOptions(int, int)}.\r
+     *\r
+     * @param options A combination of the bits defined by the DISPLAY_ constants\r
+     *                defined in ActionBar.\r
+     */\r
+    public abstract void setDisplayOptions(int options);\r
+\r
+    /**\r
+     * Set selected display options. Only the options specified by mask will be changed.\r
+     * To change all display option bits at once, see {@link #setDisplayOptions(int)}.\r
+     *\r
+     * <p>Example: setDisplayOptions(0, DISPLAY_SHOW_HOME) will disable the\r
+     * {@link #DISPLAY_SHOW_HOME} option.\r
+     * setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO)\r
+     * will enable {@link #DISPLAY_SHOW_HOME} and disable {@link #DISPLAY_USE_LOGO}.\r
+     *\r
+     * @param options A combination of the bits defined by the DISPLAY_ constants\r
+     *                defined in ActionBar.\r
+     * @param mask A bit mask declaring which display options should be changed.\r
+     */\r
+    public abstract void setDisplayOptions(int options, int mask);\r
+\r
+    /**\r
+     * Set whether to display the activity logo rather than the activity icon.\r
+     * A logo is often a wider, more detailed image.\r
+     *\r
+     * <p>To set several display options at once, see the setDisplayOptions methods.\r
+     *\r
+     * @param useLogo true to use the activity logo, false to use the activity icon.\r
+     *\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setDisplayUseLogoEnabled(boolean useLogo);\r
+\r
+    /**\r
+     * Set whether to include the application home affordance in the action bar.\r
+     * Home is presented as either an activity icon or logo.\r
+     *\r
+     * <p>To set several display options at once, see the setDisplayOptions methods.\r
+     *\r
+     * @param showHome true to show home, false otherwise.\r
+     *\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setDisplayShowHomeEnabled(boolean showHome);\r
+\r
+    /**\r
+     * Set whether home should be displayed as an "up" affordance.\r
+     * Set this to true if selecting "home" returns up by a single level in your UI\r
+     * rather than back to the top level or front page.\r
+     *\r
+     * <p>To set several display options at once, see the setDisplayOptions methods.\r
+     *\r
+     * @param showHomeAsUp true to show the user that selecting home will return one\r
+     *                     level up rather than to the top level of the app.\r
+     *\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setDisplayHomeAsUpEnabled(boolean showHomeAsUp);\r
+\r
+    /**\r
+     * Set whether an activity title/subtitle should be displayed.\r
+     *\r
+     * <p>To set several display options at once, see the setDisplayOptions methods.\r
+     *\r
+     * @param showTitle true to display a title/subtitle if present.\r
+     *\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setDisplayShowTitleEnabled(boolean showTitle);\r
+\r
+    /**\r
+     * Set whether a custom view should be displayed, if set.\r
+     *\r
+     * <p>To set several display options at once, see the setDisplayOptions methods.\r
+     *\r
+     * @param showCustom true if the currently set custom view should be displayed, false otherwise.\r
+     *\r
+     * @see #setDisplayOptions(int)\r
+     * @see #setDisplayOptions(int, int)\r
+     */\r
+    public abstract void setDisplayShowCustomEnabled(boolean showCustom);\r
+\r
+    /**\r
+     * Set the ActionBar's background. This will be used for the primary\r
+     * action bar.\r
+     *\r
+     * @param d Background drawable\r
+     * @see #setStackedBackgroundDrawable(Drawable)\r
+     * @see #setSplitBackgroundDrawable(Drawable)\r
+     */\r
+    public abstract void setBackgroundDrawable(Drawable d);\r
+\r
+    /**\r
+     * Set the ActionBar's stacked background. This will appear\r
+     * in the second row/stacked bar on some devices and configurations.\r
+     *\r
+     * @param d Background drawable for the stacked row\r
+     */\r
+    public void setStackedBackgroundDrawable(Drawable d) { }\r
+\r
+    /**\r
+     * Set the ActionBar's split background. This will appear in\r
+     * the split action bar containing menu-provided action buttons\r
+     * on some devices and configurations.\r
+     * <p>You can enable split action bar with {@link android.R.attr#uiOptions}\r
+     *\r
+     * @param d Background drawable for the split bar\r
+     */\r
+    public void setSplitBackgroundDrawable(Drawable d) { }\r
+\r
+    /**\r
+     * @return The current custom view.\r
+     */\r
+    public abstract View getCustomView();\r
+\r
+    /**\r
+     * Returns the current ActionBar title in standard mode.\r
+     * Returns null if {@link #getNavigationMode()} would not return\r
+     * {@link #NAVIGATION_MODE_STANDARD}.\r
+     *\r
+     * @return The current ActionBar title or null.\r
+     */\r
+    public abstract CharSequence getTitle();\r
+\r
+    /**\r
+     * Returns the current ActionBar subtitle in standard mode.\r
+     * Returns null if {@link #getNavigationMode()} would not return\r
+     * {@link #NAVIGATION_MODE_STANDARD}.\r
+     *\r
+     * @return The current ActionBar subtitle or null.\r
+     */\r
+    public abstract CharSequence getSubtitle();\r
+\r
+    /**\r
+     * Returns the current navigation mode. The result will be one of:\r
+     * <ul>\r
+     * <li>{@link #NAVIGATION_MODE_STANDARD}</li>\r
+     * <li>{@link #NAVIGATION_MODE_LIST}</li>\r
+     * <li>{@link #NAVIGATION_MODE_TABS}</li>\r
+     * </ul>\r
+     *\r
+     * @return The current navigation mode.\r
+     */\r
+    public abstract int getNavigationMode();\r
+\r
+    /**\r
+     * Set the current navigation mode.\r
+     *\r
+     * @param mode The new mode to set.\r
+     * @see #NAVIGATION_MODE_STANDARD\r
+     * @see #NAVIGATION_MODE_LIST\r
+     * @see #NAVIGATION_MODE_TABS\r
+     */\r
+    public abstract void setNavigationMode(int mode);\r
+\r
+    /**\r
+     * @return The current set of display options.\r
+     */\r
+    public abstract int getDisplayOptions();\r
+\r
+    /**\r
+     * Create and return a new {@link Tab}.\r
+     * This tab will not be included in the action bar until it is added.\r
+     *\r
+     * <p>Very often tabs will be used to switch between {@link Fragment}\r
+     * objects.  Here is a typical implementation of such tabs:</p>\r
+     *\r
+     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.java\r
+     *      complete}\r
+     *\r
+     * @return A new Tab\r
+     *\r
+     * @see #addTab(Tab)\r
+     */\r
+    public abstract Tab newTab();\r
+\r
+    /**\r
+     * Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list.\r
+     * If this is the first tab to be added it will become the selected tab.\r
+     *\r
+     * @param tab Tab to add\r
+     */\r
+    public abstract void addTab(Tab tab);\r
+\r
+    /**\r
+     * Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list.\r
+     *\r
+     * @param tab Tab to add\r
+     * @param setSelected True if the added tab should become the selected tab.\r
+     */\r
+    public abstract void addTab(Tab tab, boolean setSelected);\r
+\r
+    /**\r
+     * Add a tab for use in tabbed navigation mode. The tab will be inserted at\r
+     * <code>position</code>. If this is the first tab to be added it will become\r
+     * the selected tab.\r
+     *\r
+     * @param tab The tab to add\r
+     * @param position The new position of the tab\r
+     */\r
+    public abstract void addTab(Tab tab, int position);\r
+\r
+    /**\r
+     * Add a tab for use in tabbed navigation mode. The tab will be insterted at\r
+     * <code>position</code>.\r
+     *\r
+     * @param tab The tab to add\r
+     * @param position The new position of the tab\r
+     * @param setSelected True if the added tab should become the selected tab.\r
+     */\r
+    public abstract void addTab(Tab tab, int position, boolean setSelected);\r
+\r
+    /**\r
+     * Remove a tab from the action bar. If the removed tab was selected it will be deselected\r
+     * and another tab will be selected if present.\r
+     *\r
+     * @param tab The tab to remove\r
+     */\r
+    public abstract void removeTab(Tab tab);\r
+\r
+    /**\r
+     * Remove a tab from the action bar. If the removed tab was selected it will be deselected\r
+     * and another tab will be selected if present.\r
+     *\r
+     * @param position Position of the tab to remove\r
+     */\r
+    public abstract void removeTabAt(int position);\r
+\r
+    /**\r
+     * Remove all tabs from the action bar and deselect the current tab.\r
+     */\r
+    public abstract void removeAllTabs();\r
+\r
+    /**\r
+     * Select the specified tab. If it is not a child of this action bar it will be added.\r
+     *\r
+     * <p>Note: If you want to select by index, use {@link #setSelectedNavigationItem(int)}.</p>\r
+     *\r
+     * @param tab Tab to select\r
+     */\r
+    public abstract void selectTab(Tab tab);\r
+\r
+    /**\r
+     * Returns the currently selected tab if in tabbed navigation mode and there is at least\r
+     * one tab present.\r
+     *\r
+     * @return The currently selected tab or null\r
+     */\r
+    public abstract Tab getSelectedTab();\r
+\r
+    /**\r
+     * Returns the tab at the specified index.\r
+     *\r
+     * @param index Index value in the range 0-get\r
+     * @return\r
+     */\r
+    public abstract Tab getTabAt(int index);\r
+\r
+    /**\r
+     * Returns the number of tabs currently registered with the action bar.\r
+     * @return Tab count\r
+     */\r
+    public abstract int getTabCount();\r
+\r
+    /**\r
+     * Retrieve the current height of the ActionBar.\r
+     *\r
+     * @return The ActionBar's height\r
+     */\r
+    public abstract int getHeight();\r
+\r
+    /**\r
+     * Show the ActionBar if it is not currently showing.\r
+     * If the window hosting the ActionBar does not have the feature\r
+     * {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application\r
+     * content to fit the new space available.\r
+     */\r
+    public abstract void show();\r
+\r
+    /**\r
+     * Hide the ActionBar if it is currently showing.\r
+     * If the window hosting the ActionBar does not have the feature\r
+     * {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application\r
+     * content to fit the new space available.\r
+     */\r
+    public abstract void hide();\r
+\r
+    /**\r
+     * @return <code>true</code> if the ActionBar is showing, <code>false</code> otherwise.\r
+     */\r
+    public abstract boolean isShowing();\r
+\r
+    /**\r
+     * Add a listener that will respond to menu visibility change events.\r
+     *\r
+     * @param listener The new listener to add\r
+     */\r
+    public abstract void addOnMenuVisibilityListener(OnMenuVisibilityListener listener);\r
+\r
+    /**\r
+     * Remove a menu visibility listener. This listener will no longer receive menu\r
+     * visibility change events.\r
+     *\r
+     * @param listener A listener to remove that was previously added\r
+     */\r
+    public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener);\r
+\r
+    /**\r
+     * Enable or disable the "home" button in the corner of the action bar. (Note that this\r
+     * is the application home/up affordance on the action bar, not the systemwide home\r
+     * button.)\r
+     *\r
+     * <p>This defaults to true for packages targeting &lt; API 14. For packages targeting\r
+     * API 14 or greater, the application should call this method to enable interaction\r
+     * with the home/up affordance.\r
+     *\r
+     * <p>Setting the {@link #DISPLAY_HOME_AS_UP} display option will automatically enable\r
+     * the home button.\r
+     *\r
+     * @param enabled true to enable the home button, false to disable the home button.\r
+     */\r
+    public void setHomeButtonEnabled(boolean enabled) { }\r
+\r
+    /**\r
+     * Returns a {@link Context} with an appropriate theme for creating views that\r
+     * will appear in the action bar. If you are inflating or instantiating custom views\r
+     * that will appear in an action bar, you should use the Context returned by this method.\r
+     * (This includes adapters used for list navigation mode.)\r
+     * This will ensure that views contrast properly against the action bar.\r
+     *\r
+     * @return A themed Context for creating views\r
+     */\r
+    public Context getThemedContext() { return null; }\r
+\r
+    /**\r
+     * Listener interface for ActionBar navigation events.\r
+     */\r
+    public interface OnNavigationListener {\r
+        /**\r
+         * This method is called whenever a navigation item in your action bar\r
+         * is selected.\r
+         *\r
+         * @param itemPosition Position of the item clicked.\r
+         * @param itemId ID of the item clicked.\r
+         * @return True if the event was handled, false otherwise.\r
+         */\r
+        public boolean onNavigationItemSelected(int itemPosition, long itemId);\r
+    }\r
+\r
+    /**\r
+     * Listener for receiving events when action bar menus are shown or hidden.\r
+     */\r
+    public interface OnMenuVisibilityListener {\r
+        /**\r
+         * Called when an action bar menu is shown or hidden. Applications may want to use\r
+         * this to tune auto-hiding behavior for the action bar or pause/resume video playback,\r
+         * gameplay, or other activity within the main content area.\r
+         *\r
+         * @param isVisible True if an action bar menu is now visible, false if no action bar\r
+         *                  menus are visible.\r
+         */\r
+        public void onMenuVisibilityChanged(boolean isVisible);\r
+    }\r
+\r
+    /**\r
+     * A tab in the action bar.\r
+     *\r
+     * <p>Tabs manage the hiding and showing of {@link Fragment}s.\r
+     */\r
+    public static abstract class Tab {\r
+        /**\r
+         * An invalid position for a tab.\r
+         *\r
+         * @see #getPosition()\r
+         */\r
+        public static final int INVALID_POSITION = -1;\r
+\r
+        /**\r
+         * Return the current position of this tab in the action bar.\r
+         *\r
+         * @return Current position, or {@link #INVALID_POSITION} if this tab is not currently in\r
+         *         the action bar.\r
+         */\r
+        public abstract int getPosition();\r
+\r
+        /**\r
+         * Return the icon associated with this tab.\r
+         *\r
+         * @return The tab's icon\r
+         */\r
+        public abstract Drawable getIcon();\r
+\r
+        /**\r
+         * Return the text of this tab.\r
+         *\r
+         * @return The tab's text\r
+         */\r
+        public abstract CharSequence getText();\r
+\r
+        /**\r
+         * Set the icon displayed on this tab.\r
+         *\r
+         * @param icon The drawable to use as an icon\r
+         * @return The current instance for call chaining\r
+         */\r
+        public abstract Tab setIcon(Drawable icon);\r
+\r
+        /**\r
+         * Set the icon displayed on this tab.\r
+         *\r
+         * @param resId Resource ID referring to the drawable to use as an icon\r
+         * @return The current instance for call chaining\r
+         */\r
+        public abstract Tab setIcon(int resId);\r
+\r
+        /**\r
+         * Set the text displayed on this tab. Text may be truncated if there is not\r
+         * room to display the entire string.\r
+         *\r
+         * @param text The text to display\r
+         * @return The current instance for call chaining\r
+         */\r
+        public abstract Tab setText(CharSequence text);\r
+\r
+        /**\r
+         * Set the text displayed on this tab. Text may be truncated if there is not\r
+         * room to display the entire string.\r
+         *\r
+         * @param resId A resource ID referring to the text that should be displayed\r
+         * @return The current instance for call chaining\r
+         */\r
+        public abstract Tab setText(int resId);\r
+\r
+        /**\r
+         * Set a custom view to be used for this tab. This overrides values set by\r
+         * {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}.\r
+         *\r
+         * @param view Custom view to be used as a tab.\r
+         * @return The current instance for call chaining\r
+         */\r
+        public abstract Tab setCustomView(View view);\r
+\r
+        /**\r
+         * Set a custom view to be used for this tab. This overrides values set by\r
+         * {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}.\r
+         *\r
+         * @param layoutResId A layout resource to inflate and use as a custom tab view\r
+         * @return The current instance for call chaining\r
+         */\r
+        public abstract Tab setCustomView(int layoutResId);\r
+\r
+        /**\r
+         * Retrieve a previously set custom view for this tab.\r
+         *\r
+         * @return The custom view set by {@link #setCustomView(View)}.\r
+         */\r
+        public abstract View getCustomView();\r
+\r
+        /**\r
+         * Give this Tab an arbitrary object to hold for later use.\r
+         *\r
+         * @param obj Object to store\r
+         * @return The current instance for call chaining\r
+         */\r
+        public abstract Tab setTag(Object obj);\r
+\r
+        /**\r
+         * @return This Tab's tag object.\r
+         */\r
+        public abstract Object getTag();\r
+\r
+        /**\r
+         * Set the {@link TabListener} that will handle switching to and from this tab.\r
+         * All tabs must have a TabListener set before being added to the ActionBar.\r
+         *\r
+         * @param listener Listener to handle tab selection events\r
+         * @return The current instance for call chaining\r
+         */\r
+        public abstract Tab setTabListener(TabListener listener);\r
+\r
+        /**\r
+         * Select this tab. Only valid if the tab has been added to the action bar.\r
+         */\r
+        public abstract void select();\r
+\r
+        /**\r
+         * Set a description of this tab's content for use in accessibility support.\r
+         * If no content description is provided the title will be used.\r
+         *\r
+         * @param resId A resource ID referring to the description text\r
+         * @return The current instance for call chaining\r
+         * @see #setContentDescription(CharSequence)\r
+         * @see #getContentDescription()\r
+         */\r
+        public abstract Tab setContentDescription(int resId);\r
+\r
+        /**\r
+         * Set a description of this tab's content for use in accessibility support.\r
+         * If no content description is provided the title will be used.\r
+         *\r
+         * @param contentDesc Description of this tab's content\r
+         * @return The current instance for call chaining\r
+         * @see #setContentDescription(int)\r
+         * @see #getContentDescription()\r
+         */\r
+        public abstract Tab setContentDescription(CharSequence contentDesc);\r
+\r
+        /**\r
+         * Gets a brief description of this tab's content for use in accessibility support.\r
+         *\r
+         * @return Description of this tab's content\r
+         * @see #setContentDescription(CharSequence)\r
+         * @see #setContentDescription(int)\r
+         */\r
+        public abstract CharSequence getContentDescription();\r
+    }\r
+\r
+    /**\r
+     * Callback interface invoked when a tab is focused, unfocused, added, or removed.\r
+     */\r
+    public interface TabListener {\r
+        /**\r
+         * Called when a tab enters the selected state.\r
+         *\r
+         * @param tab The tab that was selected\r
+         * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute\r
+         *        during a tab switch. The previous tab's unselect and this tab's select will be\r
+         *        executed in a single transaction. This FragmentTransaction does not support\r
+         *        being added to the back stack.\r
+         */\r
+        public void onTabSelected(Tab tab, FragmentTransaction ft);\r
+\r
+        /**\r
+         * Called when a tab exits the selected state.\r
+         *\r
+         * @param tab The tab that was unselected\r
+         * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute\r
+         *        during a tab switch. This tab's unselect and the newly selected tab's select\r
+         *        will be executed in a single transaction. This FragmentTransaction does not\r
+         *        support being added to the back stack.\r
+         */\r
+        public void onTabUnselected(Tab tab, FragmentTransaction ft);\r
+\r
+        /**\r
+         * Called when a tab that is already selected is chosen again by the user.\r
+         * Some applications may use this action to return to the top level of a category.\r
+         *\r
+         * @param tab The tab that was reselected.\r
+         * @param ft A {@link FragmentTransaction} for queuing fragment operations to execute\r
+         *        once this method returns. This FragmentTransaction does not support\r
+         *        being added to the back stack.\r
+         */\r
+        public void onTabReselected(Tab tab, FragmentTransaction ft);\r
+    }\r
+\r
+    /**\r
+     * Per-child layout information associated with action bar custom views.\r
+     *\r
+     * @attr ref android.R.styleable#ActionBar_LayoutParams_layout_gravity\r
+     */\r
+    public static class LayoutParams extends MarginLayoutParams {\r
+        /**\r
+         * Gravity for the view associated with these LayoutParams.\r
+         *\r
+         * @see android.view.Gravity\r
+         */\r
+        @ViewDebug.ExportedProperty(mapping = {\r
+            @ViewDebug.IntToString(from =  -1,                       to = "NONE"),\r
+            @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),\r
+            @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),\r
+            @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),\r
+            @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),\r
+            @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),\r
+            @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),\r
+            @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),\r
+            @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),\r
+            @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),\r
+            @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),\r
+            @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")\r
+        })\r
+        public int gravity = -1;\r
+\r
+        public LayoutParams(Context c, AttributeSet attrs) {\r
+            super(c, attrs);\r
+        }\r
+\r
+        public LayoutParams(int width, int height) {\r
+            super(width, height);\r
+            this.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;\r
+        }\r
+\r
+        public LayoutParams(int width, int height, int gravity) {\r
+            super(width, height);\r
+            this.gravity = gravity;\r
+        }\r
+\r
+        public LayoutParams(int gravity) {\r
+            this(WRAP_CONTENT, FILL_PARENT, gravity);\r
+        }\r
+\r
+        public LayoutParams(LayoutParams source) {\r
+            super(source);\r
+\r
+            this.gravity = source.gravity;\r
+        }\r
+\r
+        public LayoutParams(ViewGroup.LayoutParams source) {\r
+            super(source);\r
+        }\r
+    }\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockActivity.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockActivity.java
new file mode 100644 (file)
index 0000000..9cb57e9
--- /dev/null
@@ -0,0 +1,259 @@
+package com.actionbarsherlock.app;\r
+\r
+import android.app.Activity;\r
+import android.content.res.Configuration;\r
+import android.os.Bundle;\r
+import android.view.KeyEvent;\r
+import android.view.View;\r
+import android.view.Window;\r
+import android.view.ViewGroup.LayoutParams;\r
+import com.actionbarsherlock.ActionBarSherlock;\r
+import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;\r
+import com.actionbarsherlock.view.ActionMode;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+public abstract class SherlockActivity extends Activity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {\r
+    private ActionBarSherlock mSherlock;\r
+\r
+    protected final ActionBarSherlock getSherlock() {\r
+        if (mSherlock == null) {\r
+            mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);\r
+        }\r
+        return mSherlock;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Action bar and mode\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public ActionBar getSupportActionBar() {\r
+        return getSherlock().getActionBar();\r
+    }\r
+\r
+    public ActionMode startActionMode(ActionMode.Callback callback) {\r
+        return getSherlock().startActionMode(callback);\r
+    }\r
+\r
+    @Override\r
+    public void onActionModeStarted(ActionMode mode) {}\r
+\r
+    @Override\r
+    public void onActionModeFinished(ActionMode mode) {}\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // General lifecycle/callback dispatching\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public void onConfigurationChanged(Configuration newConfig) {\r
+        super.onConfigurationChanged(newConfig);\r
+        getSherlock().dispatchConfigurationChanged(newConfig);\r
+    }\r
+\r
+    @Override\r
+    protected void onPostResume() {\r
+        super.onPostResume();\r
+        getSherlock().dispatchPostResume();\r
+    }\r
+\r
+    @Override\r
+    protected void onPause() {\r
+        getSherlock().dispatchPause();\r
+        super.onPause();\r
+    }\r
+\r
+    @Override\r
+    protected void onStop() {\r
+        getSherlock().dispatchStop();\r
+        super.onStop();\r
+    }\r
+\r
+    @Override\r
+    protected void onDestroy() {\r
+        getSherlock().dispatchDestroy();\r
+        super.onDestroy();\r
+    }\r
+\r
+    @Override\r
+    protected void onPostCreate(Bundle savedInstanceState) {\r
+        getSherlock().dispatchPostCreate(savedInstanceState);\r
+        super.onPostCreate(savedInstanceState);\r
+    }\r
+\r
+    @Override\r
+    protected void onTitleChanged(CharSequence title, int color) {\r
+        getSherlock().dispatchTitleChanged(title, color);\r
+        super.onTitleChanged(title, color);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onMenuOpened(int featureId, android.view.Menu menu) {\r
+        if (getSherlock().dispatchMenuOpened(featureId, menu)) {\r
+            return true;\r
+        }\r
+        return super.onMenuOpened(featureId, menu);\r
+    }\r
+\r
+    @Override\r
+    public void onPanelClosed(int featureId, android.view.Menu menu) {\r
+        getSherlock().dispatchPanelClosed(featureId, menu);\r
+        super.onPanelClosed(featureId, menu);\r
+    }\r
+\r
+    @Override\r
+    public boolean dispatchKeyEvent(KeyEvent event) {\r
+        if (getSherlock().dispatchKeyEvent(event)) {\r
+            return true;\r
+        }\r
+        return super.dispatchKeyEvent(event);\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Native menu handling\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public MenuInflater getSupportMenuInflater() {\r
+        return getSherlock().getMenuInflater();\r
+    }\r
+\r
+    public void invalidateOptionsMenu() {\r
+        getSherlock().dispatchInvalidateOptionsMenu();\r
+    }\r
+\r
+    public void supportInvalidateOptionsMenu() {\r
+        invalidateOptionsMenu();\r
+    }\r
+\r
+    @Override\r
+    public final boolean onCreateOptionsMenu(android.view.Menu menu) {\r
+        return getSherlock().dispatchCreateOptionsMenu(menu);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onPrepareOptionsMenu(android.view.Menu menu) {\r
+        return getSherlock().dispatchPrepareOptionsMenu(menu);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onOptionsItemSelected(android.view.MenuItem item) {\r
+        return getSherlock().dispatchOptionsItemSelected(item);\r
+    }\r
+\r
+    @Override\r
+    public void openOptionsMenu() {\r
+        if (!getSherlock().dispatchOpenOptionsMenu()) {\r
+            super.openOptionsMenu();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void closeOptionsMenu() {\r
+        if (!getSherlock().dispatchCloseOptionsMenu()) {\r
+            super.closeOptionsMenu();\r
+        }\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Sherlock menu handling\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onCreateOptionsMenu(menu);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onCreateOptionsMenu(Menu menu) {\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public boolean onPreparePanel(int featureId, View view, Menu menu) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onPrepareOptionsMenu(menu);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onPrepareOptionsMenu(Menu menu) {\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onOptionsItemSelected(item);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onOptionsItemSelected(MenuItem item) {\r
+        return false;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Content\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public void addContentView(View view, LayoutParams params) {\r
+        getSherlock().addContentView(view, params);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(int layoutResId) {\r
+        getSherlock().setContentView(layoutResId);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(View view, LayoutParams params) {\r
+        getSherlock().setContentView(view, params);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(View view) {\r
+        getSherlock().setContentView(view);\r
+    }\r
+\r
+    public void requestWindowFeature(long featureId) {\r
+        getSherlock().requestFeature((int)featureId);\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Progress Indication\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public void setSupportProgress(int progress) {\r
+        getSherlock().setProgress(progress);\r
+    }\r
+\r
+    public void setSupportProgressBarIndeterminate(boolean indeterminate) {\r
+        getSherlock().setProgressBarIndeterminate(indeterminate);\r
+    }\r
+\r
+    public void setSupportProgressBarIndeterminateVisibility(boolean visible) {\r
+        getSherlock().setProgressBarIndeterminateVisibility(visible);\r
+    }\r
+\r
+    public void setSupportProgressBarVisibility(boolean visible) {\r
+        getSherlock().setProgressBarVisibility(visible);\r
+    }\r
+\r
+    public void setSupportSecondaryProgress(int secondaryProgress) {\r
+        getSherlock().setSecondaryProgress(secondaryProgress);\r
+    }\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockDialogFragment.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockDialogFragment.java
new file mode 100644 (file)
index 0000000..a7c856b
--- /dev/null
@@ -0,0 +1,68 @@
+package com.actionbarsherlock.app;
+
+import android.app.Activity;
+import android.support.v4.app.DialogFragment;
+import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
+import com.actionbarsherlock.internal.view.menu.MenuWrapper;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener;
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener;
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener;
+
+public class SherlockDialogFragment extends DialogFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
+    private SherlockFragmentActivity mActivity;
+
+    public SherlockFragmentActivity getSherlockActivity() {
+        return mActivity;
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        if (!(activity instanceof SherlockFragmentActivity)) {
+            throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
+        }
+        mActivity = (SherlockFragmentActivity)activity;
+
+        super.onAttach(activity);
+    }
+
+    @Override
+    public void onDetach() {
+        mActivity = null;
+        super.onDetach();
+    }
+
+    @Override
+    public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
+        onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        //Nothing to see here.
+    }
+
+    @Override
+    public final void onPrepareOptionsMenu(android.view.Menu menu) {
+        onPrepareOptionsMenu(new MenuWrapper(menu));
+    }
+
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        //Nothing to see here.
+    }
+
+    @Override
+    public final boolean onOptionsItemSelected(android.view.MenuItem item) {
+        return onOptionsItemSelected(new MenuItemWrapper(item));
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        //Nothing to see here.
+        return false;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockExpandableListActivity.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockExpandableListActivity.java
new file mode 100644 (file)
index 0000000..078f9b0
--- /dev/null
@@ -0,0 +1,259 @@
+package com.actionbarsherlock.app;\r
+\r
+import android.app.ExpandableListActivity;\r
+import android.content.res.Configuration;\r
+import android.os.Bundle;\r
+import android.view.KeyEvent;\r
+import android.view.View;\r
+import android.view.ViewGroup.LayoutParams;\r
+import android.view.Window;\r
+import com.actionbarsherlock.ActionBarSherlock;\r
+import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;\r
+import com.actionbarsherlock.view.ActionMode;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+public abstract class SherlockExpandableListActivity extends ExpandableListActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {\r
+    private ActionBarSherlock mSherlock;\r
+\r
+    protected final ActionBarSherlock getSherlock() {\r
+        if (mSherlock == null) {\r
+            mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);\r
+        }\r
+        return mSherlock;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Action bar and mode\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public ActionBar getSupportActionBar() {\r
+        return getSherlock().getActionBar();\r
+    }\r
+\r
+    public ActionMode startActionMode(ActionMode.Callback callback) {\r
+        return getSherlock().startActionMode(callback);\r
+    }\r
+\r
+    @Override\r
+    public void onActionModeStarted(ActionMode mode) {}\r
+\r
+    @Override\r
+    public void onActionModeFinished(ActionMode mode) {}\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // General lifecycle/callback dispatching\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public void onConfigurationChanged(Configuration newConfig) {\r
+        super.onConfigurationChanged(newConfig);\r
+        getSherlock().dispatchConfigurationChanged(newConfig);\r
+    }\r
+\r
+    @Override\r
+    protected void onPostResume() {\r
+        super.onPostResume();\r
+        getSherlock().dispatchPostResume();\r
+    }\r
+\r
+    @Override\r
+    protected void onPause() {\r
+        getSherlock().dispatchPause();\r
+        super.onPause();\r
+    }\r
+\r
+    @Override\r
+    protected void onStop() {\r
+        getSherlock().dispatchStop();\r
+        super.onStop();\r
+    }\r
+\r
+    @Override\r
+    protected void onDestroy() {\r
+        getSherlock().dispatchDestroy();\r
+        super.onDestroy();\r
+    }\r
+\r
+    @Override\r
+    protected void onPostCreate(Bundle savedInstanceState) {\r
+        getSherlock().dispatchPostCreate(savedInstanceState);\r
+        super.onPostCreate(savedInstanceState);\r
+    }\r
+\r
+    @Override\r
+    protected void onTitleChanged(CharSequence title, int color) {\r
+        getSherlock().dispatchTitleChanged(title, color);\r
+        super.onTitleChanged(title, color);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onMenuOpened(int featureId, android.view.Menu menu) {\r
+        if (getSherlock().dispatchMenuOpened(featureId, menu)) {\r
+            return true;\r
+        }\r
+        return super.onMenuOpened(featureId, menu);\r
+    }\r
+\r
+    @Override\r
+    public void onPanelClosed(int featureId, android.view.Menu menu) {\r
+        getSherlock().dispatchPanelClosed(featureId, menu);\r
+        super.onPanelClosed(featureId, menu);\r
+    }\r
+\r
+    @Override\r
+    public boolean dispatchKeyEvent(KeyEvent event) {\r
+        if (getSherlock().dispatchKeyEvent(event)) {\r
+            return true;\r
+        }\r
+        return super.dispatchKeyEvent(event);\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Native menu handling\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public MenuInflater getSupportMenuInflater() {\r
+        return getSherlock().getMenuInflater();\r
+    }\r
+\r
+    public void invalidateOptionsMenu() {\r
+        getSherlock().dispatchInvalidateOptionsMenu();\r
+    }\r
+\r
+    public void supportInvalidateOptionsMenu() {\r
+        invalidateOptionsMenu();\r
+    }\r
+\r
+    @Override\r
+    public final boolean onCreateOptionsMenu(android.view.Menu menu) {\r
+        return getSherlock().dispatchCreateOptionsMenu(menu);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onPrepareOptionsMenu(android.view.Menu menu) {\r
+        return getSherlock().dispatchPrepareOptionsMenu(menu);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onOptionsItemSelected(android.view.MenuItem item) {\r
+        return getSherlock().dispatchOptionsItemSelected(item);\r
+    }\r
+\r
+    @Override\r
+    public void openOptionsMenu() {\r
+        if (!getSherlock().dispatchOpenOptionsMenu()) {\r
+            super.openOptionsMenu();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void closeOptionsMenu() {\r
+        if (!getSherlock().dispatchCloseOptionsMenu()) {\r
+            super.closeOptionsMenu();\r
+        }\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Sherlock menu handling\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onCreateOptionsMenu(menu);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onCreateOptionsMenu(Menu menu) {\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public boolean onPreparePanel(int featureId, View view, Menu menu) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onPrepareOptionsMenu(menu);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onPrepareOptionsMenu(Menu menu) {\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onOptionsItemSelected(item);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onOptionsItemSelected(MenuItem item) {\r
+        return false;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Content\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public void addContentView(View view, LayoutParams params) {\r
+        getSherlock().addContentView(view, params);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(int layoutResId) {\r
+        getSherlock().setContentView(layoutResId);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(View view, LayoutParams params) {\r
+        getSherlock().setContentView(view, params);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(View view) {\r
+        getSherlock().setContentView(view);\r
+    }\r
+\r
+    public void requestWindowFeature(long featureId) {\r
+        getSherlock().requestFeature((int)featureId);\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Progress Indication\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public void setSupportProgress(int progress) {\r
+        getSherlock().setProgress(progress);\r
+    }\r
+\r
+    public void setSupportProgressBarIndeterminate(boolean indeterminate) {\r
+        getSherlock().setProgressBarIndeterminate(indeterminate);\r
+    }\r
+\r
+    public void setSupportProgressBarIndeterminateVisibility(boolean visible) {\r
+        getSherlock().setProgressBarIndeterminateVisibility(visible);\r
+    }\r
+\r
+    public void setSupportProgressBarVisibility(boolean visible) {\r
+        getSherlock().setProgressBarVisibility(visible);\r
+    }\r
+\r
+    public void setSupportSecondaryProgress(int secondaryProgress) {\r
+        getSherlock().setSecondaryProgress(secondaryProgress);\r
+    }\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockFragment.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockFragment.java
new file mode 100644 (file)
index 0000000..0f24e9c
--- /dev/null
@@ -0,0 +1,68 @@
+package com.actionbarsherlock.app;
+
+import android.app.Activity;
+import android.support.v4.app.Fragment;
+import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
+import com.actionbarsherlock.internal.view.menu.MenuWrapper;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener;
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener;
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener;
+
+public class SherlockFragment extends Fragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
+    private SherlockFragmentActivity mActivity;
+
+    public SherlockFragmentActivity getSherlockActivity() {
+        return mActivity;
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        if (!(activity instanceof SherlockFragmentActivity)) {
+            throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
+        }
+        mActivity = (SherlockFragmentActivity)activity;
+
+        super.onAttach(activity);
+    }
+
+    @Override
+    public void onDetach() {
+        mActivity = null;
+        super.onDetach();
+    }
+
+    @Override
+    public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
+        onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        //Nothing to see here.
+    }
+
+    @Override
+    public final void onPrepareOptionsMenu(android.view.Menu menu) {
+        onPrepareOptionsMenu(new MenuWrapper(menu));
+    }
+
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        //Nothing to see here.
+    }
+
+    @Override
+    public final boolean onOptionsItemSelected(android.view.MenuItem item) {
+        return onOptionsItemSelected(new MenuItemWrapper(item));
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        //Nothing to see here.
+        return false;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockFragmentActivity.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockFragmentActivity.java
new file mode 100644 (file)
index 0000000..5cd13ba
--- /dev/null
@@ -0,0 +1,292 @@
+package com.actionbarsherlock.app;
+
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.support.v4.app._ActionBarSherlockTrojanHorse;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.Window;
+import com.actionbarsherlock.ActionBarSherlock;
+import com.actionbarsherlock.view.ActionMode;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+
+import static com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
+import static com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
+
+/** @see {@link _ActionBarSherlockTrojanHorse} */
+public class SherlockFragmentActivity extends _ActionBarSherlockTrojanHorse implements OnActionModeStartedListener, OnActionModeFinishedListener {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "SherlockFragmentActivity";
+
+    private ActionBarSherlock mSherlock;
+    private boolean mIgnoreNativeCreate = false;
+    private boolean mIgnoreNativePrepare = false;
+    private boolean mIgnoreNativeSelected = false;
+
+    protected final ActionBarSherlock getSherlock() {
+        if (mSherlock == null) {
+            mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
+        }
+        return mSherlock;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Action bar and mode
+    ///////////////////////////////////////////////////////////////////////////
+
+    public ActionBar getSupportActionBar() {
+        return getSherlock().getActionBar();
+    }
+
+    public ActionMode startActionMode(ActionMode.Callback callback) {
+        return getSherlock().startActionMode(callback);
+    }
+
+    @Override
+    public void onActionModeStarted(ActionMode mode) {}
+
+    @Override
+    public void onActionModeFinished(ActionMode mode) {}
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // General lifecycle/callback dispatching
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        getSherlock().dispatchConfigurationChanged(newConfig);
+    }
+
+    @Override
+    protected void onPostResume() {
+        super.onPostResume();
+        getSherlock().dispatchPostResume();
+    }
+
+    @Override
+    protected void onPause() {
+        getSherlock().dispatchPause();
+        super.onPause();
+    }
+
+    @Override
+    protected void onStop() {
+        getSherlock().dispatchStop();
+        super.onStop();
+    }
+
+    @Override
+    protected void onDestroy() {
+        getSherlock().dispatchDestroy();
+        super.onDestroy();
+    }
+
+    @Override
+    protected void onPostCreate(Bundle savedInstanceState) {
+        getSherlock().dispatchPostCreate(savedInstanceState);
+        super.onPostCreate(savedInstanceState);
+    }
+
+    @Override
+    protected void onTitleChanged(CharSequence title, int color) {
+        getSherlock().dispatchTitleChanged(title, color);
+        super.onTitleChanged(title, color);
+    }
+
+    @Override
+    public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
+        if (getSherlock().dispatchMenuOpened(featureId, menu)) {
+            return true;
+        }
+        return super.onMenuOpened(featureId, menu);
+    }
+
+    @Override
+    public void onPanelClosed(int featureId, android.view.Menu menu) {
+        getSherlock().dispatchPanelClosed(featureId, menu);
+        super.onPanelClosed(featureId, menu);
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (getSherlock().dispatchKeyEvent(event)) {
+            return true;
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Native menu handling
+    ///////////////////////////////////////////////////////////////////////////
+
+    public MenuInflater getSupportMenuInflater() {
+        if (DEBUG) Log.d(TAG, "[getSupportMenuInflater]");
+
+        return getSherlock().getMenuInflater();
+    }
+
+    public void invalidateOptionsMenu() {
+        if (DEBUG) Log.d(TAG, "[invalidateOptionsMenu]");
+
+        getSherlock().dispatchInvalidateOptionsMenu();
+    }
+
+    public void supportInvalidateOptionsMenu() {
+        if (DEBUG) Log.d(TAG, "[supportInvalidateOptionsMenu]");
+
+        invalidateOptionsMenu();
+    }
+
+    @Override
+    public final boolean onCreatePanelMenu(int featureId, android.view.Menu menu) {
+        if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] featureId: " + featureId + ", menu: " + menu);
+
+        if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativeCreate) {
+            mIgnoreNativeCreate = true;
+            boolean result = getSherlock().dispatchCreateOptionsMenu(menu);
+            mIgnoreNativeCreate = false;
+
+            if (DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result);
+            return result;
+        }
+        return super.onCreatePanelMenu(featureId, menu);
+    }
+
+    @Override
+    public final boolean onCreateOptionsMenu(android.view.Menu menu) {
+        return true;
+    }
+
+    @Override
+    public final boolean onPreparePanel(int featureId, View view, android.view.Menu menu) {
+        if (DEBUG) Log.d(TAG, "[onPreparePanel] featureId: " + featureId + ", view: " + view + ", menu: " + menu);
+
+        if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativePrepare) {
+            mIgnoreNativePrepare = true;
+            boolean result = getSherlock().dispatchPrepareOptionsMenu(menu);
+            mIgnoreNativePrepare = false;
+
+            if (DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result);
+            return result;
+        }
+        return super.onPreparePanel(featureId, view, menu);
+    }
+
+    @Override
+    public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
+        return true;
+    }
+
+    @Override
+    public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) {
+        if (DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item);
+
+        if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativeSelected) {
+            mIgnoreNativeSelected = true;
+            boolean result = getSherlock().dispatchOptionsItemSelected(item);
+            mIgnoreNativeSelected = false;
+
+            if (DEBUG) Log.d(TAG, "[onMenuItemSelected] returning " + result);
+            return result;
+        }
+        return super.onMenuItemSelected(featureId, item);
+    }
+
+    @Override
+    public final boolean onOptionsItemSelected(android.view.MenuItem item) {
+        return false;
+    }
+
+    @Override
+    public void openOptionsMenu() {
+        if (!getSherlock().dispatchOpenOptionsMenu()) {
+            super.openOptionsMenu();
+        }
+    }
+
+    @Override
+    public void closeOptionsMenu() {
+        if (!getSherlock().dispatchCloseOptionsMenu()) {
+            super.closeOptionsMenu();
+        }
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Sherlock menu handling
+    ///////////////////////////////////////////////////////////////////////////
+
+    public boolean onCreateOptionsMenu(Menu menu) {
+        return true;
+    }
+
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        return true;
+    }
+
+    public boolean onOptionsItemSelected(MenuItem item) {
+        return false;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Content
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void addContentView(View view, LayoutParams params) {
+        getSherlock().addContentView(view, params);
+    }
+
+    @Override
+    public void setContentView(int layoutResId) {
+        getSherlock().setContentView(layoutResId);
+    }
+
+    @Override
+    public void setContentView(View view, LayoutParams params) {
+        getSherlock().setContentView(view, params);
+    }
+
+    @Override
+    public void setContentView(View view) {
+        getSherlock().setContentView(view);
+    }
+
+    public void requestWindowFeature(long featureId) {
+        getSherlock().requestFeature((int)featureId);
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Progress Indication
+    ///////////////////////////////////////////////////////////////////////////
+
+    public void setSupportProgress(int progress) {
+        getSherlock().setProgress(progress);
+    }
+
+    public void setSupportProgressBarIndeterminate(boolean indeterminate) {
+        getSherlock().setProgressBarIndeterminate(indeterminate);
+    }
+
+    public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
+        getSherlock().setProgressBarIndeterminateVisibility(visible);
+    }
+
+    public void setSupportProgressBarVisibility(boolean visible) {
+        getSherlock().setProgressBarVisibility(visible);
+    }
+
+    public void setSupportSecondaryProgress(int secondaryProgress) {
+        getSherlock().setSecondaryProgress(secondaryProgress);
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockListActivity.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockListActivity.java
new file mode 100644 (file)
index 0000000..00c00fe
--- /dev/null
@@ -0,0 +1,259 @@
+package com.actionbarsherlock.app;\r
+\r
+import android.app.ListActivity;\r
+import android.content.res.Configuration;\r
+import android.os.Bundle;\r
+import android.view.KeyEvent;\r
+import android.view.View;\r
+import android.view.Window;\r
+import android.view.ViewGroup.LayoutParams;\r
+import com.actionbarsherlock.ActionBarSherlock;\r
+import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;\r
+import com.actionbarsherlock.view.ActionMode;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+public abstract class SherlockListActivity extends ListActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {\r
+    private ActionBarSherlock mSherlock;\r
+\r
+    protected final ActionBarSherlock getSherlock() {\r
+        if (mSherlock == null) {\r
+            mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);\r
+        }\r
+        return mSherlock;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Action bar and mode\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public ActionBar getSupportActionBar() {\r
+        return getSherlock().getActionBar();\r
+    }\r
+\r
+    public ActionMode startActionMode(ActionMode.Callback callback) {\r
+        return getSherlock().startActionMode(callback);\r
+    }\r
+\r
+    @Override\r
+    public void onActionModeStarted(ActionMode mode) {}\r
+\r
+    @Override\r
+    public void onActionModeFinished(ActionMode mode) {}\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // General lifecycle/callback dispatching\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public void onConfigurationChanged(Configuration newConfig) {\r
+        super.onConfigurationChanged(newConfig);\r
+        getSherlock().dispatchConfigurationChanged(newConfig);\r
+    }\r
+\r
+    @Override\r
+    protected void onPostResume() {\r
+        super.onPostResume();\r
+        getSherlock().dispatchPostResume();\r
+    }\r
+\r
+    @Override\r
+    protected void onPause() {\r
+        getSherlock().dispatchPause();\r
+        super.onPause();\r
+    }\r
+\r
+    @Override\r
+    protected void onStop() {\r
+        getSherlock().dispatchStop();\r
+        super.onStop();\r
+    }\r
+\r
+    @Override\r
+    protected void onDestroy() {\r
+        getSherlock().dispatchDestroy();\r
+        super.onDestroy();\r
+    }\r
+\r
+    @Override\r
+    protected void onPostCreate(Bundle savedInstanceState) {\r
+        getSherlock().dispatchPostCreate(savedInstanceState);\r
+        super.onPostCreate(savedInstanceState);\r
+    }\r
+\r
+    @Override\r
+    protected void onTitleChanged(CharSequence title, int color) {\r
+        getSherlock().dispatchTitleChanged(title, color);\r
+        super.onTitleChanged(title, color);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onMenuOpened(int featureId, android.view.Menu menu) {\r
+        if (getSherlock().dispatchMenuOpened(featureId, menu)) {\r
+            return true;\r
+        }\r
+        return super.onMenuOpened(featureId, menu);\r
+    }\r
+\r
+    @Override\r
+    public void onPanelClosed(int featureId, android.view.Menu menu) {\r
+        getSherlock().dispatchPanelClosed(featureId, menu);\r
+        super.onPanelClosed(featureId, menu);\r
+    }\r
+\r
+    @Override\r
+    public boolean dispatchKeyEvent(KeyEvent event) {\r
+        if (getSherlock().dispatchKeyEvent(event)) {\r
+            return true;\r
+        }\r
+        return super.dispatchKeyEvent(event);\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Native menu handling\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public MenuInflater getSupportMenuInflater() {\r
+        return getSherlock().getMenuInflater();\r
+    }\r
+\r
+    public void invalidateOptionsMenu() {\r
+        getSherlock().dispatchInvalidateOptionsMenu();\r
+    }\r
+\r
+    public void supportInvalidateOptionsMenu() {\r
+        invalidateOptionsMenu();\r
+    }\r
+\r
+    @Override\r
+    public final boolean onCreateOptionsMenu(android.view.Menu menu) {\r
+        return getSherlock().dispatchCreateOptionsMenu(menu);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onPrepareOptionsMenu(android.view.Menu menu) {\r
+        return getSherlock().dispatchPrepareOptionsMenu(menu);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onOptionsItemSelected(android.view.MenuItem item) {\r
+        return getSherlock().dispatchOptionsItemSelected(item);\r
+    }\r
+\r
+    @Override\r
+    public void openOptionsMenu() {\r
+        if (!getSherlock().dispatchOpenOptionsMenu()) {\r
+            super.openOptionsMenu();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void closeOptionsMenu() {\r
+        if (!getSherlock().dispatchCloseOptionsMenu()) {\r
+            super.closeOptionsMenu();\r
+        }\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Sherlock menu handling\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onCreateOptionsMenu(menu);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onCreateOptionsMenu(Menu menu) {\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public boolean onPreparePanel(int featureId, View view, Menu menu) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onPrepareOptionsMenu(menu);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onPrepareOptionsMenu(Menu menu) {\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onOptionsItemSelected(item);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onOptionsItemSelected(MenuItem item) {\r
+        return false;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Content\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public void addContentView(View view, LayoutParams params) {\r
+        getSherlock().addContentView(view, params);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(int layoutResId) {\r
+        getSherlock().setContentView(layoutResId);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(View view, LayoutParams params) {\r
+        getSherlock().setContentView(view, params);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(View view) {\r
+        getSherlock().setContentView(view);\r
+    }\r
+\r
+    public void requestWindowFeature(long featureId) {\r
+        getSherlock().requestFeature((int)featureId);\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Progress Indication\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public void setSupportProgress(int progress) {\r
+        getSherlock().setProgress(progress);\r
+    }\r
+\r
+    public void setSupportProgressBarIndeterminate(boolean indeterminate) {\r
+        getSherlock().setProgressBarIndeterminate(indeterminate);\r
+    }\r
+\r
+    public void setSupportProgressBarIndeterminateVisibility(boolean visible) {\r
+        getSherlock().setProgressBarIndeterminateVisibility(visible);\r
+    }\r
+\r
+    public void setSupportProgressBarVisibility(boolean visible) {\r
+        getSherlock().setProgressBarVisibility(visible);\r
+    }\r
+\r
+    public void setSupportSecondaryProgress(int secondaryProgress) {\r
+        getSherlock().setSecondaryProgress(secondaryProgress);\r
+    }\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockListFragment.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockListFragment.java
new file mode 100644 (file)
index 0000000..13ca3c4
--- /dev/null
@@ -0,0 +1,68 @@
+package com.actionbarsherlock.app;
+
+import android.app.Activity;
+import android.support.v4.app.ListFragment;
+import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
+import com.actionbarsherlock.internal.view.menu.MenuWrapper;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnCreateOptionsMenuListener;
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnOptionsItemSelectedListener;
+import static com.actionbarsherlock.app.SherlockFragmentActivity.OnPrepareOptionsMenuListener;
+
+public class SherlockListFragment extends ListFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
+    private SherlockFragmentActivity mActivity;
+
+    public SherlockFragmentActivity getSherlockActivity() {
+        return mActivity;
+    }
+
+    @Override
+    public void onAttach(Activity activity) {
+        if (!(activity instanceof SherlockFragmentActivity)) {
+            throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
+        }
+        mActivity = (SherlockFragmentActivity)activity;
+
+        super.onAttach(activity);
+    }
+
+    @Override
+    public void onDetach() {
+        mActivity = null;
+        super.onDetach();
+    }
+
+    @Override
+    public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
+        onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
+    }
+
+    @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        //Nothing to see here.
+    }
+
+    @Override
+    public final void onPrepareOptionsMenu(android.view.Menu menu) {
+        onPrepareOptionsMenu(new MenuWrapper(menu));
+    }
+
+    @Override
+    public void onPrepareOptionsMenu(Menu menu) {
+        //Nothing to see here.
+    }
+
+    @Override
+    public final boolean onOptionsItemSelected(android.view.MenuItem item) {
+        return onOptionsItemSelected(new MenuItemWrapper(item));
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        //Nothing to see here.
+        return false;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockPreferenceActivity.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/app/SherlockPreferenceActivity.java
new file mode 100644 (file)
index 0000000..4f80be5
--- /dev/null
@@ -0,0 +1,259 @@
+package com.actionbarsherlock.app;\r
+\r
+import android.content.res.Configuration;\r
+import android.os.Bundle;\r
+import android.preference.PreferenceActivity;\r
+import android.view.KeyEvent;\r
+import android.view.View;\r
+import android.view.ViewGroup.LayoutParams;\r
+import android.view.Window;\r
+import com.actionbarsherlock.ActionBarSherlock;\r
+import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;\r
+import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;\r
+import com.actionbarsherlock.view.ActionMode;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+public abstract class SherlockPreferenceActivity extends PreferenceActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {\r
+    private ActionBarSherlock mSherlock;\r
+\r
+    protected final ActionBarSherlock getSherlock() {\r
+        if (mSherlock == null) {\r
+            mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);\r
+        }\r
+        return mSherlock;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Action bar and mode\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public ActionBar getSupportActionBar() {\r
+        return getSherlock().getActionBar();\r
+    }\r
+\r
+    public ActionMode startActionMode(ActionMode.Callback callback) {\r
+        return getSherlock().startActionMode(callback);\r
+    }\r
+\r
+    @Override\r
+    public void onActionModeStarted(ActionMode mode) {}\r
+\r
+    @Override\r
+    public void onActionModeFinished(ActionMode mode) {}\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // General lifecycle/callback dispatching\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public void onConfigurationChanged(Configuration newConfig) {\r
+        super.onConfigurationChanged(newConfig);\r
+        getSherlock().dispatchConfigurationChanged(newConfig);\r
+    }\r
+\r
+    @Override\r
+    protected void onPostResume() {\r
+        super.onPostResume();\r
+        getSherlock().dispatchPostResume();\r
+    }\r
+\r
+    @Override\r
+    protected void onPause() {\r
+        getSherlock().dispatchPause();\r
+        super.onPause();\r
+    }\r
+\r
+    @Override\r
+    protected void onStop() {\r
+        getSherlock().dispatchStop();\r
+        super.onStop();\r
+    }\r
+\r
+    @Override\r
+    protected void onDestroy() {\r
+        getSherlock().dispatchDestroy();\r
+        super.onDestroy();\r
+    }\r
+\r
+    @Override\r
+    protected void onPostCreate(Bundle savedInstanceState) {\r
+        getSherlock().dispatchPostCreate(savedInstanceState);\r
+        super.onPostCreate(savedInstanceState);\r
+    }\r
+\r
+    @Override\r
+    protected void onTitleChanged(CharSequence title, int color) {\r
+        getSherlock().dispatchTitleChanged(title, color);\r
+        super.onTitleChanged(title, color);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onMenuOpened(int featureId, android.view.Menu menu) {\r
+        if (getSherlock().dispatchMenuOpened(featureId, menu)) {\r
+            return true;\r
+        }\r
+        return super.onMenuOpened(featureId, menu);\r
+    }\r
+\r
+    @Override\r
+    public void onPanelClosed(int featureId, android.view.Menu menu) {\r
+        getSherlock().dispatchPanelClosed(featureId, menu);\r
+        super.onPanelClosed(featureId, menu);\r
+    }\r
+\r
+    @Override\r
+    public boolean dispatchKeyEvent(KeyEvent event) {\r
+        if (getSherlock().dispatchKeyEvent(event)) {\r
+            return true;\r
+        }\r
+        return super.dispatchKeyEvent(event);\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Native menu handling\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public MenuInflater getSupportMenuInflater() {\r
+        return getSherlock().getMenuInflater();\r
+    }\r
+\r
+    public void invalidateOptionsMenu() {\r
+        getSherlock().dispatchInvalidateOptionsMenu();\r
+    }\r
+\r
+    public void supportInvalidateOptionsMenu() {\r
+        invalidateOptionsMenu();\r
+    }\r
+\r
+    @Override\r
+    public final boolean onCreateOptionsMenu(android.view.Menu menu) {\r
+        return getSherlock().dispatchCreateOptionsMenu(menu);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onPrepareOptionsMenu(android.view.Menu menu) {\r
+        return getSherlock().dispatchPrepareOptionsMenu(menu);\r
+    }\r
+\r
+    @Override\r
+    public final boolean onOptionsItemSelected(android.view.MenuItem item) {\r
+        return getSherlock().dispatchOptionsItemSelected(item);\r
+    }\r
+\r
+    @Override\r
+    public void openOptionsMenu() {\r
+        if (!getSherlock().dispatchOpenOptionsMenu()) {\r
+            super.openOptionsMenu();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public void closeOptionsMenu() {\r
+        if (!getSherlock().dispatchCloseOptionsMenu()) {\r
+            super.closeOptionsMenu();\r
+        }\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Sherlock menu handling\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public boolean onCreatePanelMenu(int featureId, Menu menu) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onCreateOptionsMenu(menu);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onCreateOptionsMenu(Menu menu) {\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public boolean onPreparePanel(int featureId, View view, Menu menu) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onPrepareOptionsMenu(menu);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onPrepareOptionsMenu(Menu menu) {\r
+        return true;\r
+    }\r
+\r
+    @Override\r
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
+        if (featureId == Window.FEATURE_OPTIONS_PANEL) {\r
+            return onOptionsItemSelected(item);\r
+        }\r
+        return false;\r
+    }\r
+\r
+    public boolean onOptionsItemSelected(MenuItem item) {\r
+        return false;\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Content\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    @Override\r
+    public void addContentView(View view, LayoutParams params) {\r
+        getSherlock().addContentView(view, params);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(int layoutResId) {\r
+        getSherlock().setContentView(layoutResId);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(View view, LayoutParams params) {\r
+        getSherlock().setContentView(view, params);\r
+    }\r
+\r
+    @Override\r
+    public void setContentView(View view) {\r
+        getSherlock().setContentView(view);\r
+    }\r
+\r
+    public void requestWindowFeature(long featureId) {\r
+        getSherlock().requestFeature((int)featureId);\r
+    }\r
+\r
+\r
+    ///////////////////////////////////////////////////////////////////////////\r
+    // Progress Indication\r
+    ///////////////////////////////////////////////////////////////////////////\r
+\r
+    public void setSupportProgress(int progress) {\r
+        getSherlock().setProgress(progress);\r
+    }\r
+\r
+    public void setSupportProgressBarIndeterminate(boolean indeterminate) {\r
+        getSherlock().setProgressBarIndeterminate(indeterminate);\r
+    }\r
+\r
+    public void setSupportProgressBarIndeterminateVisibility(boolean visible) {\r
+        getSherlock().setProgressBarIndeterminateVisibility(visible);\r
+    }\r
+\r
+    public void setSupportProgressBarVisibility(boolean visible) {\r
+        getSherlock().setProgressBarVisibility(visible);\r
+    }\r
+\r
+    public void setSupportSecondaryProgress(int secondaryProgress) {\r
+        getSherlock().setSecondaryProgress(secondaryProgress);\r
+    }\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockCompat.java
new file mode 100644 (file)
index 0000000..05353d2
--- /dev/null
@@ -0,0 +1,1207 @@
+package com.actionbarsherlock.internal;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import org.xmlpull.v1.XmlPullParser;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.util.AndroidRuntimeException;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewStub;
+import android.view.Window;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+import com.actionbarsherlock.ActionBarSherlock;
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.internal.app.ActionBarImpl;
+import com.actionbarsherlock.internal.view.StandaloneActionMode;
+import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
+import com.actionbarsherlock.internal.view.menu.MenuBuilder;
+import com.actionbarsherlock.internal.view.menu.MenuItemImpl;
+import com.actionbarsherlock.internal.view.menu.MenuPresenter;
+import com.actionbarsherlock.internal.widget.ActionBarContainer;
+import com.actionbarsherlock.internal.widget.ActionBarContextView;
+import com.actionbarsherlock.internal.widget.ActionBarView;
+import com.actionbarsherlock.internal.widget.IcsProgressBar;
+import com.actionbarsherlock.view.ActionMode;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+
+@ActionBarSherlock.Implementation(api = 7)
+public class ActionBarSherlockCompat extends ActionBarSherlock implements MenuBuilder.Callback, com.actionbarsherlock.view.Window.Callback, MenuPresenter.Callback, android.view.MenuItem.OnMenuItemClickListener {
+    /** Window features which are enabled by default. */
+    protected static final int DEFAULT_FEATURES = 0;
+
+
+    public ActionBarSherlockCompat(Activity activity, int flags) {
+        super(activity, flags);
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Properties
+    ///////////////////////////////////////////////////////////////////////////
+
+    /** Whether or not the device has a dedicated menu key button. */
+    private boolean mReserveOverflow;
+    /** Lazy-load indicator for {@link #mReserveOverflow}. */
+    private boolean mReserveOverflowSet = false;
+
+    /** Current menu instance for managing action items. */
+    private MenuBuilder mMenu;
+    /** Map between native options items and sherlock items. */
+    protected HashMap<android.view.MenuItem, MenuItemImpl> mNativeItemMap;
+    /** Indication of a long-press on the hardware menu key. */
+    private boolean mMenuKeyIsLongPress = false;
+
+    /** Parent view of the window decoration (action bar, mode, etc.). */
+    private ViewGroup mDecor;
+    /** Parent view of the activity content. */
+    private ViewGroup mContentParent;
+
+    /** Whether or not the title is stable and can be displayed. */
+    private boolean mIsTitleReady = false;
+    /** Whether or not the parent activity has been destroyed. */
+    private boolean mIsDestroyed = false;
+
+    /* Emulate PanelFeatureState */
+    private boolean mClosingActionMenu;
+    private boolean mMenuIsPrepared;
+    private boolean mMenuRefreshContent;
+    private Bundle mMenuFrozenActionViewState;
+
+    /** Implementation which backs the action bar interface API. */
+    private ActionBarImpl aActionBar;
+    /** Main action bar view which displays the core content. */
+    private ActionBarView wActionBar;
+    /** Relevant window and action bar features flags. */
+    private int mFeatures = DEFAULT_FEATURES;
+    /** Relevant user interface option flags. */
+    private int mUiOptions = 0;
+
+    /** Decor indeterminate progress indicator. */
+    private IcsProgressBar mCircularProgressBar;
+    /** Decor progress indicator. */
+    private IcsProgressBar mHorizontalProgressBar;
+
+    /** Current displayed context action bar, if any. */
+    private ActionMode mActionMode;
+    /** Parent view in which the context action bar is displayed. */
+    private ActionBarContextView mActionModeView;
+
+    /** Title view used with dialogs. */
+    private TextView mTitleView;
+    /** Current activity title. */
+    private CharSequence mTitle = null;
+    /** Whether or not this "activity" is floating (i.e., a dialog) */
+    private boolean mIsFloating;
+
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Instance methods
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public ActionBar getActionBar() {
+        if (DEBUG) Log.d(TAG, "[getActionBar]");
+
+        initActionBar();
+        return aActionBar;
+    }
+
+    private void initActionBar() {
+        if (DEBUG) Log.d(TAG, "[initActionBar]");
+
+        // Initializing the window decor can change window feature flags.
+        // Make sure that we have the correct set before performing the test below.
+        if (mDecor == null) {
+            installDecor();
+        }
+
+        if ((aActionBar != null) || !hasFeature(Window.FEATURE_ACTION_BAR) || hasFeature(Window.FEATURE_NO_TITLE) || mActivity.isChild()) {
+            return;
+        }
+
+        aActionBar = new ActionBarImpl(mActivity, mFeatures);
+
+        if (!mIsDelegate) {
+            //We may never get another chance to set the title
+            wActionBar.setWindowTitle(mActivity.getTitle());
+        }
+    }
+
+    @Override
+    protected Context getThemedContext() {
+        return aActionBar.getThemedContext();
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        if (DEBUG) Log.d(TAG, "[setTitle] title: " + title);
+
+        dispatchTitleChanged(title, 0);
+    }
+
+    @Override
+    public ActionMode startActionMode(ActionMode.Callback callback) {
+        if (DEBUG) Log.d(TAG, "[startActionMode] callback: " + callback);
+
+        if (mActionMode != null) {
+            mActionMode.finish();
+        }
+
+        final ActionMode.Callback wrappedCallback = new ActionModeCallbackWrapper(callback);
+        ActionMode mode = null;
+
+        //Emulate Activity's onWindowStartingActionMode:
+        initActionBar();
+        if (aActionBar != null) {
+            mode = aActionBar.startActionMode(wrappedCallback);
+        }
+
+        if (mode != null) {
+            mActionMode = mode;
+        } else {
+            if (mActionModeView == null) {
+                ViewStub stub = (ViewStub)mDecor.findViewById(R.id.abs__action_mode_bar_stub);
+                if (stub != null) {
+                    mActionModeView = (ActionBarContextView)stub.inflate();
+                }
+            }
+            if (mActionModeView != null) {
+                mActionModeView.killMode();
+                mode = new StandaloneActionMode(mActivity, mActionModeView, wrappedCallback, true);
+                if (callback.onCreateActionMode(mode, mode.getMenu())) {
+                    mode.invalidate();
+                    mActionModeView.initForMode(mode);
+                    mActionModeView.setVisibility(View.VISIBLE);
+                    mActionMode = mode;
+                    mActionModeView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                } else {
+                    mActionMode = null;
+                }
+            }
+        }
+        if (mActionMode != null && mActivity instanceof OnActionModeStartedListener) {
+            ((OnActionModeStartedListener)mActivity).onActionModeStarted(mActionMode);
+        }
+        return mActionMode;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Lifecycle and interaction callbacks for delegation
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void dispatchConfigurationChanged(Configuration newConfig) {
+        if (DEBUG) Log.d(TAG, "[dispatchConfigurationChanged] newConfig: " + newConfig);
+
+        if (aActionBar != null) {
+            aActionBar.onConfigurationChanged(newConfig);
+        }
+    }
+
+    @Override
+    public void dispatchPostResume() {
+        if (DEBUG) Log.d(TAG, "[dispatchPostResume]");
+
+        if (aActionBar != null) {
+            aActionBar.setShowHideAnimationEnabled(true);
+        }
+    }
+
+    @Override
+    public void dispatchPause() {
+        if (DEBUG) Log.d(TAG, "[dispatchPause]");
+
+        if (wActionBar != null && wActionBar.isOverflowMenuShowing()) {
+            wActionBar.hideOverflowMenu();
+        }
+    }
+
+    @Override
+    public void dispatchStop() {
+        if (DEBUG) Log.d(TAG, "[dispatchStop]");
+
+        if (aActionBar != null) {
+            aActionBar.setShowHideAnimationEnabled(false);
+        }
+    }
+
+    @Override
+    public void dispatchInvalidateOptionsMenu() {
+        if (DEBUG) Log.d(TAG, "[dispatchInvalidateOptionsMenu]");
+
+        Bundle savedActionViewStates = null;
+        if (mMenu != null) {
+            savedActionViewStates = new Bundle();
+            mMenu.saveActionViewStates(savedActionViewStates);
+            if (savedActionViewStates.size() > 0) {
+                mMenuFrozenActionViewState = savedActionViewStates;
+            }
+            // This will be started again when the panel is prepared.
+            mMenu.stopDispatchingItemsChanged();
+            mMenu.clear();
+        }
+        mMenuRefreshContent = true;
+
+        // Prepare the options panel if we have an action bar
+        if (wActionBar != null) {
+            mMenuIsPrepared = false;
+            preparePanel();
+        }
+    }
+
+    @Override
+    public boolean dispatchOpenOptionsMenu() {
+        if (DEBUG) Log.d(TAG, "[dispatchOpenOptionsMenu]");
+
+        if (!isReservingOverflow()) {
+            return false;
+        }
+
+        return wActionBar.showOverflowMenu();
+    }
+
+    @Override
+    public boolean dispatchCloseOptionsMenu() {
+        if (DEBUG) Log.d(TAG, "[dispatchCloseOptionsMenu]");
+
+        if (!isReservingOverflow()) {
+            return false;
+        }
+
+        return wActionBar.hideOverflowMenu();
+    }
+
+    @Override
+    public void dispatchPostCreate(Bundle savedInstanceState) {
+        if (DEBUG) Log.d(TAG, "[dispatchOnPostCreate]");
+
+        if (mIsDelegate) {
+            mIsTitleReady = true;
+        }
+
+        if (mDecor == null) {
+            initActionBar();
+        }
+    }
+
+    @Override
+    public boolean dispatchCreateOptionsMenu(android.view.Menu menu) {
+        if (DEBUG) {
+            Log.d(TAG, "[dispatchCreateOptionsMenu] android.view.Menu: " + menu);
+            Log.d(TAG, "[dispatchCreateOptionsMenu] returning true");
+        }
+        return true;
+    }
+
+    @Override
+    public boolean dispatchPrepareOptionsMenu(android.view.Menu menu) {
+        if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] android.view.Menu: " + menu);
+
+        if (mActionMode != null) {
+            return false;
+        }
+
+        mMenuIsPrepared = false;
+        if (!preparePanel()) {
+            return false;
+        }
+
+        if (isReservingOverflow()) {
+            return false;
+        }
+
+        if (mNativeItemMap == null) {
+            mNativeItemMap = new HashMap<android.view.MenuItem, MenuItemImpl>();
+        } else {
+            mNativeItemMap.clear();
+        }
+
+        if (mMenu == null) {
+            return false;
+        }
+
+        boolean result = mMenu.bindNativeOverflow(menu, this, mNativeItemMap);
+        if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] returning " + result);
+        return result;
+    }
+
+    @Override
+    public boolean dispatchOptionsItemSelected(android.view.MenuItem item) {
+        throw new IllegalStateException("Native callback invoked. Create a test case and report!");
+    }
+
+    @Override
+    public boolean dispatchMenuOpened(int featureId, android.view.Menu menu) {
+        if (DEBUG) Log.d(TAG, "[dispatchMenuOpened] featureId: " + featureId + ", menu: " + menu);
+
+        if (featureId == Window.FEATURE_ACTION_BAR || featureId == Window.FEATURE_OPTIONS_PANEL) {
+            if (aActionBar != null) {
+                aActionBar.dispatchMenuVisibilityChanged(true);
+            }
+            return true;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void dispatchPanelClosed(int featureId, android.view.Menu menu){
+        if (DEBUG) Log.d(TAG, "[dispatchPanelClosed] featureId: " + featureId + ", menu: " + menu);
+
+        if (featureId == Window.FEATURE_ACTION_BAR || featureId == Window.FEATURE_OPTIONS_PANEL) {
+            if (aActionBar != null) {
+                aActionBar.dispatchMenuVisibilityChanged(false);
+            }
+        }
+    }
+
+    @Override
+    public void dispatchTitleChanged(CharSequence title, int color) {
+        if (DEBUG) Log.d(TAG, "[dispatchTitleChanged] title: " + title + ", color: " + color);
+
+        if (!mIsDelegate || mIsTitleReady) {
+            if (mTitleView != null) {
+                mTitleView.setText(title);
+            } else if (wActionBar != null) {
+                wActionBar.setWindowTitle(title);
+            }
+        }
+
+        mTitle = title;
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] event: " + event);
+
+        final int keyCode = event.getKeyCode();
+
+        // Not handled by the view hierarchy, does the action bar want it
+        // to cancel out of something special?
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            final int action = event.getAction();
+            // Back cancels action modes first.
+            if (mActionMode != null) {
+                if (action == KeyEvent.ACTION_UP) {
+                    mActionMode.finish();
+                }
+                if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning true");
+                return true;
+            }
+
+            // Next collapse any expanded action views.
+            if (wActionBar != null && wActionBar.hasExpandedActionView()) {
+                if (action == KeyEvent.ACTION_UP) {
+                    wActionBar.collapseActionView();
+                }
+                if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning true");
+                return true;
+            }
+        }
+
+        boolean result = false;
+        if (keyCode == KeyEvent.KEYCODE_MENU && isReservingOverflow()) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN && event.isLongPress()) {
+                mMenuKeyIsLongPress = true;
+            } else if (event.getAction() == KeyEvent.ACTION_UP) {
+                if (!mMenuKeyIsLongPress) {
+                    if (mActionMode == null && wActionBar != null) {
+                        if (wActionBar.isOverflowMenuShowing()) {
+                            wActionBar.hideOverflowMenu();
+                        } else {
+                            wActionBar.showOverflowMenu();
+                        }
+                    }
+                    result = true;
+                }
+                mMenuKeyIsLongPress = false;
+            }
+        }
+
+        if (DEBUG) Log.d(TAG, "[dispatchKeyEvent] returning " + result);
+        return result;
+    }
+
+    @Override
+    public void dispatchDestroy() {
+        mIsDestroyed = true;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Menu callback lifecycle and creation
+    ///////////////////////////////////////////////////////////////////////////
+
+    private boolean preparePanel() {
+        // Already prepared (isPrepared will be reset to false later)
+        if (mMenuIsPrepared) {
+            return true;
+        }
+
+        // Init the panel state's menu--return false if init failed
+        if (mMenu == null || mMenuRefreshContent) {
+            if (mMenu == null) {
+                if (!initializePanelMenu() || (mMenu == null)) {
+                    return false;
+                }
+            }
+
+            if (wActionBar != null) {
+                wActionBar.setMenu(mMenu, this);
+            }
+
+            // Call callback, and return if it doesn't want to display menu.
+
+            // Creating the panel menu will involve a lot of manipulation;
+            // don't dispatch change events to presenters until we're done.
+            mMenu.stopDispatchingItemsChanged();
+            if (!callbackCreateOptionsMenu(mMenu)) {
+                // Ditch the menu created above
+                mMenu = null;
+
+                if (wActionBar != null) {
+                    // Don't show it in the action bar either
+                    wActionBar.setMenu(null, this);
+                }
+
+                return false;
+            }
+
+            mMenuRefreshContent = false;
+        }
+
+        // Callback and return if the callback does not want to show the menu
+
+        // Preparing the panel menu can involve a lot of manipulation;
+        // don't dispatch change events to presenters until we're done.
+        mMenu.stopDispatchingItemsChanged();
+
+        // Restore action view state before we prepare. This gives apps
+        // an opportunity to override frozen/restored state in onPrepare.
+        if (mMenuFrozenActionViewState != null) {
+            mMenu.restoreActionViewStates(mMenuFrozenActionViewState);
+            mMenuFrozenActionViewState = null;
+        }
+
+        if (!callbackPrepareOptionsMenu(mMenu)) {
+            if (wActionBar != null) {
+                // The app didn't want to show the menu for now but it still exists.
+                // Clear it out of the action bar.
+                wActionBar.setMenu(null, this);
+            }
+            mMenu.startDispatchingItemsChanged();
+            return false;
+        }
+
+        // Set the proper keymap
+        KeyCharacterMap kmap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+        mMenu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC);
+        mMenu.startDispatchingItemsChanged();
+
+        // Set other state
+        mMenuIsPrepared = true;
+
+        return true;
+    }
+
+    public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+        return callbackOptionsItemSelected(item);
+    }
+
+    public void onMenuModeChange(MenuBuilder menu) {
+        reopenMenu(true);
+    }
+
+    private void reopenMenu(boolean toggleMenuMode) {
+        if (wActionBar != null && wActionBar.isOverflowReserved()) {
+            if (!wActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
+                if (wActionBar.getVisibility() == View.VISIBLE) {
+                    if (callbackPrepareOptionsMenu(mMenu)) {
+                        wActionBar.showOverflowMenu();
+                    }
+                }
+            } else {
+                wActionBar.hideOverflowMenu();
+            }
+            return;
+        }
+    }
+
+    private boolean initializePanelMenu() {
+        Context context = mActivity;//getContext();
+
+        // If we have an action bar, initialize the menu with a context themed for it.
+        if (wActionBar != null) {
+            TypedValue outValue = new TypedValue();
+            Resources.Theme currentTheme = context.getTheme();
+            currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme,
+                    outValue, true);
+            final int targetThemeRes = outValue.resourceId;
+
+            if (targetThemeRes != 0 /*&& context.getThemeResId() != targetThemeRes*/) {
+                context = new ContextThemeWrapper(context, targetThemeRes);
+            }
+        }
+
+        mMenu = new MenuBuilder(context);
+        mMenu.setCallback(this);
+
+        return true;
+    }
+
+    void checkCloseActionMenu(Menu menu) {
+        if (mClosingActionMenu) {
+            return;
+        }
+
+        mClosingActionMenu = true;
+        wActionBar.dismissPopupMenus();
+        //Callback cb = getCallback();
+        //if (cb != null && !isDestroyed()) {
+        //    cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
+        //}
+        mClosingActionMenu = false;
+    }
+
+    @Override
+    public boolean onOpenSubMenu(MenuBuilder subMenu) {
+        return true;
+    }
+
+    @Override
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        checkCloseActionMenu(menu);
+    }
+
+    @Override
+    public boolean onMenuItemClick(android.view.MenuItem item) {
+        if (DEBUG) Log.d(TAG, "[mNativeItemListener.onMenuItemClick] item: " + item);
+
+        final MenuItemImpl sherlockItem = mNativeItemMap.get(item);
+        if (sherlockItem != null) {
+            sherlockItem.invoke();
+        } else {
+            Log.e(TAG, "Options item \"" + item + "\" not found in mapping");
+        }
+
+        return true; //Do not allow continuation of native handling
+    }
+
+    @Override
+    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+        return callbackOptionsItemSelected(item);
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Progress bar interaction and internal handling
+    ///////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void setProgressBarVisibility(boolean visible) {
+        if (DEBUG) Log.d(TAG, "[setProgressBarVisibility] visible: " + visible);
+
+        setFeatureInt(Window.FEATURE_PROGRESS, visible ? Window.PROGRESS_VISIBILITY_ON :
+            Window.PROGRESS_VISIBILITY_OFF);
+    }
+
+    @Override
+    public void setProgressBarIndeterminateVisibility(boolean visible) {
+        if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminateVisibility] visible: " + visible);
+
+        setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
+                visible ? Window.PROGRESS_VISIBILITY_ON : Window.PROGRESS_VISIBILITY_OFF);
+    }
+
+    @Override
+    public void setProgressBarIndeterminate(boolean indeterminate) {
+        if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminate] indeterminate: " + indeterminate);
+
+        setFeatureInt(Window.FEATURE_PROGRESS,
+                indeterminate ? Window.PROGRESS_INDETERMINATE_ON : Window.PROGRESS_INDETERMINATE_OFF);
+    }
+
+    @Override
+    public void setProgress(int progress) {
+        if (DEBUG) Log.d(TAG, "[setProgress] progress: " + progress);
+
+        setFeatureInt(Window.FEATURE_PROGRESS, progress + Window.PROGRESS_START);
+    }
+
+    @Override
+    public void setSecondaryProgress(int secondaryProgress) {
+        if (DEBUG) Log.d(TAG, "[setSecondaryProgress] secondaryProgress: " + secondaryProgress);
+
+        setFeatureInt(Window.FEATURE_PROGRESS,
+                secondaryProgress + Window.PROGRESS_SECONDARY_START);
+    }
+
+    private void setFeatureInt(int featureId, int value) {
+        updateInt(featureId, value, false);
+    }
+
+    private void updateInt(int featureId, int value, boolean fromResume) {
+        // Do nothing if the decor is not yet installed... an update will
+        // need to be forced when we eventually become active.
+        if (mContentParent == null) {
+            return;
+        }
+
+        final int featureMask = 1 << featureId;
+
+        if ((getFeatures() & featureMask) == 0 && !fromResume) {
+            return;
+        }
+
+        onIntChanged(featureId, value);
+    }
+
+    private void onIntChanged(int featureId, int value) {
+        if (featureId == Window.FEATURE_PROGRESS || featureId == Window.FEATURE_INDETERMINATE_PROGRESS) {
+            updateProgressBars(value);
+        }
+    }
+
+    private void updateProgressBars(int value) {
+        IcsProgressBar circularProgressBar = getCircularProgressBar(true);
+        IcsProgressBar horizontalProgressBar = getHorizontalProgressBar(true);
+
+        final int features = mFeatures;//getLocalFeatures();
+        if (value == Window.PROGRESS_VISIBILITY_ON) {
+            if ((features & (1 << Window.FEATURE_PROGRESS)) != 0) {
+                int level = horizontalProgressBar.getProgress();
+                int visibility = (horizontalProgressBar.isIndeterminate() || level < 10000) ?
+                        View.VISIBLE : View.INVISIBLE;
+                horizontalProgressBar.setVisibility(visibility);
+            }
+            if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0) {
+                circularProgressBar.setVisibility(View.VISIBLE);
+            }
+        } else if (value == Window.PROGRESS_VISIBILITY_OFF) {
+            if ((features & (1 << Window.FEATURE_PROGRESS)) != 0) {
+                horizontalProgressBar.setVisibility(View.GONE);
+            }
+            if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0) {
+                circularProgressBar.setVisibility(View.GONE);
+            }
+        } else if (value == Window.PROGRESS_INDETERMINATE_ON) {
+            horizontalProgressBar.setIndeterminate(true);
+        } else if (value == Window.PROGRESS_INDETERMINATE_OFF) {
+            horizontalProgressBar.setIndeterminate(false);
+        } else if (Window.PROGRESS_START <= value && value <= Window.PROGRESS_END) {
+            // We want to set the progress value before testing for visibility
+            // so that when the progress bar becomes visible again, it has the
+            // correct level.
+            horizontalProgressBar.setProgress(value - Window.PROGRESS_START);
+
+            if (value < Window.PROGRESS_END) {
+                showProgressBars(horizontalProgressBar, circularProgressBar);
+            } else {
+                hideProgressBars(horizontalProgressBar, circularProgressBar);
+            }
+        } else if (Window.PROGRESS_SECONDARY_START <= value && value <= Window.PROGRESS_SECONDARY_END) {
+            horizontalProgressBar.setSecondaryProgress(value - Window.PROGRESS_SECONDARY_START);
+
+            showProgressBars(horizontalProgressBar, circularProgressBar);
+        }
+    }
+
+    private void showProgressBars(IcsProgressBar horizontalProgressBar, IcsProgressBar spinnyProgressBar) {
+        final int features = mFeatures;//getLocalFeatures();
+        if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
+                spinnyProgressBar.getVisibility() == View.INVISIBLE) {
+            spinnyProgressBar.setVisibility(View.VISIBLE);
+        }
+        // Only show the progress bars if the primary progress is not complete
+        if ((features & (1 << Window.FEATURE_PROGRESS)) != 0 &&
+                horizontalProgressBar.getProgress() < 10000) {
+            horizontalProgressBar.setVisibility(View.VISIBLE);
+        }
+    }
+
+    private void hideProgressBars(IcsProgressBar horizontalProgressBar, IcsProgressBar spinnyProgressBar) {
+        final int features = mFeatures;//getLocalFeatures();
+        Animation anim = AnimationUtils.loadAnimation(mActivity, android.R.anim.fade_out);
+        anim.setDuration(1000);
+        if ((features & (1 << Window.FEATURE_INDETERMINATE_PROGRESS)) != 0 &&
+                spinnyProgressBar.getVisibility() == View.VISIBLE) {
+            spinnyProgressBar.startAnimation(anim);
+            spinnyProgressBar.setVisibility(View.INVISIBLE);
+        }
+        if ((features & (1 << Window.FEATURE_PROGRESS)) != 0 &&
+                horizontalProgressBar.getVisibility() == View.VISIBLE) {
+            horizontalProgressBar.startAnimation(anim);
+            horizontalProgressBar.setVisibility(View.INVISIBLE);
+        }
+    }
+
+    private IcsProgressBar getCircularProgressBar(boolean shouldInstallDecor) {
+        if (mCircularProgressBar != null) {
+            return mCircularProgressBar;
+        }
+        if (mContentParent == null && shouldInstallDecor) {
+            installDecor();
+        }
+        mCircularProgressBar = (IcsProgressBar)mDecor.findViewById(R.id.abs__progress_circular);
+        if (mCircularProgressBar != null) {
+            mCircularProgressBar.setVisibility(View.INVISIBLE);
+        }
+        return mCircularProgressBar;
+    }
+
+    private IcsProgressBar getHorizontalProgressBar(boolean shouldInstallDecor) {
+        if (mHorizontalProgressBar != null) {
+            return mHorizontalProgressBar;
+        }
+        if (mContentParent == null && shouldInstallDecor) {
+            installDecor();
+        }
+        mHorizontalProgressBar = (IcsProgressBar)mDecor.findViewById(R.id.abs__progress_horizontal);
+        if (mHorizontalProgressBar != null) {
+            mHorizontalProgressBar.setVisibility(View.INVISIBLE);
+        }
+        return mHorizontalProgressBar;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Feature management and content interaction and creation
+    ///////////////////////////////////////////////////////////////////////////
+
+    private int getFeatures() {
+        if (DEBUG) Log.d(TAG, "[getFeatures] returning " + mFeatures);
+
+        return mFeatures;
+    }
+
+    @Override
+    public boolean hasFeature(int featureId) {
+        if (DEBUG) Log.d(TAG, "[hasFeature] featureId: " + featureId);
+
+        boolean result = (mFeatures & (1 << featureId)) != 0;
+        if (DEBUG) Log.d(TAG, "[hasFeature] returning " + result);
+        return result;
+    }
+
+    @Override
+    public boolean requestFeature(int featureId) {
+        if (DEBUG) Log.d(TAG, "[requestFeature] featureId: " + featureId);
+
+        if (mContentParent != null) {
+            throw new AndroidRuntimeException("requestFeature() must be called before adding content");
+        }
+
+        switch (featureId) {
+            case Window.FEATURE_ACTION_BAR:
+            case Window.FEATURE_ACTION_BAR_OVERLAY:
+            case Window.FEATURE_ACTION_MODE_OVERLAY:
+            case Window.FEATURE_INDETERMINATE_PROGRESS:
+            case Window.FEATURE_NO_TITLE:
+            case Window.FEATURE_PROGRESS:
+                mFeatures |= (1 << featureId);
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    @Override
+    public void setUiOptions(int uiOptions) {
+        if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions);
+
+        mUiOptions = uiOptions;
+    }
+
+    @Override
+    public void setUiOptions(int uiOptions, int mask) {
+        if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions + ", mask: " + mask);
+
+        mUiOptions = (mUiOptions & ~mask) | (uiOptions & mask);
+    }
+
+    @Override
+    public void setContentView(int layoutResId) {
+        if (DEBUG) Log.d(TAG, "[setContentView] layoutResId: " + layoutResId);
+
+        if (mContentParent == null) {
+            installDecor();
+        } else {
+            mContentParent.removeAllViews();
+        }
+        mActivity.getLayoutInflater().inflate(layoutResId, mContentParent);
+
+        android.view.Window.Callback callback = mActivity.getWindow().getCallback();
+        if (callback != null) {
+            callback.onContentChanged();
+        }
+
+        initActionBar();
+    }
+
+    @Override
+    public void setContentView(View view, ViewGroup.LayoutParams params) {
+        if (DEBUG) Log.d(TAG, "[setContentView] view: " + view + ", params: " + params);
+
+        if (mContentParent == null) {
+            installDecor();
+        } else {
+            mContentParent.removeAllViews();
+        }
+        mContentParent.addView(view, params);
+
+        android.view.Window.Callback callback = mActivity.getWindow().getCallback();
+        if (callback != null) {
+            callback.onContentChanged();
+        }
+
+        initActionBar();
+    }
+
+    @Override
+    public void addContentView(View view, ViewGroup.LayoutParams params) {
+        if (DEBUG) Log.d(TAG, "[addContentView] view: " + view + ", params: " + params);
+
+        if (mContentParent == null) {
+            installDecor();
+        }
+        mContentParent.addView(view, params);
+
+        initActionBar();
+    }
+
+    private void installDecor() {
+        if (DEBUG) Log.d(TAG, "[installDecor]");
+
+        if (mDecor == null) {
+            mDecor = (ViewGroup)mActivity.getWindow().getDecorView().findViewById(android.R.id.content);
+        }
+        if (mContentParent == null) {
+            //Since we are not operating at the window level we need to take
+            //into account the fact that the true decor may have already been
+            //initialized and had content attached to it. If that is the case,
+            //copy over its children to our new content container.
+            List<View> views = null;
+            if (mDecor.getChildCount() > 0) {
+                views = new ArrayList<View>(1); //Usually there's only one child
+                for (int i = 0, children = mDecor.getChildCount(); i < children; i++) {
+                    View child = mDecor.getChildAt(0);
+                    mDecor.removeView(child);
+                    views.add(child);
+                }
+            }
+
+            mContentParent = generateLayout();
+
+            //Copy over the old children. See above for explanation.
+            if (views != null) {
+                for (View child : views) {
+                    mContentParent.addView(child);
+                }
+            }
+
+            mTitleView = (TextView)mDecor.findViewById(android.R.id.title);
+            if (mTitleView != null) {
+                if (hasFeature(Window.FEATURE_NO_TITLE)) {
+                    mTitleView.setVisibility(View.GONE);
+                    if (mContentParent instanceof FrameLayout) {
+                        ((FrameLayout)mContentParent).setForeground(null);
+                    }
+                } else {
+                    mTitleView.setText(mTitle);
+                }
+            } else {
+                wActionBar = (ActionBarView)mDecor.findViewById(R.id.abs__action_bar);
+                if (wActionBar != null) {
+                    wActionBar.setWindowCallback(this);
+                    if (wActionBar.getTitle() == null) {
+                        wActionBar.setWindowTitle(mActivity.getTitle());
+                    }
+                    if (hasFeature(Window.FEATURE_PROGRESS)) {
+                        wActionBar.initProgress();
+                    }
+                    if (hasFeature(Window.FEATURE_INDETERMINATE_PROGRESS)) {
+                        wActionBar.initIndeterminateProgress();
+                    }
+
+                    //Since we don't require onCreate dispatching, parse for uiOptions here
+                    int uiOptions = loadUiOptionsFromManifest(mActivity);
+                    if (uiOptions != 0) {
+                        mUiOptions = uiOptions;
+                    }
+
+                    boolean splitActionBar = false;
+                    final boolean splitWhenNarrow = (mUiOptions & ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW) != 0;
+                    if (splitWhenNarrow) {
+                        splitActionBar = getResources_getBoolean(mActivity, R.bool.abs__split_action_bar_is_narrow);
+                    } else {
+                        splitActionBar = mActivity.getTheme()
+                                .obtainStyledAttributes(R.styleable.SherlockTheme)
+                                .getBoolean(R.styleable.SherlockTheme_windowSplitActionBar, false);
+                    }
+                    final ActionBarContainer splitView = (ActionBarContainer)mDecor.findViewById(R.id.abs__split_action_bar);
+                    if (splitView != null) {
+                        wActionBar.setSplitView(splitView);
+                        wActionBar.setSplitActionBar(splitActionBar);
+                        wActionBar.setSplitWhenNarrow(splitWhenNarrow);
+
+                        mActionModeView = (ActionBarContextView)mDecor.findViewById(R.id.abs__action_context_bar);
+                        mActionModeView.setSplitView(splitView);
+                        mActionModeView.setSplitActionBar(splitActionBar);
+                        mActionModeView.setSplitWhenNarrow(splitWhenNarrow);
+                    } else if (splitActionBar) {
+                        Log.e(TAG, "Requested split action bar with incompatible window decor! Ignoring request.");
+                    }
+
+                    // Post the panel invalidate for later; avoid application onCreateOptionsMenu
+                    // being called in the middle of onCreate or similar.
+                    mDecor.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            //Invalidate if the panel menu hasn't been created before this.
+                            if (!mIsDestroyed && !mActivity.isFinishing() && mMenu == null) {
+                                dispatchInvalidateOptionsMenu();
+                            }
+                        }
+                    });
+                }
+            }
+        }
+    }
+
+    private ViewGroup generateLayout() {
+        if (DEBUG) Log.d(TAG, "[generateLayout]");
+
+        // Apply data from current theme.
+
+        TypedArray a = mActivity.getTheme().obtainStyledAttributes(R.styleable.SherlockTheme);
+
+        mIsFloating = a.getBoolean(R.styleable.SherlockTheme_android_windowIsFloating, false);
+
+        if (!a.hasValue(R.styleable.SherlockTheme_windowActionBar)) {
+            throw new IllegalStateException("You must use Theme.Sherlock, Theme.Sherlock.Light, Theme.Sherlock.Light.DarkActionBar, or a derivative.");
+        }
+
+        if (a.getBoolean(R.styleable.SherlockTheme_windowNoTitle, false)) {
+            requestFeature(Window.FEATURE_NO_TITLE);
+        } else if (a.getBoolean(R.styleable.SherlockTheme_windowActionBar, false)) {
+            // Don't allow an action bar if there is no title.
+            requestFeature(Window.FEATURE_ACTION_BAR);
+        }
+
+        if (a.getBoolean(R.styleable.SherlockTheme_windowActionBarOverlay, false)) {
+            requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
+        }
+
+        if (a.getBoolean(R.styleable.SherlockTheme_windowActionModeOverlay, false)) {
+            requestFeature(Window.FEATURE_ACTION_MODE_OVERLAY);
+        }
+
+        a.recycle();
+
+        int layoutResource;
+        if (!hasFeature(Window.FEATURE_NO_TITLE)) {
+            if (mIsFloating) {
+                //Trash original dialog LinearLayout
+                mDecor = (ViewGroup)mDecor.getParent();
+                mDecor.removeAllViews();
+
+                layoutResource = R.layout.abs__dialog_title_holo;
+            } else {
+                if (hasFeature(Window.FEATURE_ACTION_BAR_OVERLAY)) {
+                    layoutResource = R.layout.abs__screen_action_bar_overlay;
+                } else {
+                    layoutResource = R.layout.abs__screen_action_bar;
+                }
+            }
+        } else if (hasFeature(Window.FEATURE_ACTION_MODE_OVERLAY) && !hasFeature(Window.FEATURE_NO_TITLE)) {
+            layoutResource = R.layout.abs__screen_simple_overlay_action_mode;
+        } else {
+            layoutResource = R.layout.abs__screen_simple;
+        }
+
+        if (DEBUG) Log.d(TAG, "[generateLayout] using screen XML " + mActivity.getResources().getString(layoutResource));
+        View in = mActivity.getLayoutInflater().inflate(layoutResource, null);
+        mDecor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+
+        ViewGroup contentParent = (ViewGroup)mDecor.findViewById(R.id.abs__content);
+        if (contentParent == null) {
+            throw new RuntimeException("Couldn't find content container view");
+        }
+
+        //Make our new child the true content view (for fragments). VERY VOLATILE!
+        mDecor.setId(View.NO_ID);
+        contentParent.setId(android.R.id.content);
+
+        if (hasFeature(Window.FEATURE_INDETERMINATE_PROGRESS)) {
+            IcsProgressBar progress = getCircularProgressBar(false);
+            if (progress != null) {
+                progress.setIndeterminate(true);
+            }
+        }
+
+        return contentParent;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////
+    // Miscellaneous
+    ///////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Determine whether or not the device has a dedicated menu key.
+     *
+     * @return {@code true} if native menu key is present.
+     */
+    private boolean isReservingOverflow() {
+        if (!mReserveOverflowSet) {
+            mReserveOverflow = ActionMenuPresenter.reserveOverflow(mActivity);
+            mReserveOverflowSet = true;
+        }
+        return mReserveOverflow;
+    }
+
+    private static int loadUiOptionsFromManifest(Activity activity) {
+        int uiOptions = 0;
+        try {
+            final String thisPackage = activity.getClass().getName();
+            if (DEBUG) Log.i(TAG, "Parsing AndroidManifest.xml for " + thisPackage);
+
+            final String packageName = activity.getApplicationInfo().packageName;
+            final AssetManager am = activity.createPackageContext(packageName, 0).getAssets();
+            final XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml");
+
+            int eventType = xml.getEventType();
+            while (eventType != XmlPullParser.END_DOCUMENT) {
+                if (eventType == XmlPullParser.START_TAG) {
+                    String name = xml.getName();
+
+                    if ("application".equals(name)) {
+                        //Check if the <application> has the attribute
+                        if (DEBUG) Log.d(TAG, "Got <application>");
+
+                        for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
+                            if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
+
+                            if ("uiOptions".equals(xml.getAttributeName(i))) {
+                                uiOptions = xml.getAttributeIntValue(i, 0);
+                                break; //out of for loop
+                            }
+                        }
+                    } else if ("activity".equals(name)) {
+                        //Check if the <activity> is us and has the attribute
+                        if (DEBUG) Log.d(TAG, "Got <activity>");
+                        Integer activityUiOptions = null;
+                        String activityPackage = null;
+                        boolean isOurActivity = false;
+
+                        for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
+                            if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
+
+                            //We need both uiOptions and name attributes
+                            String attrName = xml.getAttributeName(i);
+                            if ("uiOptions".equals(attrName)) {
+                                activityUiOptions = xml.getAttributeIntValue(i, 0);
+                            } else if ("name".equals(attrName)) {
+                                activityPackage = cleanActivityName(packageName, xml.getAttributeValue(i));
+                                if (!thisPackage.equals(activityPackage)) {
+                                    break; //out of for loop
+                                }
+                                isOurActivity = true;
+                            }
+
+                            //Make sure we have both attributes before processing
+                            if ((activityUiOptions != null) && (activityPackage != null)) {
+                                //Our activity, uiOptions specified, override with our value
+                                uiOptions = activityUiOptions.intValue();
+                            }
+                        }
+                        if (isOurActivity) {
+                            //If we matched our activity but it had no logo don't
+                            //do any more processing of the manifest
+                            break;
+                        }
+                    }
+                }
+                eventType = xml.nextToken();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        if (DEBUG) Log.i(TAG, "Returning " + Integer.toHexString(uiOptions));
+        return uiOptions;
+    }
+
+    public static String cleanActivityName(String manifestPackage, String activityName) {
+        if (activityName.charAt(0) == '.') {
+            //Relative activity name (e.g., android:name=".ui.SomeClass")
+            return manifestPackage + activityName;
+        }
+        if (activityName.indexOf('.', 1) == -1) {
+            //Unqualified activity name (e.g., android:name="SomeClass")
+            return manifestPackage + "." + activityName;
+        }
+        //Fully-qualified activity name (e.g., "com.my.package.SomeClass")
+        return activityName;
+    }
+
+    /**
+     * Clears out internal reference when the action mode is destroyed.
+     */
+    private class ActionModeCallbackWrapper implements ActionMode.Callback {
+        private final ActionMode.Callback mWrapped;
+
+        public ActionModeCallbackWrapper(ActionMode.Callback wrapped) {
+            mWrapped = wrapped;
+        }
+
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            return mWrapped.onCreateActionMode(mode, menu);
+        }
+
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            return mWrapped.onPrepareActionMode(mode, menu);
+        }
+
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            return mWrapped.onActionItemClicked(mode, item);
+        }
+
+        public void onDestroyActionMode(ActionMode mode) {
+            mWrapped.onDestroyActionMode(mode);
+            if (mActionModeView != null) {
+                mActionModeView.setVisibility(View.GONE);
+                mActionModeView.removeAllViews();
+            }
+            if (mActivity instanceof OnActionModeFinishedListener) {
+                ((OnActionModeFinishedListener)mActivity).onActionModeFinished(mActionMode);
+            }
+            mActionMode = null;
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ActionBarSherlockNative.java
new file mode 100644 (file)
index 0000000..9afca18
--- /dev/null
@@ -0,0 +1,328 @@
+package com.actionbarsherlock.internal;
+
+import com.actionbarsherlock.ActionBarSherlock;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.internal.app.ActionBarWrapper;
+import com.actionbarsherlock.internal.view.menu.MenuWrapper;
+import com.actionbarsherlock.view.ActionMode;
+import com.actionbarsherlock.view.MenuInflater;
+import android.app.Activity;
+import android.content.Context;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.View;
+import android.view.Window;
+import android.view.ViewGroup.LayoutParams;
+
+@ActionBarSherlock.Implementation(api = 14)
+public class ActionBarSherlockNative extends ActionBarSherlock {
+    private ActionBarWrapper mActionBar;
+    private ActionModeWrapper mActionMode;
+    private MenuWrapper mMenu;
+
+    public ActionBarSherlockNative(Activity activity, int flags) {
+        super(activity, flags);
+    }
+
+
+    @Override
+    public ActionBar getActionBar() {
+        if (DEBUG) Log.d(TAG, "[getActionBar]");
+
+        initActionBar();
+        return mActionBar;
+    }
+
+    private void initActionBar() {
+        if (mActionBar != null || mActivity.getActionBar() == null) {
+            return;
+        }
+
+        mActionBar = new ActionBarWrapper(mActivity);
+    }
+
+    @Override
+    public void dispatchInvalidateOptionsMenu() {
+        if (DEBUG) Log.d(TAG, "[dispatchInvalidateOptionsMenu]");
+
+        mActivity.getWindow().invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);
+    }
+
+    @Override
+    public boolean dispatchCreateOptionsMenu(android.view.Menu menu) {
+        if (DEBUG) Log.d(TAG, "[dispatchCreateOptionsMenu] menu: " + menu);
+
+        if (mMenu == null || menu != mMenu.unwrap()) {
+            mMenu = new MenuWrapper(menu);
+        }
+
+        final boolean result = callbackCreateOptionsMenu(mMenu);
+        if (DEBUG) Log.d(TAG, "[dispatchCreateOptionsMenu] returning " + result);
+        return result;
+    }
+
+    @Override
+    public boolean dispatchPrepareOptionsMenu(android.view.Menu menu) {
+        if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] menu: " + menu);
+
+        final boolean result = callbackPrepareOptionsMenu(mMenu);
+        if (DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] returning " + result);
+        return result;
+    }
+
+    @Override
+    public boolean dispatchOptionsItemSelected(android.view.MenuItem item) {
+        if (DEBUG) Log.d(TAG, "[dispatchOptionsItemSelected] item: " + item.getTitleCondensed());
+
+        final boolean result = callbackOptionsItemSelected(mMenu.findItem(item));
+        if (DEBUG) Log.d(TAG, "[dispatchOptionsItemSelected] returning " + result);
+        return result;
+    }
+
+    @Override
+    public boolean hasFeature(int feature) {
+        if (DEBUG) Log.d(TAG, "[hasFeature] feature: " + feature);
+
+        final boolean result = mActivity.getWindow().hasFeature(feature);
+        if (DEBUG) Log.d(TAG, "[hasFeature] returning " + result);
+        return result;
+    }
+
+    @Override
+    public boolean requestFeature(int featureId) {
+        if (DEBUG) Log.d(TAG, "[requestFeature] featureId: " + featureId);
+
+        final boolean result = mActivity.getWindow().requestFeature(featureId);
+        if (DEBUG) Log.d(TAG, "[requestFeature] returning " + result);
+        return result;
+    }
+
+    @Override
+    public void setUiOptions(int uiOptions) {
+        if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions);
+
+        mActivity.getWindow().setUiOptions(uiOptions);
+    }
+
+    @Override
+    public void setUiOptions(int uiOptions, int mask) {
+        if (DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions + ", mask: " + mask);
+
+        mActivity.getWindow().setUiOptions(uiOptions, mask);
+    }
+
+    @Override
+    public void setContentView(int layoutResId) {
+        if (DEBUG) Log.d(TAG, "[setContentView] layoutResId: " + layoutResId);
+
+        mActivity.getWindow().setContentView(layoutResId);
+        initActionBar();
+    }
+
+    @Override
+    public void setContentView(View view, LayoutParams params) {
+        if (DEBUG) Log.d(TAG, "[setContentView] view: " + view + ", params: " + params);
+
+        mActivity.getWindow().setContentView(view, params);
+        initActionBar();
+    }
+
+    @Override
+    public void addContentView(View view, LayoutParams params) {
+        if (DEBUG) Log.d(TAG, "[addContentView] view: " + view + ", params: " + params);
+
+        mActivity.getWindow().addContentView(view, params);
+        initActionBar();
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        if (DEBUG) Log.d(TAG, "[setTitle] title: " + title);
+
+        mActivity.getWindow().setTitle(title);
+    }
+
+    @Override
+    public void setProgressBarVisibility(boolean visible) {
+        if (DEBUG) Log.d(TAG, "[setProgressBarVisibility] visible: " + visible);
+
+        mActivity.setProgressBarVisibility(visible);
+    }
+
+    @Override
+    public void setProgressBarIndeterminateVisibility(boolean visible) {
+        if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminateVisibility] visible: " + visible);
+
+        mActivity.setProgressBarIndeterminateVisibility(visible);
+    }
+
+    @Override
+    public void setProgressBarIndeterminate(boolean indeterminate) {
+        if (DEBUG) Log.d(TAG, "[setProgressBarIndeterminate] indeterminate: " + indeterminate);
+
+        mActivity.setProgressBarIndeterminate(indeterminate);
+    }
+
+    @Override
+    public void setProgress(int progress) {
+        if (DEBUG) Log.d(TAG, "[setProgress] progress: " + progress);
+
+        mActivity.setProgress(progress);
+    }
+
+    @Override
+    public void setSecondaryProgress(int secondaryProgress) {
+        if (DEBUG) Log.d(TAG, "[setSecondaryProgress] secondaryProgress: " + secondaryProgress);
+
+        mActivity.setSecondaryProgress(secondaryProgress);
+    }
+
+    @Override
+    protected Context getThemedContext() {
+        Context context = mActivity;
+        TypedValue outValue = new TypedValue();
+        mActivity.getTheme().resolveAttribute(android.R.attr.actionBarWidgetTheme, outValue, true);
+        if (outValue.resourceId != 0) {
+            //We are unable to test if this is the same as our current theme
+            //so we just wrap it and hope that if the attribute was specified
+            //then the user is intentionally specifying an alternate theme.
+            context = new ContextThemeWrapper(context, outValue.resourceId);
+        }
+        return context;
+    }
+
+    @Override
+    public ActionMode startActionMode(com.actionbarsherlock.view.ActionMode.Callback callback) {
+        if (DEBUG) Log.d(TAG, "[startActionMode] callback: " + callback);
+
+        if (mActionMode != null) {
+            mActionMode.finish();
+        }
+        ActionModeCallbackWrapper wrapped = null;
+        if (callback != null) {
+            wrapped = new ActionModeCallbackWrapper(callback);
+        }
+
+        //Calling this will trigger the callback wrapper's onCreate which
+        //is where we will set the new instance to mActionMode since we need
+        //to pass it through to the sherlock callbacks and the call below
+        //will not have returned yet to store its value.
+        mActivity.startActionMode(wrapped);
+
+        return mActionMode;
+    }
+
+    private class ActionModeCallbackWrapper implements android.view.ActionMode.Callback {
+        private final ActionMode.Callback mCallback;
+
+        public ActionModeCallbackWrapper(ActionMode.Callback callback) {
+            mCallback = callback;
+        }
+
+        @Override
+        public boolean onCreateActionMode(android.view.ActionMode mode, android.view.Menu menu) {
+            //See ActionBarSherlockNative#startActionMode
+            mActionMode = new ActionModeWrapper(mode);
+
+            return mCallback.onCreateActionMode(mActionMode, mActionMode.getMenu());
+        }
+
+        @Override
+        public boolean onPrepareActionMode(android.view.ActionMode mode, android.view.Menu menu) {
+            return mCallback.onPrepareActionMode(mActionMode, mActionMode.getMenu());
+        }
+
+        @Override
+        public boolean onActionItemClicked(android.view.ActionMode mode, android.view.MenuItem item) {
+            return mCallback.onActionItemClicked(mActionMode, mActionMode.getMenu().findItem(item));
+        }
+
+        @Override
+        public void onDestroyActionMode(android.view.ActionMode mode) {
+            mCallback.onDestroyActionMode(mActionMode);
+        }
+    }
+
+    private class ActionModeWrapper extends ActionMode {
+        private final android.view.ActionMode mActionMode;
+        private MenuWrapper mMenu = null;
+
+        ActionModeWrapper(android.view.ActionMode actionMode) {
+            mActionMode = actionMode;
+        }
+
+        @Override
+        public void setTitle(CharSequence title) {
+            mActionMode.setTitle(title);
+        }
+
+        @Override
+        public void setTitle(int resId) {
+            mActionMode.setTitle(resId);
+        }
+
+        @Override
+        public void setSubtitle(CharSequence subtitle) {
+            mActionMode.setSubtitle(subtitle);
+        }
+
+        @Override
+        public void setSubtitle(int resId) {
+            mActionMode.setSubtitle(resId);
+        }
+
+        @Override
+        public void setCustomView(View view) {
+            mActionMode.setCustomView(view);
+        }
+
+        @Override
+        public void invalidate() {
+            mActionMode.invalidate();
+        }
+
+        @Override
+        public void finish() {
+            mActionMode.finish();
+        }
+
+        @Override
+        public MenuWrapper getMenu() {
+            if (mMenu == null) {
+                mMenu = new MenuWrapper(mActionMode.getMenu());
+            }
+            return mMenu;
+        }
+
+        @Override
+        public CharSequence getTitle() {
+            return mActionMode.getTitle();
+        }
+
+        @Override
+        public CharSequence getSubtitle() {
+            return mActionMode.getSubtitle();
+        }
+
+        @Override
+        public View getCustomView() {
+            return mActionMode.getCustomView();
+        }
+
+        @Override
+        public MenuInflater getMenuInflater() {
+            return ActionBarSherlockNative.this.getMenuInflater();
+        }
+
+        @Override
+        public void setTag(Object tag) {
+            mActionMode.setTag(tag);
+        }
+
+        @Override
+        public Object getTag() {
+            return mActionMode.getTag();
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ResourcesCompat.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/ResourcesCompat.java
new file mode 100644 (file)
index 0000000..8e1efe8
--- /dev/null
@@ -0,0 +1,95 @@
+package com.actionbarsherlock.internal;
+
+import android.content.Context;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import com.actionbarsherlock.R;
+
+public final class ResourcesCompat {
+    //No instances
+    private ResourcesCompat() {}
+
+
+    /**
+     * Support implementation of {@code getResources().getBoolean()} that we
+     * can use to simulate filtering based on width and smallest width
+     * qualifiers on pre-3.2.
+     *
+     * @param context Context to load booleans from on 3.2+ and to fetch the
+     * display metrics.
+     * @param id Id of boolean to load.
+     * @return Associated boolean value as reflected by the current display
+     * metrics.
+     */
+    public static boolean getResources_getBoolean(Context context, int id) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
+            return context.getResources().getBoolean(id);
+        }
+
+        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+        float widthDp = metrics.widthPixels / metrics.density;
+        float heightDp = metrics.heightPixels / metrics.density;
+        float smallestWidthDp = (widthDp < heightDp) ? widthDp : heightDp;
+
+        if (id == R.bool.abs__action_bar_embed_tabs) {
+            if (widthDp >= 480) {
+                return true; //values-w480dp
+            }
+            return false; //values
+        }
+        if (id == R.bool.abs__split_action_bar_is_narrow) {
+            if (widthDp >= 480) {
+                return false; //values-w480dp
+            }
+            return true; //values
+        }
+        if (id == R.bool.abs__action_bar_expanded_action_views_exclusive) {
+            if (smallestWidthDp >= 600) {
+                return false; //values-sw600dp
+            }
+            return true; //values
+        }
+        if (id == R.bool.abs__config_allowActionMenuItemTextWithIcon) {
+            if (widthDp >= 480) {
+                return true; //values-w480dp
+            }
+            return false; //values
+        }
+
+        throw new IllegalArgumentException("Unknown boolean resource ID " + id);
+    }
+
+    /**
+     * Support implementation of {@code getResources().getInteger()} that we
+     * can use to simulate filtering based on width qualifiers on pre-3.2.
+     *
+     * @param context Context to load integers from on 3.2+ and to fetch the
+     * display metrics.
+     * @param id Id of integer to load.
+     * @return Associated integer value as reflected by the current display
+     * metrics.
+     */
+    public static int getResources_getInteger(Context context, int id) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
+            return context.getResources().getInteger(id);
+        }
+
+        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+        float widthDp = metrics.widthPixels / metrics.density;
+
+        if (id == R.integer.abs__max_action_buttons) {
+            if (widthDp >= 600) {
+                return 5; //values-w600dp
+            }
+            if (widthDp >= 500) {
+                return 4; //values-w500dp
+            }
+            if (widthDp >= 360) {
+                return 3; //values-w360dp
+            }
+            return 2; //values
+        }
+
+        throw new IllegalArgumentException("Unknown integer resource ID " + id);
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarImpl.java
new file mode 100644 (file)
index 0000000..6ae0402
--- /dev/null
@@ -0,0 +1,1026 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.app;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Handler;
+import android.support.v4.app.FragmentTransaction;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.SpinnerAdapter;
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
+import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorListenerAdapter;
+import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
+import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Animator.AnimatorListener;
+import com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout;
+import com.actionbarsherlock.internal.view.menu.MenuBuilder;
+import com.actionbarsherlock.internal.view.menu.MenuPopupHelper;
+import com.actionbarsherlock.internal.view.menu.SubMenuBuilder;
+import com.actionbarsherlock.internal.widget.ActionBarContainer;
+import com.actionbarsherlock.internal.widget.ActionBarContextView;
+import com.actionbarsherlock.internal.widget.ActionBarView;
+import com.actionbarsherlock.internal.widget.ScrollingTabContainerView;
+import com.actionbarsherlock.view.ActionMode;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
+
+/**
+ * ActionBarImpl is the ActionBar implementation used
+ * by devices of all screen sizes. If it detects a compatible decor,
+ * it will split contextual modes across both the ActionBarView at
+ * the top of the screen and a horizontal LinearLayout at the bottom
+ * which is normally hidden.
+ */
+public class ActionBarImpl extends ActionBar {
+    //UNUSED private static final String TAG = "ActionBarImpl";
+
+    private Context mContext;
+    private Context mThemedContext;
+    private Activity mActivity;
+    //UNUSED private Dialog mDialog;
+
+    private ActionBarContainer mContainerView;
+    private ActionBarView mActionView;
+    private ActionBarContextView mContextView;
+    private ActionBarContainer mSplitView;
+    private NineFrameLayout mContentView;
+    private ScrollingTabContainerView mTabScrollView;
+
+    private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
+
+    private TabImpl mSelectedTab;
+    private int mSavedTabPosition = INVALID_POSITION;
+
+    ActionModeImpl mActionMode;
+    ActionMode mDeferredDestroyActionMode;
+    ActionMode.Callback mDeferredModeDestroyCallback;
+
+    private boolean mLastMenuVisibility;
+    private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
+            new ArrayList<OnMenuVisibilityListener>();
+
+    private static final int CONTEXT_DISPLAY_NORMAL = 0;
+    private static final int CONTEXT_DISPLAY_SPLIT = 1;
+
+    private static final int INVALID_POSITION = -1;
+
+    private int mContextDisplayMode;
+    private boolean mHasEmbeddedTabs;
+
+    final Handler mHandler = new Handler();
+    Runnable mTabSelector;
+
+    private Animator mCurrentShowAnim;
+    private Animator mCurrentModeAnim;
+    private boolean mShowHideAnimationEnabled;
+    boolean mWasHiddenBeforeMode;
+
+    final AnimatorListener mHideListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (mContentView != null) {
+                mContentView.setTranslationY(0);
+                mContainerView.setTranslationY(0);
+            }
+            if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
+                mSplitView.setVisibility(View.GONE);
+            }
+            mContainerView.setVisibility(View.GONE);
+            mContainerView.setTransitioning(false);
+            mCurrentShowAnim = null;
+            completeDeferredDestroyActionMode();
+        }
+    };
+
+    final AnimatorListener mShowListener = new AnimatorListenerAdapter() {
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mCurrentShowAnim = null;
+            mContainerView.requestLayout();
+        }
+    };
+
+    public ActionBarImpl(Activity activity, int features) {
+        mActivity = activity;
+        Window window = activity.getWindow();
+        View decor = window.getDecorView();
+        init(decor);
+
+        //window.hasFeature() workaround for pre-3.0
+        if ((features & (1 << Window.FEATURE_ACTION_BAR_OVERLAY)) == 0) {
+            mContentView = (NineFrameLayout)decor.findViewById(android.R.id.content);
+        }
+    }
+
+    public ActionBarImpl(Dialog dialog) {
+        //UNUSED mDialog = dialog;
+        init(dialog.getWindow().getDecorView());
+    }
+
+    private void init(View decor) {
+        mContext = decor.getContext();
+        mActionView = (ActionBarView) decor.findViewById(R.id.abs__action_bar);
+        mContextView = (ActionBarContextView) decor.findViewById(
+                R.id.abs__action_context_bar);
+        mContainerView = (ActionBarContainer) decor.findViewById(
+                R.id.abs__action_bar_container);
+        mSplitView = (ActionBarContainer) decor.findViewById(
+                R.id.abs__split_action_bar);
+
+        if (mActionView == null || mContextView == null || mContainerView == null) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with a compatible window decor layout");
+        }
+
+        mActionView.setContextView(mContextView);
+        mContextDisplayMode = mActionView.isSplitActionBar() ?
+                CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
+
+        // Older apps get the home button interaction enabled by default.
+        // Newer apps need to enable it explicitly.
+        setHomeButtonEnabled(mContext.getApplicationInfo().targetSdkVersion < 14);
+
+        setHasEmbeddedTabs(getResources_getBoolean(mContext,
+                R.bool.abs__action_bar_embed_tabs));
+    }
+
+    public void onConfigurationChanged(Configuration newConfig) {
+        setHasEmbeddedTabs(getResources_getBoolean(mContext,
+                R.bool.abs__action_bar_embed_tabs));
+
+        //Manually dispatch a configuration change to the action bar view on pre-2.2
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) {
+            mActionView.onConfigurationChanged(newConfig);
+            if (mContextView != null) {
+                mContextView.onConfigurationChanged(newConfig);
+            }
+        }
+    }
+
+    private void setHasEmbeddedTabs(boolean hasEmbeddedTabs) {
+        mHasEmbeddedTabs = hasEmbeddedTabs;
+        // Switch tab layout configuration if needed
+        if (!mHasEmbeddedTabs) {
+            mActionView.setEmbeddedTabView(null);
+            mContainerView.setTabContainer(mTabScrollView);
+        } else {
+            mContainerView.setTabContainer(null);
+            mActionView.setEmbeddedTabView(mTabScrollView);
+        }
+        final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
+        if (mTabScrollView != null) {
+            mTabScrollView.setVisibility(isInTabMode ? View.VISIBLE : View.GONE);
+        }
+        mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
+    }
+
+    private void ensureTabsExist() {
+        if (mTabScrollView != null) {
+            return;
+        }
+
+        ScrollingTabContainerView tabScroller = new ScrollingTabContainerView(mContext);
+
+        if (mHasEmbeddedTabs) {
+            tabScroller.setVisibility(View.VISIBLE);
+            mActionView.setEmbeddedTabView(tabScroller);
+        } else {
+            tabScroller.setVisibility(getNavigationMode() == NAVIGATION_MODE_TABS ?
+                    View.VISIBLE : View.GONE);
+            mContainerView.setTabContainer(tabScroller);
+        }
+        mTabScrollView = tabScroller;
+    }
+
+    void completeDeferredDestroyActionMode() {
+        if (mDeferredModeDestroyCallback != null) {
+            mDeferredModeDestroyCallback.onDestroyActionMode(mDeferredDestroyActionMode);
+            mDeferredDestroyActionMode = null;
+            mDeferredModeDestroyCallback = null;
+        }
+    }
+
+    /**
+     * Enables or disables animation between show/hide states.
+     * If animation is disabled using this method, animations in progress
+     * will be finished.
+     *
+     * @param enabled true to animate, false to not animate.
+     */
+    public void setShowHideAnimationEnabled(boolean enabled) {
+        mShowHideAnimationEnabled = enabled;
+        if (!enabled && mCurrentShowAnim != null) {
+            mCurrentShowAnim.end();
+        }
+    }
+
+    public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+        mMenuVisibilityListeners.add(listener);
+    }
+
+    public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+        mMenuVisibilityListeners.remove(listener);
+    }
+
+    public void dispatchMenuVisibilityChanged(boolean isVisible) {
+        if (isVisible == mLastMenuVisibility) {
+            return;
+        }
+        mLastMenuVisibility = isVisible;
+
+        final int count = mMenuVisibilityListeners.size();
+        for (int i = 0; i < count; i++) {
+            mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
+        }
+    }
+
+    @Override
+    public void setCustomView(int resId) {
+        setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId, mActionView, false));
+    }
+
+    @Override
+    public void setDisplayUseLogoEnabled(boolean useLogo) {
+        setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
+    }
+
+    @Override
+    public void setDisplayShowHomeEnabled(boolean showHome) {
+        setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
+    }
+
+    @Override
+    public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
+        setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
+    }
+
+    @Override
+    public void setDisplayShowTitleEnabled(boolean showTitle) {
+        setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
+    }
+
+    @Override
+    public void setDisplayShowCustomEnabled(boolean showCustom) {
+        setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
+    }
+
+    @Override
+    public void setHomeButtonEnabled(boolean enable) {
+        mActionView.setHomeButtonEnabled(enable);
+    }
+
+    @Override
+    public void setTitle(int resId) {
+        setTitle(mContext.getString(resId));
+    }
+
+    @Override
+    public void setSubtitle(int resId) {
+        setSubtitle(mContext.getString(resId));
+    }
+
+    public void setSelectedNavigationItem(int position) {
+        switch (mActionView.getNavigationMode()) {
+        case NAVIGATION_MODE_TABS:
+            selectTab(mTabs.get(position));
+            break;
+        case NAVIGATION_MODE_LIST:
+            mActionView.setDropdownSelectedPosition(position);
+            break;
+        default:
+            throw new IllegalStateException(
+                    "setSelectedNavigationIndex not valid for current navigation mode");
+        }
+    }
+
+    public void removeAllTabs() {
+        cleanupTabs();
+    }
+
+    private void cleanupTabs() {
+        if (mSelectedTab != null) {
+            selectTab(null);
+        }
+        mTabs.clear();
+        if (mTabScrollView != null) {
+            mTabScrollView.removeAllTabs();
+        }
+        mSavedTabPosition = INVALID_POSITION;
+    }
+
+    public void setTitle(CharSequence title) {
+        mActionView.setTitle(title);
+    }
+
+    public void setSubtitle(CharSequence subtitle) {
+        mActionView.setSubtitle(subtitle);
+    }
+
+    public void setDisplayOptions(int options) {
+        mActionView.setDisplayOptions(options);
+    }
+
+    public void setDisplayOptions(int options, int mask) {
+        final int current = mActionView.getDisplayOptions();
+        mActionView.setDisplayOptions((options & mask) | (current & ~mask));
+    }
+
+    public void setBackgroundDrawable(Drawable d) {
+        mContainerView.setPrimaryBackground(d);
+    }
+
+    public void setStackedBackgroundDrawable(Drawable d) {
+        mContainerView.setStackedBackground(d);
+    }
+
+    public void setSplitBackgroundDrawable(Drawable d) {
+        if (mSplitView != null) {
+            mSplitView.setSplitBackground(d);
+        }
+    }
+
+    public View getCustomView() {
+        return mActionView.getCustomNavigationView();
+    }
+
+    public CharSequence getTitle() {
+        return mActionView.getTitle();
+    }
+
+    public CharSequence getSubtitle() {
+        return mActionView.getSubtitle();
+    }
+
+    public int getNavigationMode() {
+        return mActionView.getNavigationMode();
+    }
+
+    public int getDisplayOptions() {
+        return mActionView.getDisplayOptions();
+    }
+
+    public ActionMode startActionMode(ActionMode.Callback callback) {
+        boolean wasHidden = false;
+        if (mActionMode != null) {
+            wasHidden = mWasHiddenBeforeMode;
+            mActionMode.finish();
+        }
+
+        mContextView.killMode();
+        ActionModeImpl mode = new ActionModeImpl(callback);
+        if (mode.dispatchOnCreate()) {
+            mWasHiddenBeforeMode = !isShowing() || wasHidden;
+            mode.invalidate();
+            mContextView.initForMode(mode);
+            animateToMode(true);
+            if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
+                // TODO animate this
+                mSplitView.setVisibility(View.VISIBLE);
+            }
+            mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            mActionMode = mode;
+            return mode;
+        }
+        return null;
+    }
+
+    private void configureTab(Tab tab, int position) {
+        final TabImpl tabi = (TabImpl) tab;
+        final ActionBar.TabListener callback = tabi.getCallback();
+
+        if (callback == null) {
+            throw new IllegalStateException("Action Bar Tab must have a Callback");
+        }
+
+        tabi.setPosition(position);
+        mTabs.add(position, tabi);
+
+        final int count = mTabs.size();
+        for (int i = position + 1; i < count; i++) {
+            mTabs.get(i).setPosition(i);
+        }
+    }
+
+    @Override
+    public void addTab(Tab tab) {
+        addTab(tab, mTabs.isEmpty());
+    }
+
+    @Override
+    public void addTab(Tab tab, int position) {
+        addTab(tab, position, mTabs.isEmpty());
+    }
+
+    @Override
+    public void addTab(Tab tab, boolean setSelected) {
+        ensureTabsExist();
+        mTabScrollView.addTab(tab, setSelected);
+        configureTab(tab, mTabs.size());
+        if (setSelected) {
+            selectTab(tab);
+        }
+    }
+
+    @Override
+    public void addTab(Tab tab, int position, boolean setSelected) {
+        ensureTabsExist();
+        mTabScrollView.addTab(tab, position, setSelected);
+        configureTab(tab, position);
+        if (setSelected) {
+            selectTab(tab);
+        }
+    }
+
+    @Override
+    public Tab newTab() {
+        return new TabImpl();
+    }
+
+    @Override
+    public void removeTab(Tab tab) {
+        removeTabAt(tab.getPosition());
+    }
+
+    @Override
+    public void removeTabAt(int position) {
+        if (mTabScrollView == null) {
+            // No tabs around to remove
+            return;
+        }
+
+        int selectedTabPosition = mSelectedTab != null
+                ? mSelectedTab.getPosition() : mSavedTabPosition;
+        mTabScrollView.removeTabAt(position);
+        TabImpl removedTab = mTabs.remove(position);
+        if (removedTab != null) {
+            removedTab.setPosition(-1);
+        }
+
+        final int newTabCount = mTabs.size();
+        for (int i = position; i < newTabCount; i++) {
+            mTabs.get(i).setPosition(i);
+        }
+
+        if (selectedTabPosition == position) {
+            selectTab(mTabs.isEmpty() ? null : mTabs.get(Math.max(0, position - 1)));
+        }
+    }
+
+    @Override
+    public void selectTab(Tab tab) {
+        if (getNavigationMode() != NAVIGATION_MODE_TABS) {
+            mSavedTabPosition = tab != null ? tab.getPosition() : INVALID_POSITION;
+            return;
+        }
+
+        FragmentTransaction trans = null;
+        if (mActivity instanceof SherlockFragmentActivity) {
+            trans = ((SherlockFragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
+                    .disallowAddToBackStack();
+        }
+
+        if (mSelectedTab == tab) {
+            if (mSelectedTab != null) {
+                mSelectedTab.getCallback().onTabReselected(mSelectedTab, trans);
+                mTabScrollView.animateToTab(tab.getPosition());
+            }
+        } else {
+            mTabScrollView.setTabSelected(tab != null ? tab.getPosition() : Tab.INVALID_POSITION);
+            if (mSelectedTab != null) {
+                mSelectedTab.getCallback().onTabUnselected(mSelectedTab, trans);
+            }
+            mSelectedTab = (TabImpl) tab;
+            if (mSelectedTab != null) {
+                mSelectedTab.getCallback().onTabSelected(mSelectedTab, trans);
+            }
+        }
+
+        if (trans != null && !trans.isEmpty()) {
+            trans.commit();
+        }
+    }
+
+    @Override
+    public Tab getSelectedTab() {
+        return mSelectedTab;
+    }
+
+    @Override
+    public int getHeight() {
+        return mContainerView.getHeight();
+    }
+
+    @Override
+    public void show() {
+        show(true);
+    }
+
+    void show(boolean markHiddenBeforeMode) {
+        if (mCurrentShowAnim != null) {
+            mCurrentShowAnim.end();
+        }
+        if (mContainerView.getVisibility() == View.VISIBLE) {
+            if (markHiddenBeforeMode) mWasHiddenBeforeMode = false;
+            return;
+        }
+        mContainerView.setVisibility(View.VISIBLE);
+
+        if (mShowHideAnimationEnabled) {
+            mContainerView.setAlpha(0);
+            AnimatorSet anim = new AnimatorSet();
+            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 1));
+            if (mContentView != null) {
+                b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
+                        -mContainerView.getHeight(), 0));
+                mContainerView.setTranslationY(-mContainerView.getHeight());
+                b.with(ObjectAnimator.ofFloat(mContainerView, "translationY", 0));
+            }
+            if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
+                mSplitView.setAlpha(0);
+                mSplitView.setVisibility(View.VISIBLE);
+                b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 1));
+            }
+            anim.addListener(mShowListener);
+            mCurrentShowAnim = anim;
+            anim.start();
+        } else {
+            mContainerView.setAlpha(1);
+            mContainerView.setTranslationY(0);
+            mShowListener.onAnimationEnd(null);
+        }
+    }
+
+    @Override
+    public void hide() {
+        if (mCurrentShowAnim != null) {
+            mCurrentShowAnim.end();
+        }
+        if (mContainerView.getVisibility() == View.GONE) {
+            return;
+        }
+
+        if (mShowHideAnimationEnabled) {
+            mContainerView.setAlpha(1);
+            mContainerView.setTransitioning(true);
+            AnimatorSet anim = new AnimatorSet();
+            AnimatorSet.Builder b = anim.play(ObjectAnimator.ofFloat(mContainerView, "alpha", 0));
+            if (mContentView != null) {
+                b.with(ObjectAnimator.ofFloat(mContentView, "translationY",
+                        0, -mContainerView.getHeight()));
+                b.with(ObjectAnimator.ofFloat(mContainerView, "translationY",
+                        -mContainerView.getHeight()));
+            }
+            if (mSplitView != null && mSplitView.getVisibility() == View.VISIBLE) {
+                mSplitView.setAlpha(1);
+                b.with(ObjectAnimator.ofFloat(mSplitView, "alpha", 0));
+            }
+            anim.addListener(mHideListener);
+            mCurrentShowAnim = anim;
+            anim.start();
+        } else {
+            mHideListener.onAnimationEnd(null);
+        }
+    }
+
+    public boolean isShowing() {
+        return mContainerView.getVisibility() == View.VISIBLE;
+    }
+
+    void animateToMode(boolean toActionMode) {
+        if (toActionMode) {
+            show(false);
+        }
+        if (mCurrentModeAnim != null) {
+            mCurrentModeAnim.end();
+        }
+
+        mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
+        mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
+        if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) {
+            mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
+        }
+    }
+
+    public Context getThemedContext() {
+        if (mThemedContext == null) {
+            TypedValue outValue = new TypedValue();
+            Resources.Theme currentTheme = mContext.getTheme();
+            currentTheme.resolveAttribute(R.attr.actionBarWidgetTheme,
+                    outValue, true);
+            final int targetThemeRes = outValue.resourceId;
+
+            if (targetThemeRes != 0) { //XXX && mContext.getThemeResId() != targetThemeRes) {
+                mThemedContext = new ContextThemeWrapper(mContext, targetThemeRes);
+            } else {
+                mThemedContext = mContext;
+            }
+        }
+        return mThemedContext;
+    }
+
+    /**
+     * @hide
+     */
+    public class ActionModeImpl extends ActionMode implements MenuBuilder.Callback {
+        private ActionMode.Callback mCallback;
+        private MenuBuilder mMenu;
+        private WeakReference<View> mCustomView;
+
+        public ActionModeImpl(ActionMode.Callback callback) {
+            mCallback = callback;
+            mMenu = new MenuBuilder(getThemedContext())
+                    .setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+            mMenu.setCallback(this);
+        }
+
+        @Override
+        public MenuInflater getMenuInflater() {
+            return new MenuInflater(getThemedContext());
+        }
+
+        @Override
+        public Menu getMenu() {
+            return mMenu;
+        }
+
+        @Override
+        public void finish() {
+            if (mActionMode != this) {
+                // Not the active action mode - no-op
+                return;
+            }
+
+            // If we were hidden before the mode was shown, defer the onDestroy
+            // callback until the animation is finished and associated relayout
+            // is about to happen. This lets apps better anticipate visibility
+            // and layout behavior.
+            if (mWasHiddenBeforeMode) {
+                mDeferredDestroyActionMode = this;
+                mDeferredModeDestroyCallback = mCallback;
+            } else {
+                mCallback.onDestroyActionMode(this);
+            }
+            mCallback = null;
+            animateToMode(false);
+
+            // Clear out the context mode views after the animation finishes
+            mContextView.closeMode();
+            mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+
+            mActionMode = null;
+
+            if (mWasHiddenBeforeMode) {
+                hide();
+            }
+        }
+
+        @Override
+        public void invalidate() {
+            mMenu.stopDispatchingItemsChanged();
+            try {
+                mCallback.onPrepareActionMode(this, mMenu);
+            } finally {
+                mMenu.startDispatchingItemsChanged();
+            }
+        }
+
+        public boolean dispatchOnCreate() {
+            mMenu.stopDispatchingItemsChanged();
+            try {
+                return mCallback.onCreateActionMode(this, mMenu);
+            } finally {
+                mMenu.startDispatchingItemsChanged();
+            }
+        }
+
+        @Override
+        public void setCustomView(View view) {
+            mContextView.setCustomView(view);
+            mCustomView = new WeakReference<View>(view);
+        }
+
+        @Override
+        public void setSubtitle(CharSequence subtitle) {
+            mContextView.setSubtitle(subtitle);
+        }
+
+        @Override
+        public void setTitle(CharSequence title) {
+            mContextView.setTitle(title);
+        }
+
+        @Override
+        public void setTitle(int resId) {
+            setTitle(mContext.getResources().getString(resId));
+        }
+
+        @Override
+        public void setSubtitle(int resId) {
+            setSubtitle(mContext.getResources().getString(resId));
+        }
+
+        @Override
+        public CharSequence getTitle() {
+            return mContextView.getTitle();
+        }
+
+        @Override
+        public CharSequence getSubtitle() {
+            return mContextView.getSubtitle();
+        }
+
+        @Override
+        public View getCustomView() {
+            return mCustomView != null ? mCustomView.get() : null;
+        }
+
+        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+            if (mCallback != null) {
+                return mCallback.onActionItemClicked(this, item);
+            } else {
+                return false;
+            }
+        }
+
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        }
+
+        public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+            if (mCallback == null) {
+                return false;
+            }
+
+            if (!subMenu.hasVisibleItems()) {
+                return true;
+            }
+
+            new MenuPopupHelper(getThemedContext(), subMenu).show();
+            return true;
+        }
+
+        public void onCloseSubMenu(SubMenuBuilder menu) {
+        }
+
+        public void onMenuModeChange(MenuBuilder menu) {
+            if (mCallback == null) {
+                return;
+            }
+            invalidate();
+            mContextView.showOverflowMenu();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public class TabImpl extends ActionBar.Tab {
+        private ActionBar.TabListener mCallback;
+        private Object mTag;
+        private Drawable mIcon;
+        private CharSequence mText;
+        private CharSequence mContentDesc;
+        private int mPosition = -1;
+        private View mCustomView;
+
+        @Override
+        public Object getTag() {
+            return mTag;
+        }
+
+        @Override
+        public Tab setTag(Object tag) {
+            mTag = tag;
+            return this;
+        }
+
+        public ActionBar.TabListener getCallback() {
+            return mCallback;
+        }
+
+        @Override
+        public Tab setTabListener(ActionBar.TabListener callback) {
+            mCallback = callback;
+            return this;
+        }
+
+        @Override
+        public View getCustomView() {
+            return mCustomView;
+        }
+
+        @Override
+        public Tab setCustomView(View view) {
+            mCustomView = view;
+            if (mPosition >= 0) {
+                mTabScrollView.updateTab(mPosition);
+            }
+            return this;
+        }
+
+        @Override
+        public Tab setCustomView(int layoutResId) {
+            return setCustomView(LayoutInflater.from(getThemedContext())
+                    .inflate(layoutResId, null));
+        }
+
+        @Override
+        public Drawable getIcon() {
+            return mIcon;
+        }
+
+        @Override
+        public int getPosition() {
+            return mPosition;
+        }
+
+        public void setPosition(int position) {
+            mPosition = position;
+        }
+
+        @Override
+        public CharSequence getText() {
+            return mText;
+        }
+
+        @Override
+        public Tab setIcon(Drawable icon) {
+            mIcon = icon;
+            if (mPosition >= 0) {
+                mTabScrollView.updateTab(mPosition);
+            }
+            return this;
+        }
+
+        @Override
+        public Tab setIcon(int resId) {
+            return setIcon(mContext.getResources().getDrawable(resId));
+        }
+
+        @Override
+        public Tab setText(CharSequence text) {
+            mText = text;
+            if (mPosition >= 0) {
+                mTabScrollView.updateTab(mPosition);
+            }
+            return this;
+        }
+
+        @Override
+        public Tab setText(int resId) {
+            return setText(mContext.getResources().getText(resId));
+        }
+
+        @Override
+        public void select() {
+            selectTab(this);
+        }
+
+        @Override
+        public Tab setContentDescription(int resId) {
+            return setContentDescription(mContext.getResources().getText(resId));
+        }
+
+        @Override
+        public Tab setContentDescription(CharSequence contentDesc) {
+            mContentDesc = contentDesc;
+            if (mPosition >= 0) {
+                mTabScrollView.updateTab(mPosition);
+            }
+            return this;
+        }
+
+        @Override
+        public CharSequence getContentDescription() {
+            return mContentDesc;
+        }
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        mActionView.setCustomNavigationView(view);
+    }
+
+    @Override
+    public void setCustomView(View view, LayoutParams layoutParams) {
+        view.setLayoutParams(layoutParams);
+        mActionView.setCustomNavigationView(view);
+    }
+
+    @Override
+    public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
+        mActionView.setDropdownAdapter(adapter);
+        mActionView.setCallback(callback);
+    }
+
+    @Override
+    public int getSelectedNavigationIndex() {
+        switch (mActionView.getNavigationMode()) {
+            case NAVIGATION_MODE_TABS:
+                return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
+            case NAVIGATION_MODE_LIST:
+                return mActionView.getDropdownSelectedPosition();
+            default:
+                return -1;
+        }
+    }
+
+    @Override
+    public int getNavigationItemCount() {
+        switch (mActionView.getNavigationMode()) {
+            case NAVIGATION_MODE_TABS:
+                return mTabs.size();
+            case NAVIGATION_MODE_LIST:
+                SpinnerAdapter adapter = mActionView.getDropdownAdapter();
+                return adapter != null ? adapter.getCount() : 0;
+            default:
+                return 0;
+        }
+    }
+
+    @Override
+    public int getTabCount() {
+        return mTabs.size();
+    }
+
+    @Override
+    public void setNavigationMode(int mode) {
+        final int oldMode = mActionView.getNavigationMode();
+        switch (oldMode) {
+            case NAVIGATION_MODE_TABS:
+                mSavedTabPosition = getSelectedNavigationIndex();
+                selectTab(null);
+                mTabScrollView.setVisibility(View.GONE);
+                break;
+        }
+        mActionView.setNavigationMode(mode);
+        switch (mode) {
+            case NAVIGATION_MODE_TABS:
+                ensureTabsExist();
+                mTabScrollView.setVisibility(View.VISIBLE);
+                if (mSavedTabPosition != INVALID_POSITION) {
+                    setSelectedNavigationItem(mSavedTabPosition);
+                    mSavedTabPosition = INVALID_POSITION;
+                }
+                break;
+        }
+        mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
+    }
+
+    @Override
+    public Tab getTabAt(int index) {
+        return mTabs.get(index);
+    }
+
+
+    @Override
+    public void setIcon(int resId) {
+        mActionView.setIcon(resId);
+    }
+
+    @Override
+    public void setIcon(Drawable icon) {
+        mActionView.setIcon(icon);
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        mActionView.setLogo(resId);
+    }
+
+    @Override
+    public void setLogo(Drawable logo) {
+        mActionView.setLogo(logo);
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/app/ActionBarWrapper.java
new file mode 100644 (file)
index 0000000..e390ea4
--- /dev/null
@@ -0,0 +1,468 @@
+package com.actionbarsherlock.internal.app;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.v4.app.FragmentTransaction;
+import android.view.View;
+import android.widget.SpinnerAdapter;
+
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.SherlockFragmentActivity;
+
+public class ActionBarWrapper extends ActionBar implements android.app.ActionBar.OnNavigationListener, android.app.ActionBar.OnMenuVisibilityListener {
+    private final Activity mActivity;
+    private final android.app.ActionBar mActionBar;
+    private ActionBar.OnNavigationListener mNavigationListener;
+    private Set<OnMenuVisibilityListener> mMenuVisibilityListeners = new HashSet<OnMenuVisibilityListener>(1);
+    private FragmentTransaction mFragmentTransaction;
+
+
+    public ActionBarWrapper(Activity activity) {
+        mActivity = activity;
+        mActionBar = activity.getActionBar();
+        if (mActionBar != null) {
+            mActionBar.addOnMenuVisibilityListener(this);
+        }
+    }
+
+
+    @Override
+    public void setHomeButtonEnabled(boolean enabled) {
+        mActionBar.setHomeButtonEnabled(enabled);
+    }
+
+    @Override
+    public Context getThemedContext() {
+        return mActionBar.getThemedContext();
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        mActionBar.setCustomView(view);
+    }
+
+    @Override
+    public void setCustomView(View view, LayoutParams layoutParams) {
+        android.app.ActionBar.LayoutParams lp = new android.app.ActionBar.LayoutParams(layoutParams);
+        lp.gravity = layoutParams.gravity;
+        lp.bottomMargin = layoutParams.bottomMargin;
+        lp.topMargin = layoutParams.topMargin;
+        lp.leftMargin = layoutParams.leftMargin;
+        lp.rightMargin = layoutParams.rightMargin;
+        mActionBar.setCustomView(view, lp);
+    }
+
+    @Override
+    public void setCustomView(int resId) {
+        mActionBar.setCustomView(resId);
+    }
+
+    @Override
+    public void setIcon(int resId) {
+        mActionBar.setIcon(resId);
+    }
+
+    @Override
+    public void setIcon(Drawable icon) {
+        mActionBar.setIcon(icon);
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        mActionBar.setLogo(resId);
+    }
+
+    @Override
+    public void setLogo(Drawable logo) {
+        mActionBar.setLogo(logo);
+    }
+
+    @Override
+    public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
+        mNavigationListener = callback;
+        mActionBar.setListNavigationCallbacks(adapter, (callback != null) ? this : null);
+    }
+
+    @Override
+    public boolean onNavigationItemSelected(int itemPosition, long itemId) {
+        //This should never be a NullPointerException since we only set
+        //ourselves as the listener when the callback is not null.
+        return mNavigationListener.onNavigationItemSelected(itemPosition, itemId);
+    }
+
+    @Override
+    public void setSelectedNavigationItem(int position) {
+        mActionBar.setSelectedNavigationItem(position);
+    }
+
+    @Override
+    public int getSelectedNavigationIndex() {
+        return mActionBar.getSelectedNavigationIndex();
+    }
+
+    @Override
+    public int getNavigationItemCount() {
+        return mActionBar.getNavigationItemCount();
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        mActionBar.setTitle(title);
+    }
+
+    @Override
+    public void setTitle(int resId) {
+        mActionBar.setTitle(resId);
+    }
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        mActionBar.setSubtitle(subtitle);
+    }
+
+    @Override
+    public void setSubtitle(int resId) {
+        mActionBar.setSubtitle(resId);
+    }
+
+    @Override
+    public void setDisplayOptions(int options) {
+        mActionBar.setDisplayOptions(options);
+    }
+
+    @Override
+    public void setDisplayOptions(int options, int mask) {
+        mActionBar.setDisplayOptions(options, mask);
+    }
+
+    @Override
+    public void setDisplayUseLogoEnabled(boolean useLogo) {
+        mActionBar.setDisplayUseLogoEnabled(useLogo);
+    }
+
+    @Override
+    public void setDisplayShowHomeEnabled(boolean showHome) {
+        mActionBar.setDisplayShowHomeEnabled(showHome);
+    }
+
+    @Override
+    public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
+        mActionBar.setDisplayHomeAsUpEnabled(showHomeAsUp);
+    }
+
+    @Override
+    public void setDisplayShowTitleEnabled(boolean showTitle) {
+        mActionBar.setDisplayShowTitleEnabled(showTitle);
+    }
+
+    @Override
+    public void setDisplayShowCustomEnabled(boolean showCustom) {
+        mActionBar.setDisplayShowCustomEnabled(showCustom);
+    }
+
+    @Override
+    public void setBackgroundDrawable(Drawable d) {
+        mActionBar.setBackgroundDrawable(d);
+    }
+
+    @Override
+    public void setStackedBackgroundDrawable(Drawable d) {
+        mActionBar.setStackedBackgroundDrawable(d);
+    }
+
+    @Override
+    public void setSplitBackgroundDrawable(Drawable d) {
+        mActionBar.setSplitBackgroundDrawable(d);
+    }
+
+    @Override
+    public View getCustomView() {
+        return mActionBar.getCustomView();
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mActionBar.getTitle();
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        return mActionBar.getSubtitle();
+    }
+
+    @Override
+    public int getNavigationMode() {
+        return mActionBar.getNavigationMode();
+    }
+
+    @Override
+    public void setNavigationMode(int mode) {
+        mActionBar.setNavigationMode(mode);
+    }
+
+    @Override
+    public int getDisplayOptions() {
+        return mActionBar.getDisplayOptions();
+    }
+
+    public class TabWrapper extends ActionBar.Tab implements android.app.ActionBar.TabListener {
+        final android.app.ActionBar.Tab mNativeTab;
+        private Object mTag;
+        private TabListener mListener;
+
+        public TabWrapper(android.app.ActionBar.Tab nativeTab) {
+            mNativeTab = nativeTab;
+            mNativeTab.setTag(this);
+        }
+
+        @Override
+        public int getPosition() {
+            return mNativeTab.getPosition();
+        }
+
+        @Override
+        public Drawable getIcon() {
+            return mNativeTab.getIcon();
+        }
+
+        @Override
+        public CharSequence getText() {
+            return mNativeTab.getText();
+        }
+
+        @Override
+        public Tab setIcon(Drawable icon) {
+            mNativeTab.setIcon(icon);
+            return this;
+        }
+
+        @Override
+        public Tab setIcon(int resId) {
+            mNativeTab.setIcon(resId);
+            return this;
+        }
+
+        @Override
+        public Tab setText(CharSequence text) {
+            mNativeTab.setText(text);
+            return this;
+        }
+
+        @Override
+        public Tab setText(int resId) {
+            mNativeTab.setText(resId);
+            return this;
+        }
+
+        @Override
+        public Tab setCustomView(View view) {
+            mNativeTab.setCustomView(view);
+            return this;
+        }
+
+        @Override
+        public Tab setCustomView(int layoutResId) {
+            mNativeTab.setCustomView(layoutResId);
+            return this;
+        }
+
+        @Override
+        public View getCustomView() {
+            return mNativeTab.getCustomView();
+        }
+
+        @Override
+        public Tab setTag(Object obj) {
+            mTag = obj;
+            return this;
+        }
+
+        @Override
+        public Object getTag() {
+            return mTag;
+        }
+
+        @Override
+        public Tab setTabListener(TabListener listener) {
+            mNativeTab.setTabListener(listener != null ? this : null);
+            mListener = listener;
+            return this;
+        }
+
+        @Override
+        public void select() {
+            mNativeTab.select();
+        }
+
+        @Override
+        public Tab setContentDescription(int resId) {
+            mNativeTab.setContentDescription(resId);
+            return this;
+        }
+
+        @Override
+        public Tab setContentDescription(CharSequence contentDesc) {
+            mNativeTab.setContentDescription(contentDesc);
+            return this;
+        }
+
+        @Override
+        public CharSequence getContentDescription() {
+            return mNativeTab.getContentDescription();
+        }
+
+        @Override
+        public void onTabReselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
+            if (mListener != null) {
+                FragmentTransaction trans = null;
+                if (mActivity instanceof SherlockFragmentActivity) {
+                    trans = ((SherlockFragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
+                            .disallowAddToBackStack();
+                }
+
+                mListener.onTabReselected(this, trans);
+
+                if (trans != null && !trans.isEmpty()) {
+                    trans.commit();
+                }
+            }
+        }
+
+        @Override
+        public void onTabSelected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
+            if (mListener != null) {
+
+                if (mFragmentTransaction == null && mActivity instanceof SherlockFragmentActivity) {
+                    mFragmentTransaction = ((SherlockFragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
+                            .disallowAddToBackStack();
+                }
+
+                mListener.onTabSelected(this, mFragmentTransaction);
+
+                if (mFragmentTransaction != null) {
+                    if (!mFragmentTransaction.isEmpty()) {
+                        mFragmentTransaction.commit();
+                    }
+                    mFragmentTransaction = null;
+                }
+            }
+        }
+
+        @Override
+        public void onTabUnselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
+            if (mListener != null) {
+                FragmentTransaction trans = null;
+                if (mActivity instanceof SherlockFragmentActivity) {
+                    trans = ((SherlockFragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
+                            .disallowAddToBackStack();
+                    mFragmentTransaction = trans;
+                }
+
+                mListener.onTabUnselected(this, trans);
+            }
+        }
+    }
+
+    @Override
+    public Tab newTab() {
+        return new TabWrapper(mActionBar.newTab());
+    }
+
+    @Override
+    public void addTab(Tab tab) {
+        mActionBar.addTab(((TabWrapper)tab).mNativeTab);
+    }
+
+    @Override
+    public void addTab(Tab tab, boolean setSelected) {
+        mActionBar.addTab(((TabWrapper)tab).mNativeTab, setSelected);
+    }
+
+    @Override
+    public void addTab(Tab tab, int position) {
+        mActionBar.addTab(((TabWrapper)tab).mNativeTab, position);
+    }
+
+    @Override
+    public void addTab(Tab tab, int position, boolean setSelected) {
+        mActionBar.addTab(((TabWrapper)tab).mNativeTab, position, setSelected);
+    }
+
+    @Override
+    public void removeTab(Tab tab) {
+        mActionBar.removeTab(((TabWrapper)tab).mNativeTab);
+    }
+
+    @Override
+    public void removeTabAt(int position) {
+        mActionBar.removeTabAt(position);
+    }
+
+    @Override
+    public void removeAllTabs() {
+        mActionBar.removeAllTabs();
+    }
+
+    @Override
+    public void selectTab(Tab tab) {
+        mActionBar.selectTab(((TabWrapper)tab).mNativeTab);
+    }
+
+    @Override
+    public Tab getSelectedTab() {
+        android.app.ActionBar.Tab selected = mActionBar.getSelectedTab();
+        return (selected != null) ? (Tab)selected.getTag() : null;
+    }
+
+    @Override
+    public Tab getTabAt(int index) {
+        android.app.ActionBar.Tab selected = mActionBar.getTabAt(index);
+        return (selected != null) ? (Tab)selected.getTag() : null;
+    }
+
+    @Override
+    public int getTabCount() {
+        return mActionBar.getTabCount();
+    }
+
+    @Override
+    public int getHeight() {
+        return mActionBar.getHeight();
+    }
+
+    @Override
+    public void show() {
+        mActionBar.show();
+    }
+
+    @Override
+    public void hide() {
+        mActionBar.hide();
+    }
+
+    @Override
+    public boolean isShowing() {
+        return mActionBar.isShowing();
+    }
+
+    @Override
+    public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+        mMenuVisibilityListeners.add(listener);
+    }
+
+    @Override
+    public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+        mMenuVisibilityListeners.remove(listener);
+    }
+
+    @Override
+    public void onMenuVisibilityChanged(boolean isVisible) {
+        for (OnMenuVisibilityListener listener : mMenuVisibilityListeners) {
+            listener.onMenuVisibilityChanged(isVisible);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/Animator.java
new file mode 100644 (file)
index 0000000..2caf5b4
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+import java.util.ArrayList;
+
+import android.view.animation.Interpolator;
+
+/**
+ * This is the superclass for classes which provide basic support for animations which can be
+ * started, ended, and have <code>AnimatorListeners</code> added to them.
+ */
+public abstract class Animator implements Cloneable {
+
+
+    /**
+     * The set of listeners to be sent events through the life of an animation.
+     */
+    ArrayList<AnimatorListener> mListeners = null;
+
+    /**
+     * Starts this animation. If the animation has a nonzero startDelay, the animation will start
+     * running after that delay elapses. A non-delayed animation will have its initial
+     * value(s) set immediately, followed by calls to
+     * {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
+     *
+     * <p>The animation started by calling this method will be run on the thread that called
+     * this method. This thread should have a Looper on it (a runtime exception will be thrown if
+     * this is not the case). Also, if the animation will animate
+     * properties of objects in the view hierarchy, then the calling thread should be the UI
+     * thread for that view hierarchy.</p>
+     *
+     */
+    public void start() {
+    }
+
+    /**
+     * Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to
+     * stop in its tracks, sending an
+     * {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to
+     * its listeners, followed by an
+     * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message.
+     *
+     * <p>This method must be called on the thread that is running the animation.</p>
+     */
+    public void cancel() {
+    }
+
+    /**
+     * Ends the animation. This causes the animation to assign the end value of the property being
+     * animated, then calling the
+     * {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on
+     * its listeners.
+     *
+     * <p>This method must be called on the thread that is running the animation.</p>
+     */
+    public void end() {
+    }
+
+    /**
+     * The amount of time, in milliseconds, to delay starting the animation after
+     * {@link #start()} is called.
+     *
+     * @return the number of milliseconds to delay running the animation
+     */
+    public abstract long getStartDelay();
+
+    /**
+     * The amount of time, in milliseconds, to delay starting the animation after
+     * {@link #start()} is called.
+
+     * @param startDelay The amount of the delay, in milliseconds
+     */
+    public abstract void setStartDelay(long startDelay);
+
+
+    /**
+     * Sets the length of the animation.
+     *
+     * @param duration The length of the animation, in milliseconds.
+     */
+    public abstract Animator setDuration(long duration);
+
+    /**
+     * Gets the length of the animation.
+     *
+     * @return The length of the animation, in milliseconds.
+     */
+    public abstract long getDuration();
+
+    /**
+     * The time interpolator used in calculating the elapsed fraction of this animation. The
+     * interpolator determines whether the animation runs with linear or non-linear motion,
+     * such as acceleration and deceleration. The default value is
+     * {@link android.view.animation.AccelerateDecelerateInterpolator}
+     *
+     * @param value the interpolator to be used by this animation
+     */
+    public abstract void setInterpolator(/*Time*/Interpolator value);
+
+    /**
+     * Returns whether this Animator is currently running (having been started and gone past any
+     * initial startDelay period and not yet ended).
+     *
+     * @return Whether the Animator is running.
+     */
+    public abstract boolean isRunning();
+
+    /**
+     * Returns whether this Animator has been started and not yet ended. This state is a superset
+     * of the state of {@link #isRunning()}, because an Animator with a nonzero
+     * {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during the
+     * delay phase, whereas {@link #isRunning()} will return true only after the delay phase
+     * is complete.
+     *
+     * @return Whether the Animator has been started and not yet ended.
+     */
+    public boolean isStarted() {
+        // Default method returns value for isRunning(). Subclasses should override to return a
+        // real value.
+        return isRunning();
+    }
+
+    /**
+     * Adds a listener to the set of listeners that are sent events through the life of an
+     * animation, such as start, repeat, and end.
+     *
+     * @param listener the listener to be added to the current set of listeners for this animation.
+     */
+    public void addListener(AnimatorListener listener) {
+        if (mListeners == null) {
+            mListeners = new ArrayList<AnimatorListener>();
+        }
+        mListeners.add(listener);
+    }
+
+    /**
+     * Removes a listener from the set listening to this animation.
+     *
+     * @param listener the listener to be removed from the current set of listeners for this
+     *                 animation.
+     */
+    public void removeListener(AnimatorListener listener) {
+        if (mListeners == null) {
+            return;
+        }
+        mListeners.remove(listener);
+        if (mListeners.size() == 0) {
+            mListeners = null;
+        }
+    }
+
+    /**
+     * Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently
+     * listening for events on this <code>Animator</code> object.
+     *
+     * @return ArrayList<AnimatorListener> The set of listeners.
+     */
+    public ArrayList<AnimatorListener> getListeners() {
+        return mListeners;
+    }
+
+    /**
+     * Removes all listeners from this object. This is equivalent to calling
+     * <code>getListeners()</code> followed by calling <code>clear()</code> on the
+     * returned list of listeners.
+     */
+    public void removeAllListeners() {
+        if (mListeners != null) {
+            mListeners.clear();
+            mListeners = null;
+        }
+    }
+
+    @Override
+    public Animator clone() {
+        try {
+            final Animator anim = (Animator) super.clone();
+            if (mListeners != null) {
+                ArrayList<AnimatorListener> oldListeners = mListeners;
+                anim.mListeners = new ArrayList<AnimatorListener>();
+                int numListeners = oldListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    anim.mListeners.add(oldListeners.get(i));
+                }
+            }
+            return anim;
+        } catch (CloneNotSupportedException e) {
+           throw new AssertionError();
+        }
+    }
+
+    /**
+     * This method tells the object to use appropriate information to extract
+     * starting values for the animation. For example, a AnimatorSet object will pass
+     * this call to its child objects to tell them to set up the values. A
+     * ObjectAnimator object will use the information it has about its target object
+     * and PropertyValuesHolder objects to get the start values for its properties.
+     * An ValueAnimator object will ignore the request since it does not have enough
+     * information (such as a target object) to gather these values.
+     */
+    public void setupStartValues() {
+    }
+
+    /**
+     * This method tells the object to use appropriate information to extract
+     * ending values for the animation. For example, a AnimatorSet object will pass
+     * this call to its child objects to tell them to set up the values. A
+     * ObjectAnimator object will use the information it has about its target object
+     * and PropertyValuesHolder objects to get the start values for its properties.
+     * An ValueAnimator object will ignore the request since it does not have enough
+     * information (such as a target object) to gather these values.
+     */
+    public void setupEndValues() {
+    }
+
+    /**
+     * Sets the target object whose property will be animated by this animation. Not all subclasses
+     * operate on target objects (for example, {@link ValueAnimator}, but this method
+     * is on the superclass for the convenience of dealing generically with those subclasses
+     * that do handle targets.
+     *
+     * @param target The object being animated
+     */
+    public void setTarget(Object target) {
+    }
+
+    /**
+     * <p>An animation listener receives notifications from an animation.
+     * Notifications indicate animation related events, such as the end or the
+     * repetition of the animation.</p>
+     */
+    public static interface AnimatorListener {
+        /**
+         * <p>Notifies the start of the animation.</p>
+         *
+         * @param animation The started animation.
+         */
+        void onAnimationStart(Animator animation);
+
+        /**
+         * <p>Notifies the end of the animation. This callback is not invoked
+         * for animations with repeat count set to INFINITE.</p>
+         *
+         * @param animation The animation which reached its end.
+         */
+        void onAnimationEnd(Animator animation);
+
+        /**
+         * <p>Notifies the cancellation of the animation. This callback is not invoked
+         * for animations with repeat count set to INFINITE.</p>
+         *
+         * @param animation The animation which was canceled.
+         */
+        void onAnimationCancel(Animator animation);
+
+        /**
+         * <p>Notifies the repetition of the animation.</p>
+         *
+         * @param animation The animation which was repeated.
+         */
+        void onAnimationRepeat(Animator animation);
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorListenerAdapter.java
new file mode 100644 (file)
index 0000000..02ddff4
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+/**
+ * This adapter class provides empty implementations of the methods from {@link android.animation.Animator.AnimatorListener}.
+ * Any custom listener that cares only about a subset of the methods of this listener can
+ * simply subclass this adapter class instead of implementing the interface directly.
+ */
+public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAnimationCancel(Animator animation) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAnimationEnd(Animator animation) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAnimationRepeat(Animator animation) {
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onAnimationStart(Animator animation) {
+    }
+
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/AnimatorSet.java
new file mode 100644 (file)
index 0000000..3231080
--- /dev/null
@@ -0,0 +1,1111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+import android.view.animation.Interpolator;
+
+/**
+ * This class plays a set of {@link Animator} objects in the specified order. Animations
+ * can be set up to play together, in sequence, or after a specified delay.
+ *
+ * <p>There are two different approaches to adding animations to a <code>AnimatorSet</code>:
+ * either the {@link AnimatorSet#playTogether(Animator[]) playTogether()} or
+ * {@link AnimatorSet#playSequentially(Animator[]) playSequentially()} methods can be called to add
+ * a set of animations all at once, or the {@link AnimatorSet#play(Animator)} can be
+ * used in conjunction with methods in the {@link AnimatorSet.Builder Builder}
+ * class to add animations
+ * one by one.</p>
+ *
+ * <p>It is possible to set up a <code>AnimatorSet</code> with circular dependencies between
+ * its animations. For example, an animation a1 could be set up to start before animation a2, a2
+ * before a3, and a3 before a1. The results of this configuration are undefined, but will typically
+ * result in none of the affected animations being played. Because of this (and because
+ * circular dependencies do not make logical sense anyway), circular dependencies
+ * should be avoided, and the dependency flow of animations should only be in one direction.
+ */
+@SuppressWarnings("unchecked")
+public final class AnimatorSet extends Animator {
+
+    /**
+     * Internal variables
+     * NOTE: This object implements the clone() method, making a deep copy of any referenced
+     * objects. As other non-trivial fields are added to this class, make sure to add logic
+     * to clone() to make deep copies of them.
+     */
+
+    /**
+     * Tracks animations currently being played, so that we know what to
+     * cancel or end when cancel() or end() is called on this AnimatorSet
+     */
+    private ArrayList<Animator> mPlayingSet = new ArrayList<Animator>();
+
+    /**
+     * Contains all nodes, mapped to their respective Animators. When new
+     * dependency information is added for an Animator, we want to add it
+     * to a single node representing that Animator, not create a new Node
+     * if one already exists.
+     */
+    private HashMap<Animator, Node> mNodeMap = new HashMap<Animator, Node>();
+
+    /**
+     * Set of all nodes created for this AnimatorSet. This list is used upon
+     * starting the set, and the nodes are placed in sorted order into the
+     * sortedNodes collection.
+     */
+    private ArrayList<Node> mNodes = new ArrayList<Node>();
+
+    /**
+     * The sorted list of nodes. This is the order in which the animations will
+     * be played. The details about when exactly they will be played depend
+     * on the dependency relationships of the nodes.
+     */
+    private ArrayList<Node> mSortedNodes = new ArrayList<Node>();
+
+    /**
+     * Flag indicating whether the nodes should be sorted prior to playing. This
+     * flag allows us to cache the previous sorted nodes so that if the sequence
+     * is replayed with no changes, it does not have to re-sort the nodes again.
+     */
+    private boolean mNeedsSort = true;
+
+    private AnimatorSetListener mSetListener = null;
+
+    /**
+     * Flag indicating that the AnimatorSet has been manually
+     * terminated (by calling cancel() or end()).
+     * This flag is used to avoid starting other animations when currently-playing
+     * child animations of this AnimatorSet end. It also determines whether cancel/end
+     * notifications are sent out via the normal AnimatorSetListener mechanism.
+     */
+    boolean mTerminated = false;
+
+    /**
+     * Indicates whether an AnimatorSet has been start()'d, whether or
+     * not there is a nonzero startDelay.
+     */
+    private boolean mStarted = false;
+
+    // The amount of time in ms to delay starting the animation after start() is called
+    private long mStartDelay = 0;
+
+    // Animator used for a nonzero startDelay
+    private ValueAnimator mDelayAnim = null;
+
+
+    // How long the child animations should last in ms. The default value is negative, which
+    // simply means that there is no duration set on the AnimatorSet. When a real duration is
+    // set, it is passed along to the child animations.
+    private long mDuration = -1;
+
+
+    /**
+     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
+     *
+     * @param items The animations that will be started simultaneously.
+     */
+    public void playTogether(Animator... items) {
+        if (items != null) {
+            mNeedsSort = true;
+            Builder builder = play(items[0]);
+            for (int i = 1; i < items.length; ++i) {
+                builder.with(items[i]);
+            }
+        }
+    }
+
+    /**
+     * Sets up this AnimatorSet to play all of the supplied animations at the same time.
+     *
+     * @param items The animations that will be started simultaneously.
+     */
+    public void playTogether(Collection<Animator> items) {
+        if (items != null && items.size() > 0) {
+            mNeedsSort = true;
+            Builder builder = null;
+            for (Animator anim : items) {
+                if (builder == null) {
+                    builder = play(anim);
+                } else {
+                    builder.with(anim);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets up this AnimatorSet to play each of the supplied animations when the
+     * previous animation ends.
+     *
+     * @param items The animations that will be started one after another.
+     */
+    public void playSequentially(Animator... items) {
+        if (items != null) {
+            mNeedsSort = true;
+            if (items.length == 1) {
+                play(items[0]);
+            } else {
+                for (int i = 0; i < items.length - 1; ++i) {
+                    play(items[i]).before(items[i+1]);
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets up this AnimatorSet to play each of the supplied animations when the
+     * previous animation ends.
+     *
+     * @param items The animations that will be started one after another.
+     */
+    public void playSequentially(List<Animator> items) {
+        if (items != null && items.size() > 0) {
+            mNeedsSort = true;
+            if (items.size() == 1) {
+                play(items.get(0));
+            } else {
+                for (int i = 0; i < items.size() - 1; ++i) {
+                    play(items.get(i)).before(items.get(i+1));
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the current list of child Animator objects controlled by this
+     * AnimatorSet. This is a copy of the internal list; modifications to the returned list
+     * will not affect the AnimatorSet, although changes to the underlying Animator objects
+     * will affect those objects being managed by the AnimatorSet.
+     *
+     * @return ArrayList<Animator> The list of child animations of this AnimatorSet.
+     */
+    public ArrayList<Animator> getChildAnimations() {
+        ArrayList<Animator> childList = new ArrayList<Animator>();
+        for (Node node : mNodes) {
+            childList.add(node.animation);
+        }
+        return childList;
+    }
+
+    /**
+     * Sets the target object for all current {@link #getChildAnimations() child animations}
+     * of this AnimatorSet that take targets ({@link ObjectAnimator} and
+     * AnimatorSet).
+     *
+     * @param target The object being animated
+     */
+    @Override
+    public void setTarget(Object target) {
+        for (Node node : mNodes) {
+            Animator animation = node.animation;
+            if (animation instanceof AnimatorSet) {
+                ((AnimatorSet)animation).setTarget(target);
+            } else if (animation instanceof ObjectAnimator) {
+                ((ObjectAnimator)animation).setTarget(target);
+            }
+        }
+    }
+
+    /**
+     * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations}
+     * of this AnimatorSet.
+     *
+     * @param interpolator the interpolator to be used by each child animation of this AnimatorSet
+     */
+    @Override
+    public void setInterpolator(/*Time*/Interpolator interpolator) {
+        for (Node node : mNodes) {
+            node.animation.setInterpolator(interpolator);
+        }
+    }
+
+    /**
+     * This method creates a <code>Builder</code> object, which is used to
+     * set up playing constraints. This initial <code>play()</code> method
+     * tells the <code>Builder</code> the animation that is the dependency for
+     * the succeeding commands to the <code>Builder</code>. For example,
+     * calling <code>play(a1).with(a2)</code> sets up the AnimatorSet to play
+     * <code>a1</code> and <code>a2</code> at the same time,
+     * <code>play(a1).before(a2)</code> sets up the AnimatorSet to play
+     * <code>a1</code> first, followed by <code>a2</code>, and
+     * <code>play(a1).after(a2)</code> sets up the AnimatorSet to play
+     * <code>a2</code> first, followed by <code>a1</code>.
+     *
+     * <p>Note that <code>play()</code> is the only way to tell the
+     * <code>Builder</code> the animation upon which the dependency is created,
+     * so successive calls to the various functions in <code>Builder</code>
+     * will all refer to the initial parameter supplied in <code>play()</code>
+     * as the dependency of the other animations. For example, calling
+     * <code>play(a1).before(a2).before(a3)</code> will play both <code>a2</code>
+     * and <code>a3</code> when a1 ends; it does not set up a dependency between
+     * <code>a2</code> and <code>a3</code>.</p>
+     *
+     * @param anim The animation that is the dependency used in later calls to the
+     * methods in the returned <code>Builder</code> object. A null parameter will result
+     * in a null <code>Builder</code> return value.
+     * @return Builder The object that constructs the AnimatorSet based on the dependencies
+     * outlined in the calls to <code>play</code> and the other methods in the
+     * <code>Builder</code object.
+     */
+    public Builder play(Animator anim) {
+        if (anim != null) {
+            mNeedsSort = true;
+            return new Builder(anim);
+        }
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Note that canceling a <code>AnimatorSet</code> also cancels all of the animations that it
+     * is responsible for.</p>
+     */
+    @Override
+    public void cancel() {
+        mTerminated = true;
+        if (isStarted()) {
+            ArrayList<AnimatorListener> tmpListeners = null;
+            if (mListeners != null) {
+                tmpListeners = (ArrayList<AnimatorListener>) mListeners.clone();
+                for (AnimatorListener listener : tmpListeners) {
+                    listener.onAnimationCancel(this);
+                }
+            }
+            if (mDelayAnim != null && mDelayAnim.isRunning()) {
+                // If we're currently in the startDelay period, just cancel that animator and
+                // send out the end event to all listeners
+                mDelayAnim.cancel();
+            } else  if (mSortedNodes.size() > 0) {
+                for (Node node : mSortedNodes) {
+                    node.animation.cancel();
+                }
+            }
+            if (tmpListeners != null) {
+                for (AnimatorListener listener : tmpListeners) {
+                    listener.onAnimationEnd(this);
+                }
+            }
+            mStarted = false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Note that ending a <code>AnimatorSet</code> also ends all of the animations that it is
+     * responsible for.</p>
+     */
+    @Override
+    public void end() {
+        mTerminated = true;
+        if (isStarted()) {
+            if (mSortedNodes.size() != mNodes.size()) {
+                // hasn't been started yet - sort the nodes now, then end them
+                sortNodes();
+                for (Node node : mSortedNodes) {
+                    if (mSetListener == null) {
+                        mSetListener = new AnimatorSetListener(this);
+                    }
+                    node.animation.addListener(mSetListener);
+                }
+            }
+            if (mDelayAnim != null) {
+                mDelayAnim.cancel();
+            }
+            if (mSortedNodes.size() > 0) {
+                for (Node node : mSortedNodes) {
+                    node.animation.end();
+                }
+            }
+            if (mListeners != null) {
+                ArrayList<AnimatorListener> tmpListeners =
+                        (ArrayList<AnimatorListener>) mListeners.clone();
+                for (AnimatorListener listener : tmpListeners) {
+                    listener.onAnimationEnd(this);
+                }
+            }
+            mStarted = false;
+        }
+    }
+
+    /**
+     * Returns true if any of the child animations of this AnimatorSet have been started and have
+     * not yet ended.
+     * @return Whether this AnimatorSet has been started and has not yet ended.
+     */
+    @Override
+    public boolean isRunning() {
+        for (Node node : mNodes) {
+            if (node.animation.isRunning()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isStarted() {
+        return mStarted;
+    }
+
+    /**
+     * The amount of time, in milliseconds, to delay starting the animation after
+     * {@link #start()} is called.
+     *
+     * @return the number of milliseconds to delay running the animation
+     */
+    @Override
+    public long getStartDelay() {
+        return mStartDelay;
+    }
+
+    /**
+     * The amount of time, in milliseconds, to delay starting the animation after
+     * {@link #start()} is called.
+
+     * @param startDelay The amount of the delay, in milliseconds
+     */
+    @Override
+    public void setStartDelay(long startDelay) {
+        mStartDelay = startDelay;
+    }
+
+    /**
+     * Gets the length of each of the child animations of this AnimatorSet. This value may
+     * be less than 0, which indicates that no duration has been set on this AnimatorSet
+     * and each of the child animations will use their own duration.
+     *
+     * @return The length of the animation, in milliseconds, of each of the child
+     * animations of this AnimatorSet.
+     */
+    @Override
+    public long getDuration() {
+        return mDuration;
+    }
+
+    /**
+     * Sets the length of each of the current child animations of this AnimatorSet. By default,
+     * each child animation will use its own duration. If the duration is set on the AnimatorSet,
+     * then each child animation inherits this duration.
+     *
+     * @param duration The length of the animation, in milliseconds, of each of the child
+     * animations of this AnimatorSet.
+     */
+    @Override
+    public AnimatorSet setDuration(long duration) {
+        if (duration < 0) {
+            throw new IllegalArgumentException("duration must be a value of zero or greater");
+        }
+        for (Node node : mNodes) {
+            // TODO: don't set the duration of the timing-only nodes created by AnimatorSet to
+            // insert "play-after" delays
+            node.animation.setDuration(duration);
+        }
+        mDuration = duration;
+        return this;
+    }
+
+    @Override
+    public void setupStartValues() {
+        for (Node node : mNodes) {
+            node.animation.setupStartValues();
+        }
+    }
+
+    @Override
+    public void setupEndValues() {
+        for (Node node : mNodes) {
+            node.animation.setupEndValues();
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>Starting this <code>AnimatorSet</code> will, in turn, start the animations for which
+     * it is responsible. The details of when exactly those animations are started depends on
+     * the dependency relationships that have been set up between the animations.
+     */
+    @Override
+    public void start() {
+        mTerminated = false;
+        mStarted = true;
+
+        // First, sort the nodes (if necessary). This will ensure that sortedNodes
+        // contains the animation nodes in the correct order.
+        sortNodes();
+
+        int numSortedNodes = mSortedNodes.size();
+        for (int i = 0; i < numSortedNodes; ++i) {
+            Node node = mSortedNodes.get(i);
+            // First, clear out the old listeners
+            ArrayList<AnimatorListener> oldListeners = node.animation.getListeners();
+            if (oldListeners != null && oldListeners.size() > 0) {
+                final ArrayList<AnimatorListener> clonedListeners = new
+                        ArrayList<AnimatorListener>(oldListeners);
+
+                for (AnimatorListener listener : clonedListeners) {
+                    if (listener instanceof DependencyListener ||
+                            listener instanceof AnimatorSetListener) {
+                        node.animation.removeListener(listener);
+                    }
+                }
+            }
+        }
+
+        // nodesToStart holds the list of nodes to be started immediately. We don't want to
+        // start the animations in the loop directly because we first need to set up
+        // dependencies on all of the nodes. For example, we don't want to start an animation
+        // when some other animation also wants to start when the first animation begins.
+        final ArrayList<Node> nodesToStart = new ArrayList<Node>();
+        for (int i = 0; i < numSortedNodes; ++i) {
+            Node node = mSortedNodes.get(i);
+            if (mSetListener == null) {
+                mSetListener = new AnimatorSetListener(this);
+            }
+            if (node.dependencies == null || node.dependencies.size() == 0) {
+                nodesToStart.add(node);
+            } else {
+                int numDependencies = node.dependencies.size();
+                for (int j = 0; j < numDependencies; ++j) {
+                    Dependency dependency = node.dependencies.get(j);
+                    dependency.node.animation.addListener(
+                            new DependencyListener(this, node, dependency.rule));
+                }
+                node.tmpDependencies = (ArrayList<Dependency>) node.dependencies.clone();
+            }
+            node.animation.addListener(mSetListener);
+        }
+        // Now that all dependencies are set up, start the animations that should be started.
+        if (mStartDelay <= 0) {
+            for (Node node : nodesToStart) {
+                node.animation.start();
+                mPlayingSet.add(node.animation);
+            }
+        } else {
+            mDelayAnim = ValueAnimator.ofFloat(0f, 1f);
+            mDelayAnim.setDuration(mStartDelay);
+            mDelayAnim.addListener(new AnimatorListenerAdapter() {
+                boolean canceled = false;
+                public void onAnimationCancel(Animator anim) {
+                    canceled = true;
+                }
+                public void onAnimationEnd(Animator anim) {
+                    if (!canceled) {
+                        int numNodes = nodesToStart.size();
+                        for (int i = 0; i < numNodes; ++i) {
+                            Node node = nodesToStart.get(i);
+                            node.animation.start();
+                            mPlayingSet.add(node.animation);
+                        }
+                    }
+                }
+            });
+            mDelayAnim.start();
+        }
+        if (mListeners != null) {
+            ArrayList<AnimatorListener> tmpListeners =
+                    (ArrayList<AnimatorListener>) mListeners.clone();
+            int numListeners = tmpListeners.size();
+            for (int i = 0; i < numListeners; ++i) {
+                tmpListeners.get(i).onAnimationStart(this);
+            }
+        }
+        if (mNodes.size() == 0 && mStartDelay == 0) {
+            // Handle unusual case where empty AnimatorSet is started - should send out
+            // end event immediately since the event will not be sent out at all otherwise
+            mStarted = false;
+            if (mListeners != null) {
+                ArrayList<AnimatorListener> tmpListeners =
+                        (ArrayList<AnimatorListener>) mListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onAnimationEnd(this);
+                }
+            }
+        }
+    }
+
+    @Override
+    public AnimatorSet clone() {
+        final AnimatorSet anim = (AnimatorSet) super.clone();
+        /*
+         * The basic clone() operation copies all items. This doesn't work very well for
+         * AnimatorSet, because it will copy references that need to be recreated and state
+         * that may not apply. What we need to do now is put the clone in an uninitialized
+         * state, with fresh, empty data structures. Then we will build up the nodes list
+         * manually, as we clone each Node (and its animation). The clone will then be sorted,
+         * and will populate any appropriate lists, when it is started.
+         */
+        anim.mNeedsSort = true;
+        anim.mTerminated = false;
+        anim.mStarted = false;
+        anim.mPlayingSet = new ArrayList<Animator>();
+        anim.mNodeMap = new HashMap<Animator, Node>();
+        anim.mNodes = new ArrayList<Node>();
+        anim.mSortedNodes = new ArrayList<Node>();
+
+        // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
+        // One problem is that the old node dependencies point to nodes in the old AnimatorSet.
+        // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
+        HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>(); // <old, new>
+        for (Node node : mNodes) {
+            Node nodeClone = node.clone();
+            nodeCloneMap.put(node, nodeClone);
+            anim.mNodes.add(nodeClone);
+            anim.mNodeMap.put(nodeClone.animation, nodeClone);
+            // Clear out the dependencies in the clone; we'll set these up manually later
+            nodeClone.dependencies = null;
+            nodeClone.tmpDependencies = null;
+            nodeClone.nodeDependents = null;
+            nodeClone.nodeDependencies = null;
+            // clear out any listeners that were set up by the AnimatorSet; these will
+            // be set up when the clone's nodes are sorted
+            ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
+            if (cloneListeners != null) {
+                ArrayList<AnimatorListener> listenersToRemove = null;
+                for (AnimatorListener listener : cloneListeners) {
+                    if (listener instanceof AnimatorSetListener) {
+                        if (listenersToRemove == null) {
+                            listenersToRemove = new ArrayList<AnimatorListener>();
+                        }
+                        listenersToRemove.add(listener);
+                    }
+                }
+                if (listenersToRemove != null) {
+                    for (AnimatorListener listener : listenersToRemove) {
+                        cloneListeners.remove(listener);
+                    }
+                }
+            }
+        }
+        // Now that we've cloned all of the nodes, we're ready to walk through their
+        // dependencies, mapping the old dependencies to the new nodes
+        for (Node node : mNodes) {
+            Node nodeClone = nodeCloneMap.get(node);
+            if (node.dependencies != null) {
+                for (Dependency dependency : node.dependencies) {
+                    Node clonedDependencyNode = nodeCloneMap.get(dependency.node);
+                    Dependency cloneDependency = new Dependency(clonedDependencyNode,
+                            dependency.rule);
+                    nodeClone.addDependency(cloneDependency);
+                }
+            }
+        }
+
+        return anim;
+    }
+
+    /**
+     * This class is the mechanism by which animations are started based on events in other
+     * animations. If an animation has multiple dependencies on other animations, then
+     * all dependencies must be satisfied before the animation is started.
+     */
+    private static class DependencyListener implements AnimatorListener {
+
+        private AnimatorSet mAnimatorSet;
+
+        // The node upon which the dependency is based.
+        private Node mNode;
+
+        // The Dependency rule (WITH or AFTER) that the listener should wait for on
+        // the node
+        private int mRule;
+
+        public DependencyListener(AnimatorSet animatorSet, Node node, int rule) {
+            this.mAnimatorSet = animatorSet;
+            this.mNode = node;
+            this.mRule = rule;
+        }
+
+        /**
+         * Ignore cancel events for now. We may want to handle this eventually,
+         * to prevent follow-on animations from running when some dependency
+         * animation is canceled.
+         */
+        public void onAnimationCancel(Animator animation) {
+        }
+
+        /**
+         * An end event is received - see if this is an event we are listening for
+         */
+        public void onAnimationEnd(Animator animation) {
+            if (mRule == Dependency.AFTER) {
+                startIfReady(animation);
+            }
+        }
+
+        /**
+         * Ignore repeat events for now
+         */
+        public void onAnimationRepeat(Animator animation) {
+        }
+
+        /**
+         * A start event is received - see if this is an event we are listening for
+         */
+        public void onAnimationStart(Animator animation) {
+            if (mRule == Dependency.WITH) {
+                startIfReady(animation);
+            }
+        }
+
+        /**
+         * Check whether the event received is one that the node was waiting for.
+         * If so, mark it as complete and see whether it's time to start
+         * the animation.
+         * @param dependencyAnimation the animation that sent the event.
+         */
+        private void startIfReady(Animator dependencyAnimation) {
+            if (mAnimatorSet.mTerminated) {
+                // if the parent AnimatorSet was canceled, then don't start any dependent anims
+                return;
+            }
+            Dependency dependencyToRemove = null;
+            int numDependencies = mNode.tmpDependencies.size();
+            for (int i = 0; i < numDependencies; ++i) {
+                Dependency dependency = mNode.tmpDependencies.get(i);
+                if (dependency.rule == mRule &&
+                        dependency.node.animation == dependencyAnimation) {
+                    // rule fired - remove the dependency and listener and check to
+                    // see whether it's time to start the animation
+                    dependencyToRemove = dependency;
+                    dependencyAnimation.removeListener(this);
+                    break;
+                }
+            }
+            mNode.tmpDependencies.remove(dependencyToRemove);
+            if (mNode.tmpDependencies.size() == 0) {
+                // all dependencies satisfied: start the animation
+                mNode.animation.start();
+                mAnimatorSet.mPlayingSet.add(mNode.animation);
+            }
+        }
+
+    }
+
+    private class AnimatorSetListener implements AnimatorListener {
+
+        private AnimatorSet mAnimatorSet;
+
+        AnimatorSetListener(AnimatorSet animatorSet) {
+            mAnimatorSet = animatorSet;
+        }
+
+        public void onAnimationCancel(Animator animation) {
+            if (!mTerminated) {
+                // Listeners are already notified of the AnimatorSet canceling in cancel().
+                // The logic below only kicks in when animations end normally
+                if (mPlayingSet.size() == 0) {
+                    if (mListeners != null) {
+                        int numListeners = mListeners.size();
+                        for (int i = 0; i < numListeners; ++i) {
+                            mListeners.get(i).onAnimationCancel(mAnimatorSet);
+                        }
+                    }
+                }
+            }
+        }
+
+        public void onAnimationEnd(Animator animation) {
+            animation.removeListener(this);
+            mPlayingSet.remove(animation);
+            Node animNode = mAnimatorSet.mNodeMap.get(animation);
+            animNode.done = true;
+            if (!mTerminated) {
+                // Listeners are already notified of the AnimatorSet ending in cancel() or
+                // end(); the logic below only kicks in when animations end normally
+                ArrayList<Node> sortedNodes = mAnimatorSet.mSortedNodes;
+                boolean allDone = true;
+                int numSortedNodes = sortedNodes.size();
+                for (int i = 0; i < numSortedNodes; ++i) {
+                    if (!sortedNodes.get(i).done) {
+                        allDone = false;
+                        break;
+                    }
+                }
+                if (allDone) {
+                    // If this was the last child animation to end, then notify listeners that this
+                    // AnimatorSet has ended
+                    if (mListeners != null) {
+                        ArrayList<AnimatorListener> tmpListeners =
+                                (ArrayList<AnimatorListener>) mListeners.clone();
+                        int numListeners = tmpListeners.size();
+                        for (int i = 0; i < numListeners; ++i) {
+                            tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
+                        }
+                    }
+                    mAnimatorSet.mStarted = false;
+                }
+            }
+        }
+
+        // Nothing to do
+        public void onAnimationRepeat(Animator animation) {
+        }
+
+        // Nothing to do
+        public void onAnimationStart(Animator animation) {
+        }
+
+    }
+
+    /**
+     * This method sorts the current set of nodes, if needed. The sort is a simple
+     * DependencyGraph sort, which goes like this:
+     * - All nodes without dependencies become 'roots'
+     * - while roots list is not null
+     * -   for each root r
+     * -     add r to sorted list
+     * -     remove r as a dependency from any other node
+     * -   any nodes with no dependencies are added to the roots list
+     */
+    private void sortNodes() {
+        if (mNeedsSort) {
+            mSortedNodes.clear();
+            ArrayList<Node> roots = new ArrayList<Node>();
+            int numNodes = mNodes.size();
+            for (int i = 0; i < numNodes; ++i) {
+                Node node = mNodes.get(i);
+                if (node.dependencies == null || node.dependencies.size() == 0) {
+                    roots.add(node);
+                }
+            }
+            ArrayList<Node> tmpRoots = new ArrayList<Node>();
+            while (roots.size() > 0) {
+                int numRoots = roots.size();
+                for (int i = 0; i < numRoots; ++i) {
+                    Node root = roots.get(i);
+                    mSortedNodes.add(root);
+                    if (root.nodeDependents != null) {
+                        int numDependents = root.nodeDependents.size();
+                        for (int j = 0; j < numDependents; ++j) {
+                            Node node = root.nodeDependents.get(j);
+                            node.nodeDependencies.remove(root);
+                            if (node.nodeDependencies.size() == 0) {
+                                tmpRoots.add(node);
+                            }
+                        }
+                    }
+                }
+                roots.clear();
+                roots.addAll(tmpRoots);
+                tmpRoots.clear();
+            }
+            mNeedsSort = false;
+            if (mSortedNodes.size() != mNodes.size()) {
+                throw new IllegalStateException("Circular dependencies cannot exist"
+                        + " in AnimatorSet");
+            }
+        } else {
+            // Doesn't need sorting, but still need to add in the nodeDependencies list
+            // because these get removed as the event listeners fire and the dependencies
+            // are satisfied
+            int numNodes = mNodes.size();
+            for (int i = 0; i < numNodes; ++i) {
+                Node node = mNodes.get(i);
+                if (node.dependencies != null && node.dependencies.size() > 0) {
+                    int numDependencies = node.dependencies.size();
+                    for (int j = 0; j < numDependencies; ++j) {
+                        Dependency dependency = node.dependencies.get(j);
+                        if (node.nodeDependencies == null) {
+                            node.nodeDependencies = new ArrayList<Node>();
+                        }
+                        if (!node.nodeDependencies.contains(dependency.node)) {
+                            node.nodeDependencies.add(dependency.node);
+                        }
+                    }
+                }
+                // nodes are 'done' by default; they become un-done when started, and done
+                // again when ended
+                node.done = false;
+            }
+        }
+    }
+
+    /**
+     * Dependency holds information about the node that some other node is
+     * dependent upon and the nature of that dependency.
+     *
+     */
+    private static class Dependency {
+        static final int WITH = 0; // dependent node must start with this dependency node
+        static final int AFTER = 1; // dependent node must start when this dependency node finishes
+
+        // The node that the other node with this Dependency is dependent upon
+        public Node node;
+
+        // The nature of the dependency (WITH or AFTER)
+        public int rule;
+
+        public Dependency(Node node, int rule) {
+            this.node = node;
+            this.rule = rule;
+        }
+    }
+
+    /**
+     * A Node is an embodiment of both the Animator that it wraps as well as
+     * any dependencies that are associated with that Animation. This includes
+     * both dependencies upon other nodes (in the dependencies list) as
+     * well as dependencies of other nodes upon this (in the nodeDependents list).
+     */
+    private static class Node implements Cloneable {
+        public Animator animation;
+
+        /**
+         *  These are the dependencies that this node's animation has on other
+         *  nodes. For example, if this node's animation should begin with some
+         *  other animation ends, then there will be an item in this node's
+         *  dependencies list for that other animation's node.
+         */
+        public ArrayList<Dependency> dependencies = null;
+
+        /**
+         * tmpDependencies is a runtime detail. We use the dependencies list for sorting.
+         * But we also use the list to keep track of when multiple dependencies are satisfied,
+         * but removing each dependency as it is satisfied. We do not want to remove
+         * the dependency itself from the list, because we need to retain that information
+         * if the AnimatorSet is launched in the future. So we create a copy of the dependency
+         * list when the AnimatorSet starts and use this tmpDependencies list to track the
+         * list of satisfied dependencies.
+         */
+        public ArrayList<Dependency> tmpDependencies = null;
+
+        /**
+         * nodeDependencies is just a list of the nodes that this Node is dependent upon.
+         * This information is used in sortNodes(), to determine when a node is a root.
+         */
+        public ArrayList<Node> nodeDependencies = null;
+
+        /**
+         * nodeDepdendents is the list of nodes that have this node as a dependency. This
+         * is a utility field used in sortNodes to facilitate removing this node as a
+         * dependency when it is a root node.
+         */
+        public ArrayList<Node> nodeDependents = null;
+
+        /**
+         * Flag indicating whether the animation in this node is finished. This flag
+         * is used by AnimatorSet to check, as each animation ends, whether all child animations
+         * are done and it's time to send out an end event for the entire AnimatorSet.
+         */
+        public boolean done = false;
+
+        /**
+         * Constructs the Node with the animation that it encapsulates. A Node has no
+         * dependencies by default; dependencies are added via the addDependency()
+         * method.
+         *
+         * @param animation The animation that the Node encapsulates.
+         */
+        public Node(Animator animation) {
+            this.animation = animation;
+        }
+
+        /**
+         * Add a dependency to this Node. The dependency includes information about the
+         * node that this node is dependency upon and the nature of the dependency.
+         * @param dependency
+         */
+        public void addDependency(Dependency dependency) {
+            if (dependencies == null) {
+                dependencies = new ArrayList<Dependency>();
+                nodeDependencies = new ArrayList<Node>();
+            }
+            dependencies.add(dependency);
+            if (!nodeDependencies.contains(dependency.node)) {
+                nodeDependencies.add(dependency.node);
+            }
+            Node dependencyNode = dependency.node;
+            if (dependencyNode.nodeDependents == null) {
+                dependencyNode.nodeDependents = new ArrayList<Node>();
+            }
+            dependencyNode.nodeDependents.add(this);
+        }
+
+        @Override
+        public Node clone() {
+            try {
+                Node node = (Node) super.clone();
+                node.animation = animation.clone();
+                return node;
+            } catch (CloneNotSupportedException e) {
+               throw new AssertionError();
+            }
+        }
+    }
+
+    /**
+     * The <code>Builder</code> object is a utility class to facilitate adding animations to a
+     * <code>AnimatorSet</code> along with the relationships between the various animations. The
+     * intention of the <code>Builder</code> methods, along with the {@link
+     * AnimatorSet#play(Animator) play()} method of <code>AnimatorSet</code> is to make it possible
+     * to express the dependency relationships of animations in a natural way. Developers can also
+     * use the {@link AnimatorSet#playTogether(Animator[]) playTogether()} and {@link
+     * AnimatorSet#playSequentially(Animator[]) playSequentially()} methods if these suit the need,
+     * but it might be easier in some situations to express the AnimatorSet of animations in pairs.
+     * <p/>
+     * <p>The <code>Builder</code> object cannot be constructed directly, but is rather constructed
+     * internally via a call to {@link AnimatorSet#play(Animator)}.</p>
+     * <p/>
+     * <p>For example, this sets up a AnimatorSet to play anim1 and anim2 at the same time, anim3 to
+     * play when anim2 finishes, and anim4 to play when anim3 finishes:</p>
+     * <pre>
+     *     AnimatorSet s = new AnimatorSet();
+     *     s.play(anim1).with(anim2);
+     *     s.play(anim2).before(anim3);
+     *     s.play(anim4).after(anim3);
+     * </pre>
+     * <p/>
+     * <p>Note in the example that both {@link Builder#before(Animator)} and {@link
+     * Builder#after(Animator)} are used. These are just different ways of expressing the same
+     * relationship and are provided to make it easier to say things in a way that is more natural,
+     * depending on the situation.</p>
+     * <p/>
+     * <p>It is possible to make several calls into the same <code>Builder</code> object to express
+     * multiple relationships. However, note that it is only the animation passed into the initial
+     * {@link AnimatorSet#play(Animator)} method that is the dependency in any of the successive
+     * calls to the <code>Builder</code> object. For example, the following code starts both anim2
+     * and anim3 when anim1 ends; there is no direct dependency relationship between anim2 and
+     * anim3:
+     * <pre>
+     *   AnimatorSet s = new AnimatorSet();
+     *   s.play(anim1).before(anim2).before(anim3);
+     * </pre>
+     * If the desired result is to play anim1 then anim2 then anim3, this code expresses the
+     * relationship correctly:</p>
+     * <pre>
+     *   AnimatorSet s = new AnimatorSet();
+     *   s.play(anim1).before(anim2);
+     *   s.play(anim2).before(anim3);
+     * </pre>
+     * <p/>
+     * <p>Note that it is possible to express relationships that cannot be resolved and will not
+     * result in sensible results. For example, <code>play(anim1).after(anim1)</code> makes no
+     * sense. In general, circular dependencies like this one (or more indirect ones where a depends
+     * on b, which depends on c, which depends on a) should be avoided. Only create AnimatorSets
+     * that can boil down to a simple, one-way relationship of animations starting with, before, and
+     * after other, different, animations.</p>
+     */
+    public class Builder {
+
+        /**
+         * This tracks the current node being processed. It is supplied to the play() method
+         * of AnimatorSet and passed into the constructor of Builder.
+         */
+        private Node mCurrentNode;
+
+        /**
+         * package-private constructor. Builders are only constructed by AnimatorSet, when the
+         * play() method is called.
+         *
+         * @param anim The animation that is the dependency for the other animations passed into
+         * the other methods of this Builder object.
+         */
+        Builder(Animator anim) {
+            mCurrentNode = mNodeMap.get(anim);
+            if (mCurrentNode == null) {
+                mCurrentNode = new Node(anim);
+                mNodeMap.put(anim, mCurrentNode);
+                mNodes.add(mCurrentNode);
+            }
+        }
+
+        /**
+         * Sets up the given animation to play at the same time as the animation supplied in the
+         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object.
+         *
+         * @param anim The animation that will play when the animation supplied to the
+         * {@link AnimatorSet#play(Animator)} method starts.
+         */
+        public Builder with(Animator anim) {
+            Node node = mNodeMap.get(anim);
+            if (node == null) {
+                node = new Node(anim);
+                mNodeMap.put(anim, node);
+                mNodes.add(node);
+            }
+            Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH);
+            node.addDependency(dependency);
+            return this;
+        }
+
+        /**
+         * Sets up the given animation to play when the animation supplied in the
+         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
+         * ends.
+         *
+         * @param anim The animation that will play when the animation supplied to the
+         * {@link AnimatorSet#play(Animator)} method ends.
+         */
+        public Builder before(Animator anim) {
+            Node node = mNodeMap.get(anim);
+            if (node == null) {
+                node = new Node(anim);
+                mNodeMap.put(anim, node);
+                mNodes.add(node);
+            }
+            Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER);
+            node.addDependency(dependency);
+            return this;
+        }
+
+        /**
+         * Sets up the given animation to play when the animation supplied in the
+         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
+         * to start when the animation supplied in this method call ends.
+         *
+         * @param anim The animation whose end will cause the animation supplied to the
+         * {@link AnimatorSet#play(Animator)} method to play.
+         */
+        public Builder after(Animator anim) {
+            Node node = mNodeMap.get(anim);
+            if (node == null) {
+                node = new Node(anim);
+                mNodeMap.put(anim, node);
+                mNodes.add(node);
+            }
+            Dependency dependency = new Dependency(node, Dependency.AFTER);
+            mCurrentNode.addDependency(dependency);
+            return this;
+        }
+
+        /**
+         * Sets up the animation supplied in the
+         * {@link AnimatorSet#play(Animator)} call that created this <code>Builder</code> object
+         * to play when the given amount of time elapses.
+         *
+         * @param delay The number of milliseconds that should elapse before the
+         * animation starts.
+         */
+        public Builder after(long delay) {
+            // setup dummy ValueAnimator just to run the clock
+            ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+            anim.setDuration(delay);
+            after(anim);
+            return this;
+        }
+
+    }
+
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatEvaluator.java
new file mode 100644 (file)
index 0000000..e410193
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+/**
+ * This evaluator can be used to perform type interpolation between <code>float</code> values.
+ */
+public class FloatEvaluator implements TypeEvaluator<Number> {
+
+    /**
+     * This function returns the result of linearly interpolating the start and end values, with
+     * <code>fraction</code> representing the proportion between the start and end values. The
+     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
+     * and <code>t</code> is <code>fraction</code>.
+     *
+     * @param fraction   The fraction from the starting to the ending values
+     * @param startValue The start value; should be of type <code>float</code> or
+     *                   <code>Float</code>
+     * @param endValue   The end value; should be of type <code>float</code> or <code>Float</code>
+     * @return A linear interpolation between the start and end values, given the
+     *         <code>fraction</code> parameter.
+     */
+    public Float evaluate(float fraction, Number startValue, Number endValue) {
+        float startFloat = startValue.floatValue();
+        return startFloat + fraction * (endValue.floatValue() - startFloat);
+    }
+}
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/FloatKeyframeSet.java
new file mode 100644 (file)
index 0000000..6d9dafa
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+import java.util.ArrayList;
+import android.view.animation.Interpolator;
+
+import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.FloatKeyframe;
+
+/**
+ * This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate
+ * values between those keyframes for a given animation. The class internal to the animation
+ * package because it is an implementation detail of how Keyframes are stored and used.
+ *
+ * <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
+ * int, exists to speed up the getValue() method when there is no custom
+ * TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
+ * Object equivalents of these primitive types.</p>
+ */
+@SuppressWarnings("unchecked")
+class FloatKeyframeSet extends KeyframeSet {
+    private float firstValue;
+    private float lastValue;
+    private float deltaValue;
+    private boolean firstTime = true;
+
+    public FloatKeyframeSet(FloatKeyframe... keyframes) {
+        super(keyframes);
+    }
+
+    @Override
+    public Object getValue(float fraction) {
+        return getFloatValue(fraction);
+    }
+
+    @Override
+    public FloatKeyframeSet clone() {
+        ArrayList<Keyframe> keyframes = mKeyframes;
+        int numKeyframes = mKeyframes.size();
+        FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes];
+        for (int i = 0; i < numKeyframes; ++i) {
+            newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone();
+        }
+        FloatKeyframeSet newSet = new FloatKeyframeSet(newKeyframes);
+        return newSet;
+    }
+
+    public float getFloatValue(float fraction) {
+        if (mNumKeyframes == 2) {
+            if (firstTime) {
+                firstTime = false;
+                firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue();
+                lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue();
+                deltaValue = lastValue - firstValue;
+            }
+            if (mInterpolator != null) {
+                fraction = mInterpolator.getInterpolation(fraction);
+            }
+            if (mEvaluator == null) {
+                return firstValue + fraction * deltaValue;
+            } else {
+                return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue();
+            }
+        }
+        if (fraction <= 0f) {
+            final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
+            final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);
+            float prevValue = prevKeyframe.getFloatValue();
+            float nextValue = nextKeyframe.getFloatValue();
+            float prevFraction = prevKeyframe.getFraction();
+            float nextFraction = nextKeyframe.getFraction();
+            final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
+            if (interpolator != null) {
+                fraction = interpolator.getInterpolation(fraction);
+            }
+            float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
+            return mEvaluator == null ?
+                    prevValue + intervalFraction * (nextValue - prevValue) :
+                    ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
+                            floatValue();
+        } else if (fraction >= 1f) {
+            final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2);
+            final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1);
+            float prevValue = prevKeyframe.getFloatValue();
+            float nextValue = nextKeyframe.getFloatValue();
+            float prevFraction = prevKeyframe.getFraction();
+            float nextFraction = nextKeyframe.getFraction();
+            final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
+            if (interpolator != null) {
+                fraction = interpolator.getInterpolation(fraction);
+            }
+            float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
+            return mEvaluator == null ?
+                    prevValue + intervalFraction * (nextValue - prevValue) :
+                    ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
+                            floatValue();
+        }
+        FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
+        for (int i = 1; i < mNumKeyframes; ++i) {
+            FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
+            if (fraction < nextKeyframe.getFraction()) {
+                final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
+                if (interpolator != null) {
+                    fraction = interpolator.getInterpolation(fraction);
+                }
+                float intervalFraction = (fraction - prevKeyframe.getFraction()) /
+                    (nextKeyframe.getFraction() - prevKeyframe.getFraction());
+                float prevValue = prevKeyframe.getFloatValue();
+                float nextValue = nextKeyframe.getFloatValue();
+                return mEvaluator == null ?
+                        prevValue + intervalFraction * (nextValue - prevValue) :
+                        ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
+                            floatValue();
+            }
+            prevKeyframe = nextKeyframe;
+        }
+        // shouldn't get here
+        return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
+    }
+
+}
+
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntEvaluator.java
new file mode 100644 (file)
index 0000000..ed5e79e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+/**
+ * This evaluator can be used to perform type interpolation between <code>int</code> values.
+ */
+public class IntEvaluator implements TypeEvaluator<Integer> {
+
+    /**
+     * This function returns the result of linearly interpolating the start and end values, with
+     * <code>fraction</code> representing the proportion between the start and end values. The
+     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
+     * and <code>t</code> is <code>fraction</code>.
+     *
+     * @param fraction   The fraction from the starting to the ending values
+     * @param startValue The start value; should be of type <code>int</code> or
+     *                   <code>Integer</code>
+     * @param endValue   The end value; should be of type <code>int</code> or <code>Integer</code>
+     * @return A linear interpolation between the start and end values, given the
+     *         <code>fraction</code> parameter.
+     */
+    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
+        int startInt = startValue;
+        return (int)(startInt + fraction * (endValue - startInt));
+    }
+}
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/IntKeyframeSet.java
new file mode 100644 (file)
index 0000000..e9215e7
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+import java.util.ArrayList;
+import android.view.animation.Interpolator;
+
+import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.IntKeyframe;
+
+/**
+ * This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate
+ * values between those keyframes for a given animation. The class internal to the animation
+ * package because it is an implementation detail of how Keyframes are stored and used.
+ *
+ * <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
+ * float, exists to speed up the getValue() method when there is no custom
+ * TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
+ * Object equivalents of these primitive types.</p>
+ */
+@SuppressWarnings("unchecked")
+class IntKeyframeSet extends KeyframeSet {
+    private int firstValue;
+    private int lastValue;
+    private int deltaValue;
+    private boolean firstTime = true;
+
+    public IntKeyframeSet(IntKeyframe... keyframes) {
+        super(keyframes);
+    }
+
+    @Override
+    public Object getValue(float fraction) {
+        return getIntValue(fraction);
+    }
+
+    @Override
+    public IntKeyframeSet clone() {
+        ArrayList<Keyframe> keyframes = mKeyframes;
+        int numKeyframes = mKeyframes.size();
+        IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes];
+        for (int i = 0; i < numKeyframes; ++i) {
+            newKeyframes[i] = (IntKeyframe) keyframes.get(i).clone();
+        }
+        IntKeyframeSet newSet = new IntKeyframeSet(newKeyframes);
+        return newSet;
+    }
+
+    public int getIntValue(float fraction) {
+        if (mNumKeyframes == 2) {
+            if (firstTime) {
+                firstTime = false;
+                firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
+                lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
+                deltaValue = lastValue - firstValue;
+            }
+            if (mInterpolator != null) {
+                fraction = mInterpolator.getInterpolation(fraction);
+            }
+            if (mEvaluator == null) {
+                return firstValue + (int)(fraction * deltaValue);
+            } else {
+                return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
+            }
+        }
+        if (fraction <= 0f) {
+            final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
+            final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1);
+            int prevValue = prevKeyframe.getIntValue();
+            int nextValue = nextKeyframe.getIntValue();
+            float prevFraction = prevKeyframe.getFraction();
+            float nextFraction = nextKeyframe.getFraction();
+            final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
+            if (interpolator != null) {
+                fraction = interpolator.getInterpolation(fraction);
+            }
+            float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
+            return mEvaluator == null ?
+                    prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
+                    ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
+                            intValue();
+        } else if (fraction >= 1f) {
+            final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2);
+            final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1);
+            int prevValue = prevKeyframe.getIntValue();
+            int nextValue = nextKeyframe.getIntValue();
+            float prevFraction = prevKeyframe.getFraction();
+            float nextFraction = nextKeyframe.getFraction();
+            final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
+            if (interpolator != null) {
+                fraction = interpolator.getInterpolation(fraction);
+            }
+            float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
+            return mEvaluator == null ?
+                    prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
+                    ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();
+        }
+        IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
+        for (int i = 1; i < mNumKeyframes; ++i) {
+            IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i);
+            if (fraction < nextKeyframe.getFraction()) {
+                final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
+                if (interpolator != null) {
+                    fraction = interpolator.getInterpolation(fraction);
+                }
+                float intervalFraction = (fraction - prevKeyframe.getFraction()) /
+                    (nextKeyframe.getFraction() - prevKeyframe.getFraction());
+                int prevValue = prevKeyframe.getIntValue();
+                int nextValue = nextKeyframe.getIntValue();
+                return mEvaluator == null ?
+                        prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
+                        ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
+                                intValue();
+            }
+            prevKeyframe = nextKeyframe;
+        }
+        // shouldn't get here
+        return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue();
+    }
+
+}
+
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/Keyframe.java
new file mode 100644 (file)
index 0000000..ab76fa7
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+import android.view.animation.Interpolator;
+
+/**
+ * This class holds a time/value pair for an animation. The Keyframe class is used
+ * by {@link ValueAnimator} to define the values that the animation target will have over the course
+ * of the animation. As the time proceeds from one keyframe to the other, the value of the
+ * target object will animate between the value at the previous keyframe and the value at the
+ * next keyframe. Each keyframe also holds an optional {@link TimeInterpolator}
+ * object, which defines the time interpolation over the intervalue preceding the keyframe.
+ *
+ * <p>The Keyframe class itself is abstract. The type-specific factory methods will return
+ * a subclass of Keyframe specific to the type of value being stored. This is done to improve
+ * performance when dealing with the most common cases (e.g., <code>float</code> and
+ * <code>int</code> values). Other types will fall into a more general Keyframe class that
+ * treats its values as Objects. Unless your animation requires dealing with a custom type
+ * or a data structure that needs to be animated directly (and evaluated using an implementation
+ * of {@link TypeEvaluator}), you should stick to using float and int as animations using those
+ * types have lower runtime overhead than other types.</p>
+ */
+@SuppressWarnings("rawtypes")
+public abstract class Keyframe implements Cloneable {
+    /**
+     * The time at which mValue will hold true.
+     */
+    float mFraction;
+
+    /**
+     * The type of the value in this Keyframe. This type is determined at construction time,
+     * based on the type of the <code>value</code> object passed into the constructor.
+     */
+    Class mValueType;
+
+    /**
+     * The optional time interpolator for the interval preceding this keyframe. A null interpolator
+     * (the default) results in linear interpolation over the interval.
+     */
+    private /*Time*/Interpolator mInterpolator = null;
+
+    /**
+     * Flag to indicate whether this keyframe has a valid value. This flag is used when an
+     * animation first starts, to populate placeholder keyframes with real values derived
+     * from the target object.
+     */
+    boolean mHasValue = false;
+
+    /**
+     * Constructs a Keyframe object with the given time and value. The time defines the
+     * time, as a proportion of an overall animation's duration, at which the value will hold true
+     * for the animation. The value for the animation between keyframes will be calculated as
+     * an interpolation between the values at those keyframes.
+     *
+     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+     * of time elapsed of the overall animation duration.
+     * @param value The value that the object will animate to as the animation time approaches
+     * the time in this keyframe, and the the value animated from as the time passes the time in
+     * this keyframe.
+     */
+    public static Keyframe ofInt(float fraction, int value) {
+        return new IntKeyframe(fraction, value);
+    }
+
+    /**
+     * Constructs a Keyframe object with the given time. The value at this time will be derived
+     * from the target object when the animation first starts (note that this implies that keyframes
+     * with no initial value must be used as part of an {@link ObjectAnimator}).
+     * The time defines the
+     * time, as a proportion of an overall animation's duration, at which the value will hold true
+     * for the animation. The value for the animation between keyframes will be calculated as
+     * an interpolation between the values at those keyframes.
+     *
+     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+     * of time elapsed of the overall animation duration.
+     */
+    public static Keyframe ofInt(float fraction) {
+        return new IntKeyframe(fraction);
+    }
+
+    /**
+     * Constructs a Keyframe object with the given time and value. The time defines the
+     * time, as a proportion of an overall animation's duration, at which the value will hold true
+     * for the animation. The value for the animation between keyframes will be calculated as
+     * an interpolation between the values at those keyframes.
+     *
+     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+     * of time elapsed of the overall animation duration.
+     * @param value The value that the object will animate to as the animation time approaches
+     * the time in this keyframe, and the the value animated from as the time passes the time in
+     * this keyframe.
+     */
+    public static Keyframe ofFloat(float fraction, float value) {
+        return new FloatKeyframe(fraction, value);
+    }
+
+    /**
+     * Constructs a Keyframe object with the given time. The value at this time will be derived
+     * from the target object when the animation first starts (note that this implies that keyframes
+     * with no initial value must be used as part of an {@link ObjectAnimator}).
+     * The time defines the
+     * time, as a proportion of an overall animation's duration, at which the value will hold true
+     * for the animation. The value for the animation between keyframes will be calculated as
+     * an interpolation between the values at those keyframes.
+     *
+     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+     * of time elapsed of the overall animation duration.
+     */
+    public static Keyframe ofFloat(float fraction) {
+        return new FloatKeyframe(fraction);
+    }
+
+    /**
+     * Constructs a Keyframe object with the given time and value. The time defines the
+     * time, as a proportion of an overall animation's duration, at which the value will hold true
+     * for the animation. The value for the animation between keyframes will be calculated as
+     * an interpolation between the values at those keyframes.
+     *
+     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+     * of time elapsed of the overall animation duration.
+     * @param value The value that the object will animate to as the animation time approaches
+     * the time in this keyframe, and the the value animated from as the time passes the time in
+     * this keyframe.
+     */
+    public static Keyframe ofObject(float fraction, Object value) {
+        return new ObjectKeyframe(fraction, value);
+    }
+
+    /**
+     * Constructs a Keyframe object with the given time. The value at this time will be derived
+     * from the target object when the animation first starts (note that this implies that keyframes
+     * with no initial value must be used as part of an {@link ObjectAnimator}).
+     * The time defines the
+     * time, as a proportion of an overall animation's duration, at which the value will hold true
+     * for the animation. The value for the animation between keyframes will be calculated as
+     * an interpolation between the values at those keyframes.
+     *
+     * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+     * of time elapsed of the overall animation duration.
+     */
+    public static Keyframe ofObject(float fraction) {
+        return new ObjectKeyframe(fraction, null);
+    }
+
+    /**
+     * Indicates whether this keyframe has a valid value. This method is called internally when
+     * an {@link ObjectAnimator} first starts; keyframes without values are assigned values at
+     * that time by deriving the value for the property from the target object.
+     *
+     * @return boolean Whether this object has a value assigned.
+     */
+    public boolean hasValue() {
+        return mHasValue;
+    }
+
+    /**
+     * Gets the value for this Keyframe.
+     *
+     * @return The value for this Keyframe.
+     */
+    public abstract Object getValue();
+
+    /**
+     * Sets the value for this Keyframe.
+     *
+     * @param value value for this Keyframe.
+     */
+    public abstract void setValue(Object value);
+
+    /**
+     * Gets the time for this keyframe, as a fraction of the overall animation duration.
+     *
+     * @return The time associated with this keyframe, as a fraction of the overall animation
+     * duration. This should be a value between 0 and 1.
+     */
+    public float getFraction() {
+        return mFraction;
+    }
+
+    /**
+     * Sets the time for this keyframe, as a fraction of the overall animation duration.
+     *
+     * @param fraction time associated with this keyframe, as a fraction of the overall animation
+     * duration. This should be a value between 0 and 1.
+     */
+    public void setFraction(float fraction) {
+        mFraction = fraction;
+    }
+
+    /**
+     * Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
+     * that there is no interpolation, which is the same as linear interpolation.
+     *
+     * @return The optional interpolator for this Keyframe.
+     */
+    public /*Time*/Interpolator getInterpolator() {
+        return mInterpolator;
+    }
+
+    /**
+     * Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
+     * that there is no interpolation, which is the same as linear interpolation.
+     *
+     * @return The optional interpolator for this Keyframe.
+     */
+    public void setInterpolator(/*Time*/Interpolator interpolator) {
+        mInterpolator = interpolator;
+    }
+
+    /**
+     * Gets the type of keyframe. This information is used by ValueAnimator to determine the type of
+     * {@link TypeEvaluator} to use when calculating values between keyframes. The type is based
+     * on the type of Keyframe created.
+     *
+     * @return The type of the value stored in the Keyframe.
+     */
+    public Class getType() {
+        return mValueType;
+    }
+
+    @Override
+    public abstract Keyframe clone();
+
+    /**
+     * This internal subclass is used for all types which are not int or float.
+     */
+    static class ObjectKeyframe extends Keyframe {
+
+        /**
+         * The value of the animation at the time mFraction.
+         */
+        Object mValue;
+
+        ObjectKeyframe(float fraction, Object value) {
+            mFraction = fraction;
+            mValue = value;
+            mHasValue = (value != null);
+            mValueType = mHasValue ? value.getClass() : Object.class;
+        }
+
+        public Object getValue() {
+            return mValue;
+        }
+
+        public void setValue(Object value) {
+            mValue = value;
+            mHasValue = (value != null);
+        }
+
+        @Override
+        public ObjectKeyframe clone() {
+            ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mValue);
+            kfClone.setInterpolator(getInterpolator());
+            return kfClone;
+        }
+    }
+
+    /**
+     * Internal subclass used when the keyframe value is of type int.
+     */
+    static class IntKeyframe extends Keyframe {
+
+        /**
+         * The value of the animation at the time mFraction.
+         */
+        int mValue;
+
+        IntKeyframe(float fraction, int value) {
+            mFraction = fraction;
+            mValue = value;
+            mValueType = int.class;
+            mHasValue = true;
+        }
+
+        IntKeyframe(float fraction) {
+            mFraction = fraction;
+            mValueType = int.class;
+        }
+
+        public int getIntValue() {
+            return mValue;
+        }
+
+        public Object getValue() {
+            return mValue;
+        }
+
+        public void setValue(Object value) {
+            if (value != null && value.getClass() == Integer.class) {
+                mValue = ((Integer)value).intValue();
+                mHasValue = true;
+            }
+        }
+
+        @Override
+        public IntKeyframe clone() {
+            IntKeyframe kfClone = new IntKeyframe(getFraction(), mValue);
+            kfClone.setInterpolator(getInterpolator());
+            return kfClone;
+        }
+    }
+
+    /**
+     * Internal subclass used when the keyframe value is of type float.
+     */
+    static class FloatKeyframe extends Keyframe {
+        /**
+         * The value of the animation at the time mFraction.
+         */
+        float mValue;
+
+        FloatKeyframe(float fraction, float value) {
+            mFraction = fraction;
+            mValue = value;
+            mValueType = float.class;
+            mHasValue = true;
+        }
+
+        FloatKeyframe(float fraction) {
+            mFraction = fraction;
+            mValueType = float.class;
+        }
+
+        public float getFloatValue() {
+            return mValue;
+        }
+
+        public Object getValue() {
+            return mValue;
+        }
+
+        public void setValue(Object value) {
+            if (value != null && value.getClass() == Float.class) {
+                mValue = ((Float)value).floatValue();
+                mHasValue = true;
+            }
+        }
+
+        @Override
+        public FloatKeyframe clone() {
+            FloatKeyframe kfClone = new FloatKeyframe(getFraction(), mValue);
+            kfClone.setInterpolator(getInterpolator());
+            return kfClone;
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/KeyframeSet.java
new file mode 100644 (file)
index 0000000..a71e1ad
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import android.view.animation.Interpolator;
+
+import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.FloatKeyframe;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.IntKeyframe;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.ObjectKeyframe;
+
+/**
+ * This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
+ * values between those keyframes for a given animation. The class internal to the animation
+ * package because it is an implementation detail of how Keyframes are stored and used.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+class KeyframeSet {
+
+    int mNumKeyframes;
+
+    Keyframe mFirstKeyframe;
+    Keyframe mLastKeyframe;
+    /*Time*/Interpolator mInterpolator; // only used in the 2-keyframe case
+    ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
+    TypeEvaluator mEvaluator;
+
+
+    public KeyframeSet(Keyframe... keyframes) {
+        mNumKeyframes = keyframes.length;
+        mKeyframes = new ArrayList<Keyframe>();
+        mKeyframes.addAll(Arrays.asList(keyframes));
+        mFirstKeyframe = mKeyframes.get(0);
+        mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
+        mInterpolator = mLastKeyframe.getInterpolator();
+    }
+
+    public static KeyframeSet ofInt(int... values) {
+        int numKeyframes = values.length;
+        IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
+        if (numKeyframes == 1) {
+            keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
+            keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
+        } else {
+            keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
+            for (int i = 1; i < numKeyframes; ++i) {
+                keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
+            }
+        }
+        return new IntKeyframeSet(keyframes);
+    }
+
+    public static KeyframeSet ofFloat(float... values) {
+        int numKeyframes = values.length;
+        FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
+        if (numKeyframes == 1) {
+            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
+            keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
+        } else {
+            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
+            for (int i = 1; i < numKeyframes; ++i) {
+                keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
+            }
+        }
+        return new FloatKeyframeSet(keyframes);
+    }
+
+    public static KeyframeSet ofKeyframe(Keyframe... keyframes) {
+        // if all keyframes of same primitive type, create the appropriate KeyframeSet
+        int numKeyframes = keyframes.length;
+        boolean hasFloat = false;
+        boolean hasInt = false;
+        boolean hasOther = false;
+        for (int i = 0; i < numKeyframes; ++i) {
+            if (keyframes[i] instanceof FloatKeyframe) {
+                hasFloat = true;
+            } else if (keyframes[i] instanceof IntKeyframe) {
+                hasInt = true;
+            } else {
+                hasOther = true;
+            }
+        }
+        if (hasFloat && !hasInt && !hasOther) {
+            FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes];
+            for (int i = 0; i < numKeyframes; ++i) {
+                floatKeyframes[i] = (FloatKeyframe) keyframes[i];
+            }
+            return new FloatKeyframeSet(floatKeyframes);
+        } else if (hasInt && !hasFloat && !hasOther) {
+            IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes];
+            for (int i = 0; i < numKeyframes; ++i) {
+                intKeyframes[i] = (IntKeyframe) keyframes[i];
+            }
+            return new IntKeyframeSet(intKeyframes);
+        } else {
+            return new KeyframeSet(keyframes);
+        }
+    }
+
+    public static KeyframeSet ofObject(Object... values) {
+        int numKeyframes = values.length;
+        ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];
+        if (numKeyframes == 1) {
+            keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f);
+            keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]);
+        } else {
+            keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]);
+            for (int i = 1; i < numKeyframes; ++i) {
+                keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]);
+            }
+        }
+        return new KeyframeSet(keyframes);
+    }
+
+    /**
+     * Sets the TypeEvaluator to be used when calculating animated values. This object
+     * is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
+     * both of which assume their own evaluator to speed up calculations with those primitive
+     * types.
+     *
+     * @param evaluator The TypeEvaluator to be used to calculate animated values.
+     */
+    public void setEvaluator(TypeEvaluator evaluator) {
+        mEvaluator = evaluator;
+    }
+
+    @Override
+    public KeyframeSet clone() {
+        ArrayList<Keyframe> keyframes = mKeyframes;
+        int numKeyframes = mKeyframes.size();
+        Keyframe[] newKeyframes = new Keyframe[numKeyframes];
+        for (int i = 0; i < numKeyframes; ++i) {
+            newKeyframes[i] = keyframes.get(i).clone();
+        }
+        KeyframeSet newSet = new KeyframeSet(newKeyframes);
+        return newSet;
+    }
+
+    /**
+     * Gets the animated value, given the elapsed fraction of the animation (interpolated by the
+     * animation's interpolator) and the evaluator used to calculate in-between values. This
+     * function maps the input fraction to the appropriate keyframe interval and a fraction
+     * between them and returns the interpolated value. Note that the input fraction may fall
+     * outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
+     * spring interpolation that might send the fraction past 1.0). We handle this situation by
+     * just using the two keyframes at the appropriate end when the value is outside those bounds.
+     *
+     * @param fraction The elapsed fraction of the animation
+     * @return The animated value.
+     */
+    public Object getValue(float fraction) {
+
+        // Special-case optimization for the common case of only two keyframes
+        if (mNumKeyframes == 2) {
+            if (mInterpolator != null) {
+                fraction = mInterpolator.getInterpolation(fraction);
+            }
+            return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
+                    mLastKeyframe.getValue());
+        }
+        if (fraction <= 0f) {
+            final Keyframe nextKeyframe = mKeyframes.get(1);
+            final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
+            if (interpolator != null) {
+                fraction = interpolator.getInterpolation(fraction);
+            }
+            final float prevFraction = mFirstKeyframe.getFraction();
+            float intervalFraction = (fraction - prevFraction) /
+                (nextKeyframe.getFraction() - prevFraction);
+            return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
+                    nextKeyframe.getValue());
+        } else if (fraction >= 1f) {
+            final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
+            final /*Time*/Interpolator interpolator = mLastKeyframe.getInterpolator();
+            if (interpolator != null) {
+                fraction = interpolator.getInterpolation(fraction);
+            }
+            final float prevFraction = prevKeyframe.getFraction();
+            float intervalFraction = (fraction - prevFraction) /
+                (mLastKeyframe.getFraction() - prevFraction);
+            return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
+                    mLastKeyframe.getValue());
+        }
+        Keyframe prevKeyframe = mFirstKeyframe;
+        for (int i = 1; i < mNumKeyframes; ++i) {
+            Keyframe nextKeyframe = mKeyframes.get(i);
+            if (fraction < nextKeyframe.getFraction()) {
+                final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
+                if (interpolator != null) {
+                    fraction = interpolator.getInterpolation(fraction);
+                }
+                final float prevFraction = prevKeyframe.getFraction();
+                float intervalFraction = (fraction - prevFraction) /
+                    (nextKeyframe.getFraction() - prevFraction);
+                return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
+                        nextKeyframe.getValue());
+            }
+            prevKeyframe = nextKeyframe;
+        }
+        // shouldn't reach here
+        return mLastKeyframe.getValue();
+    }
+
+    @Override
+    public String toString() {
+        String returnVal = " ";
+        for (int i = 0; i < mNumKeyframes; ++i) {
+            returnVal += mKeyframes.get(i).getValue() + "  ";
+        }
+        return returnVal;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ObjectAnimator.java
new file mode 100644 (file)
index 0000000..21d15c0
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+import android.util.Log;
+//import android.util.Property;
+
+//import java.lang.reflect.Method;
+import java.util.ArrayList;
+
+/**
+ * This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
+ * The constructors of this class take parameters to define the target object that will be animated
+ * as well as the name of the property that will be animated. Appropriate set/get functions
+ * are then determined internally and the animation will call these functions as necessary to
+ * animate the property.
+ *
+ * @see #setPropertyName(String)
+ *
+ */
+@SuppressWarnings("rawtypes")
+public final class ObjectAnimator extends ValueAnimator {
+    private static final boolean DBG = false;
+
+    // The target object on which the property exists, set in the constructor
+    private Object mTarget;
+
+    private String mPropertyName;
+
+    //private Property mProperty;
+
+    /**
+     * Sets the name of the property that will be animated. This name is used to derive
+     * a setter function that will be called to set animated values.
+     * For example, a property name of <code>foo</code> will result
+     * in a call to the function <code>setFoo()</code> on the target object. If either
+     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
+     * also be derived and called.
+     *
+     * <p>For best performance of the mechanism that calls the setter function determined by the
+     * name of the property being animated, use <code>float</code> or <code>int</code> typed values,
+     * and make the setter function for those properties have a <code>void</code> return value. This
+     * will cause the code to take an optimized path for these constrained circumstances. Other
+     * property types and return types will work, but will have more overhead in processing
+     * the requests due to normal reflection mechanisms.</p>
+     *
+     * <p>Note that the setter function derived from this property name
+     * must take the same parameter type as the
+     * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
+     * the setter function will fail.</p>
+     *
+     * <p>If this ObjectAnimator has been set up to animate several properties together,
+     * using more than one PropertyValuesHolder objects, then setting the propertyName simply
+     * sets the propertyName in the first of those PropertyValuesHolder objects.</p>
+     *
+     * @param propertyName The name of the property being animated. Should not be null.
+     */
+    public void setPropertyName(String propertyName) {
+        // mValues could be null if this is being constructed piecemeal. Just record the
+        // propertyName to be used later when setValues() is called if so.
+        if (mValues != null) {
+            PropertyValuesHolder valuesHolder = mValues[0];
+            String oldName = valuesHolder.getPropertyName();
+            valuesHolder.setPropertyName(propertyName);
+            mValuesMap.remove(oldName);
+            mValuesMap.put(propertyName, valuesHolder);
+        }
+        mPropertyName = propertyName;
+        // New property/values/target should cause re-initialization prior to starting
+        mInitialized = false;
+    }
+
+    /**
+     * Sets the property that will be animated. Property objects will take precedence over
+     * properties specified by the {@link #setPropertyName(String)} method. Animations should
+     * be set up to use one or the other, not both.
+     *
+     * @param property The property being animated. Should not be null.
+     */
+    //public void setProperty(Property property) {
+    //    // mValues could be null if this is being constructed piecemeal. Just record the
+    //    // propertyName to be used later when setValues() is called if so.
+    //    if (mValues != null) {
+    //        PropertyValuesHolder valuesHolder = mValues[0];
+    //        String oldName = valuesHolder.getPropertyName();
+    //        valuesHolder.setProperty(property);
+    //        mValuesMap.remove(oldName);
+    //        mValuesMap.put(mPropertyName, valuesHolder);
+    //    }
+    //    if (mProperty != null) {
+    //        mPropertyName = property.getName();
+    //    }
+    //    mProperty = property;
+    //    // New property/values/target should cause re-initialization prior to starting
+    //    mInitialized = false;
+    //}
+
+    /**
+     * Gets the name of the property that will be animated. This name will be used to derive
+     * a setter function that will be called to set animated values.
+     * For example, a property name of <code>foo</code> will result
+     * in a call to the function <code>setFoo()</code> on the target object. If either
+     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
+     * also be derived and called.
+     */
+    public String getPropertyName() {
+        return mPropertyName;
+    }
+
+    /**
+     * Creates a new ObjectAnimator object. This default constructor is primarily for
+     * use internally; the other constructors which take parameters are more generally
+     * useful.
+     */
+    public ObjectAnimator() {
+    }
+
+    /**
+     * Private utility constructor that initializes the target object and name of the
+     * property being animated.
+     *
+     * @param target The object whose property is to be animated. This object should
+     * have a public method on it called <code>setName()</code>, where <code>name</code> is
+     * the value of the <code>propertyName</code> parameter.
+     * @param propertyName The name of the property being animated.
+     */
+    private ObjectAnimator(Object target, String propertyName) {
+        mTarget = target;
+        setPropertyName(propertyName);
+    }
+
+    /**
+     * Private utility constructor that initializes the target object and property being animated.
+     *
+     * @param target The object whose property is to be animated.
+     * @param property The property being animated.
+     */
+    //private <T> ObjectAnimator(T target, Property<T, ?> property) {
+    //    mTarget = target;
+    //    setProperty(property);
+    //}
+
+    /**
+     * Constructs and returns an ObjectAnimator that animates between int values. A single
+     * value implies that that value is the one being animated to. Two values imply a starting
+     * and ending values. More than two values imply a starting value, values to animate through
+     * along the way, and an ending value (these values will be distributed evenly across
+     * the duration of the animation).
+     *
+     * @param target The object whose property is to be animated. This object should
+     * have a public method on it called <code>setName()</code>, where <code>name</code> is
+     * the value of the <code>propertyName</code> parameter.
+     * @param propertyName The name of the property being animated.
+     * @param values A set of values that the animation will animate between over time.
+     * @return An ObjectAnimator object that is set up to animate between the given values.
+     */
+    public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
+        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
+        anim.setIntValues(values);
+        return anim;
+    }
+
+    /**
+     * Constructs and returns an ObjectAnimator that animates between int values. A single
+     * value implies that that value is the one being animated to. Two values imply a starting
+     * and ending values. More than two values imply a starting value, values to animate through
+     * along the way, and an ending value (these values will be distributed evenly across
+     * the duration of the animation).
+     *
+     * @param target The object whose property is to be animated.
+     * @param property The property being animated.
+     * @param values A set of values that the animation will animate between over time.
+     * @return An ObjectAnimator object that is set up to animate between the given values.
+     */
+    //public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
+    //    ObjectAnimator anim = new ObjectAnimator(target, property);
+    //    anim.setIntValues(values);
+    //    return anim;
+    //}
+
+    /**
+     * Constructs and returns an ObjectAnimator that animates between float values. A single
+     * value implies that that value is the one being animated to. Two values imply a starting
+     * and ending values. More than two values imply a starting value, values to animate through
+     * along the way, and an ending value (these values will be distributed evenly across
+     * the duration of the animation).
+     *
+     * @param target The object whose property is to be animated. This object should
+     * have a public method on it called <code>setName()</code>, where <code>name</code> is
+     * the value of the <code>propertyName</code> parameter.
+     * @param propertyName The name of the property being animated.
+     * @param values A set of values that the animation will animate between over time.
+     * @return An ObjectAnimator object that is set up to animate between the given values.
+     */
+    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
+        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
+        anim.setFloatValues(values);
+        return anim;
+    }
+
+    /**
+     * Constructs and returns an ObjectAnimator that animates between float values. A single
+     * value implies that that value is the one being animated to. Two values imply a starting
+     * and ending values. More than two values imply a starting value, values to animate through
+     * along the way, and an ending value (these values will be distributed evenly across
+     * the duration of the animation).
+     *
+     * @param target The object whose property is to be animated.
+     * @param property The property being animated.
+     * @param values A set of values that the animation will animate between over time.
+     * @return An ObjectAnimator object that is set up to animate between the given values.
+     */
+    //public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
+    //        float... values) {
+    //    ObjectAnimator anim = new ObjectAnimator(target, property);
+    //    anim.setFloatValues(values);
+    //    return anim;
+    //}
+
+    /**
+     * Constructs and returns an ObjectAnimator that animates between Object values. A single
+     * value implies that that value is the one being animated to. Two values imply a starting
+     * and ending values. More than two values imply a starting value, values to animate through
+     * along the way, and an ending value (these values will be distributed evenly across
+     * the duration of the animation).
+     *
+     * @param target The object whose property is to be animated. This object should
+     * have a public method on it called <code>setName()</code>, where <code>name</code> is
+     * the value of the <code>propertyName</code> parameter.
+     * @param propertyName The name of the property being animated.
+     * @param evaluator A TypeEvaluator that will be called on each animation frame to
+     * provide the necessary interpolation between the Object values to derive the animated
+     * value.
+     * @param values A set of values that the animation will animate between over time.
+     * @return An ObjectAnimator object that is set up to animate between the given values.
+     */
+    public static ObjectAnimator ofObject(Object target, String propertyName,
+            TypeEvaluator evaluator, Object... values) {
+        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
+        anim.setObjectValues(values);
+        anim.setEvaluator(evaluator);
+        return anim;
+    }
+
+    /**
+     * Constructs and returns an ObjectAnimator that animates between Object values. A single
+     * value implies that that value is the one being animated to. Two values imply a starting
+     * and ending values. More than two values imply a starting value, values to animate through
+     * along the way, and an ending value (these values will be distributed evenly across
+     * the duration of the animation).
+     *
+     * @param target The object whose property is to be animated.
+     * @param property The property being animated.
+     * @param evaluator A TypeEvaluator that will be called on each animation frame to
+     * provide the necessary interpolation between the Object values to derive the animated
+     * value.
+     * @param values A set of values that the animation will animate between over time.
+     * @return An ObjectAnimator object that is set up to animate between the given values.
+     */
+    //public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
+    //        TypeEvaluator<V> evaluator, V... values) {
+    //    ObjectAnimator anim = new ObjectAnimator(target, property);
+    //    anim.setObjectValues(values);
+    //    anim.setEvaluator(evaluator);
+    //    return anim;
+    //}
+
+    /**
+     * Constructs and returns an ObjectAnimator that animates between the sets of values specified
+     * in <code>PropertyValueHolder</code> objects. This variant should be used when animating
+     * several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows
+     * you to associate a set of animation values with a property name.
+     *
+     * @param target The object whose property is to be animated. Depending on how the
+     * PropertyValuesObjects were constructed, the target object should either have the {@link
+     * android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the
+     * PropertyValuesHOlder objects were created with property names) the target object should have
+     * public methods on it called <code>setName()</code>, where <code>name</code> is the name of
+     * the property passed in as the <code>propertyName</code> parameter for each of the
+     * PropertyValuesHolder objects.
+     * @param values A set of PropertyValuesHolder objects whose values will be animated between
+     * over time.
+     * @return An ObjectAnimator object that is set up to animate between the given values.
+     */
+    public static ObjectAnimator ofPropertyValuesHolder(Object target,
+            PropertyValuesHolder... values) {
+        ObjectAnimator anim = new ObjectAnimator();
+        anim.mTarget = target;
+        anim.setValues(values);
+        return anim;
+    }
+
+    @Override
+    public void setIntValues(int... values) {
+        if (mValues == null || mValues.length == 0) {
+            // No values yet - this animator is being constructed piecemeal. Init the values with
+            // whatever the current propertyName is
+            //if (mProperty != null) {
+            //    setValues(PropertyValuesHolder.ofInt(mProperty, values));
+            //} else {
+                setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
+            //}
+        } else {
+            super.setIntValues(values);
+        }
+    }
+
+    @Override
+    public void setFloatValues(float... values) {
+        if (mValues == null || mValues.length == 0) {
+            // No values yet - this animator is being constructed piecemeal. Init the values with
+            // whatever the current propertyName is
+            //if (mProperty != null) {
+            //    setValues(PropertyValuesHolder.ofFloat(mProperty, values));
+            //} else {
+                setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
+            //}
+        } else {
+            super.setFloatValues(values);
+        }
+    }
+
+    @Override
+    public void setObjectValues(Object... values) {
+        if (mValues == null || mValues.length == 0) {
+            // No values yet - this animator is being constructed piecemeal. Init the values with
+            // whatever the current propertyName is
+            //if (mProperty != null) {
+            //    setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator)null, values));
+            //} else {
+                setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator)null, values));
+            //}
+        } else {
+            super.setObjectValues(values);
+        }
+    }
+
+    @Override
+    public void start() {
+        if (DBG) {
+            Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
+            for (int i = 0; i < mValues.length; ++i) {
+                PropertyValuesHolder pvh = mValues[i];
+                ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
+                Log.d("ObjectAnimator", "   Values[" + i + "]: " +
+                    pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " +
+                    keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue());
+            }
+        }
+        super.start();
+    }
+
+    /**
+     * This function is called immediately before processing the first animation
+     * frame of an animation. If there is a nonzero <code>startDelay</code>, the
+     * function is called after that delay ends.
+     * It takes care of the final initialization steps for the
+     * animation. This includes setting mEvaluator, if the user has not yet
+     * set it up, and the setter/getter methods, if the user did not supply
+     * them.
+     *
+     *  <p>Overriders of this method should call the superclass method to cause
+     *  internal mechanisms to be set up correctly.</p>
+     */
+    @Override
+    void initAnimation() {
+        if (!mInitialized) {
+            // mValueType may change due to setter/getter setup; do this before calling super.init(),
+            // which uses mValueType to set up the default type evaluator.
+            int numValues = mValues.length;
+            for (int i = 0; i < numValues; ++i) {
+                mValues[i].setupSetterAndGetter(mTarget);
+            }
+            super.initAnimation();
+        }
+    }
+
+    /**
+     * Sets the length of the animation. The default duration is 300 milliseconds.
+     *
+     * @param duration The length of the animation, in milliseconds.
+     * @return ObjectAnimator The object called with setDuration(). This return
+     * value makes it easier to compose statements together that construct and then set the
+     * duration, as in
+     * <code>ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start()</code>.
+     */
+    @Override
+    public ObjectAnimator setDuration(long duration) {
+        super.setDuration(duration);
+        return this;
+    }
+
+
+    /**
+     * The target object whose property will be animated by this animation
+     *
+     * @return The object being animated
+     */
+    public Object getTarget() {
+        return mTarget;
+    }
+
+    /**
+     * Sets the target object whose property will be animated by this animation
+     *
+     * @param target The object being animated
+     */
+    @Override
+    public void setTarget(Object target) {
+        if (mTarget != target) {
+            final Object oldTarget = mTarget;
+            mTarget = target;
+            if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
+                return;
+            }
+            // New target type should cause re-initialization prior to starting
+            mInitialized = false;
+        }
+    }
+
+    @Override
+    public void setupStartValues() {
+        initAnimation();
+        int numValues = mValues.length;
+        for (int i = 0; i < numValues; ++i) {
+            mValues[i].setupStartValue(mTarget);
+        }
+    }
+
+    @Override
+    public void setupEndValues() {
+        initAnimation();
+        int numValues = mValues.length;
+        for (int i = 0; i < numValues; ++i) {
+            mValues[i].setupEndValue(mTarget);
+        }
+    }
+
+    /**
+     * This method is called with the elapsed fraction of the animation during every
+     * animation frame. This function turns the elapsed fraction into an interpolated fraction
+     * and then into an animated value (from the evaluator. The function is called mostly during
+     * animation updates, but it is also called when the <code>end()</code>
+     * function is called, to set the final value on the property.
+     *
+     * <p>Overrides of this method must call the superclass to perform the calculation
+     * of the animated value.</p>
+     *
+     * @param fraction The elapsed fraction of the animation.
+     */
+    @Override
+    void animateValue(float fraction) {
+        super.animateValue(fraction);
+        int numValues = mValues.length;
+        for (int i = 0; i < numValues; ++i) {
+            mValues[i].setAnimatedValue(mTarget);
+        }
+    }
+
+    @Override
+    public ObjectAnimator clone() {
+        final ObjectAnimator anim = (ObjectAnimator) super.clone();
+        return anim;
+    }
+
+    @Override
+    public String toString() {
+        String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " +
+            mTarget;
+        if (mValues != null) {
+            for (int i = 0; i < mValues.length; ++i) {
+                returnVal += "\n    " + mValues[i].toString();
+            }
+        }
+        return returnVal;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/PropertyValuesHolder.java
new file mode 100644 (file)
index 0000000..84f7504
--- /dev/null
@@ -0,0 +1,1012 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+//import android.util.FloatProperty;
+//import android.util.IntProperty;
+import android.util.Log;
+//import android.util.Property;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * This class holds information about a property and the values that that property
+ * should take on during an animation. PropertyValuesHolder objects can be used to create
+ * animations with ValueAnimator or ObjectAnimator that operate on several different properties
+ * in parallel.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class PropertyValuesHolder implements Cloneable {
+
+    /**
+     * The name of the property associated with the values. This need not be a real property,
+     * unless this object is being used with ObjectAnimator. But this is the name by which
+     * aniamted values are looked up with getAnimatedValue(String) in ValueAnimator.
+     */
+    String mPropertyName;
+
+    /**
+     * @hide
+     */
+    //protected Property mProperty;
+
+    /**
+     * The setter function, if needed. ObjectAnimator hands off this functionality to
+     * PropertyValuesHolder, since it holds all of the per-property information. This
+     * property is automatically
+     * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator.
+     */
+    Method mSetter = null;
+
+    /**
+     * The getter function, if needed. ObjectAnimator hands off this functionality to
+     * PropertyValuesHolder, since it holds all of the per-property information. This
+     * property is automatically
+     * derived when the animation starts in setupSetterAndGetter() if using ObjectAnimator.
+     * The getter is only derived and used if one of the values is null.
+     */
+    private Method mGetter = null;
+
+    /**
+     * The type of values supplied. This information is used both in deriving the setter/getter
+     * functions and in deriving the type of TypeEvaluator.
+     */
+    Class mValueType;
+
+    /**
+     * The set of keyframes (time/value pairs) that define this animation.
+     */
+    KeyframeSet mKeyframeSet = null;
+
+
+    // type evaluators for the primitive types handled by this implementation
+    private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
+    private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
+
+    // We try several different types when searching for appropriate setter/getter functions.
+    // The caller may have supplied values in a type that does not match the setter/getter
+    // functions (such as the integers 0 and 1 to represent floating point values for alpha).
+    // Also, the use of generics in constructors means that we end up with the Object versions
+    // of primitive types (Float vs. float). But most likely, the setter/getter functions
+    // will take primitive types instead.
+    // So we supply an ordered array of other types to try before giving up.
+    private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class,
+            Double.class, Integer.class};
+    private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class,
+            Float.class, Double.class};
+    private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class,
+            Float.class, Integer.class};
+
+    // These maps hold all property entries for a particular class. This map
+    // is used to speed up property/setter/getter lookups for a given class/property
+    // combination. No need to use reflection on the combination more than once.
+    private static final HashMap<Class, HashMap<String, Method>> sSetterPropertyMap =
+            new HashMap<Class, HashMap<String, Method>>();
+    private static final HashMap<Class, HashMap<String, Method>> sGetterPropertyMap =
+            new HashMap<Class, HashMap<String, Method>>();
+
+    // This lock is used to ensure that only one thread is accessing the property maps
+    // at a time.
+    final ReentrantReadWriteLock mPropertyMapLock = new ReentrantReadWriteLock();
+
+    // Used to pass single value to varargs parameter in setter invocation
+    final Object[] mTmpValueArray = new Object[1];
+
+    /**
+     * The type evaluator used to calculate the animated values. This evaluator is determined
+     * automatically based on the type of the start/end objects passed into the constructor,
+     * but the system only knows about the primitive types int and float. Any other
+     * type will need to set the evaluator to a custom evaluator for that type.
+     */
+    private TypeEvaluator mEvaluator;
+
+    /**
+     * The value most recently calculated by calculateValue(). This is set during
+     * that function and might be retrieved later either by ValueAnimator.animatedValue() or
+     * by the property-setting logic in ObjectAnimator.animatedValue().
+     */
+    private Object mAnimatedValue;
+
+    /**
+     * Internal utility constructor, used by the factory methods to set the property name.
+     * @param propertyName The name of the property for this holder.
+     */
+    private PropertyValuesHolder(String propertyName) {
+        mPropertyName = propertyName;
+    }
+
+    /**
+     * Internal utility constructor, used by the factory methods to set the property.
+     * @param property The property for this holder.
+     */
+    //private PropertyValuesHolder(Property property) {
+    //    mProperty = property;
+    //    if (property != null) {
+    //        mPropertyName = property.getName();
+    //    }
+    //}
+
+    /**
+     * Constructs and returns a PropertyValuesHolder with a given property name and
+     * set of int values.
+     * @param propertyName The name of the property being animated.
+     * @param values The values that the named property will animate between.
+     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
+     */
+    public static PropertyValuesHolder ofInt(String propertyName, int... values) {
+        return new IntPropertyValuesHolder(propertyName, values);
+    }
+
+    /**
+     * Constructs and returns a PropertyValuesHolder with a given property and
+     * set of int values.
+     * @param property The property being animated. Should not be null.
+     * @param values The values that the property will animate between.
+     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
+     */
+    //public static PropertyValuesHolder ofInt(Property<?, Integer> property, int... values) {
+    //    return new IntPropertyValuesHolder(property, values);
+    //}
+
+    /**
+     * Constructs and returns a PropertyValuesHolder with a given property name and
+     * set of float values.
+     * @param propertyName The name of the property being animated.
+     * @param values The values that the named property will animate between.
+     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
+     */
+    public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
+        return new FloatPropertyValuesHolder(propertyName, values);
+    }
+
+    /**
+     * Constructs and returns a PropertyValuesHolder with a given property and
+     * set of float values.
+     * @param property The property being animated. Should not be null.
+     * @param values The values that the property will animate between.
+     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
+     */
+    //public static PropertyValuesHolder ofFloat(Property<?, Float> property, float... values) {
+    //    return new FloatPropertyValuesHolder(property, values);
+    //}
+
+    /**
+     * Constructs and returns a PropertyValuesHolder with a given property name and
+     * set of Object values. This variant also takes a TypeEvaluator because the system
+     * cannot automatically interpolate between objects of unknown type.
+     *
+     * @param propertyName The name of the property being animated.
+     * @param evaluator A TypeEvaluator that will be called on each animation frame to
+     * provide the necessary interpolation between the Object values to derive the animated
+     * value.
+     * @param values The values that the named property will animate between.
+     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
+     */
+    public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator,
+            Object... values) {
+        PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
+        pvh.setObjectValues(values);
+        pvh.setEvaluator(evaluator);
+        return pvh;
+    }
+
+    /**
+     * Constructs and returns a PropertyValuesHolder with a given property and
+     * set of Object values. This variant also takes a TypeEvaluator because the system
+     * cannot automatically interpolate between objects of unknown type.
+     *
+     * @param property The property being animated. Should not be null.
+     * @param evaluator A TypeEvaluator that will be called on each animation frame to
+     * provide the necessary interpolation between the Object values to derive the animated
+     * value.
+     * @param values The values that the property will animate between.
+     * @return PropertyValuesHolder The constructed PropertyValuesHolder object.
+     */
+    //public static <V> PropertyValuesHolder ofObject(Property property,
+    //        TypeEvaluator<V> evaluator, V... values) {
+    //    PropertyValuesHolder pvh = new PropertyValuesHolder(property);
+    //    pvh.setObjectValues(values);
+    //    pvh.setEvaluator(evaluator);
+    //    return pvh;
+    //}
+
+    /**
+     * Constructs and returns a PropertyValuesHolder object with the specified property name and set
+     * of values. These values can be of any type, but the type should be consistent so that
+     * an appropriate {@link android.animation.TypeEvaluator} can be found that matches
+     * the common type.
+     * <p>If there is only one value, it is assumed to be the end value of an animation,
+     * and an initial value will be derived, if possible, by calling a getter function
+     * on the object. Also, if any value is null, the value will be filled in when the animation
+     * starts in the same way. This mechanism of automatically getting null values only works
+     * if the PropertyValuesHolder object is used in conjunction
+     * {@link ObjectAnimator}, and with a getter function
+     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
+     * no way of determining what the value should be.
+     * @param propertyName The name of the property associated with this set of values. This
+     * can be the actual property name to be used when using a ObjectAnimator object, or
+     * just a name used to get animated values, such as if this object is used with an
+     * ValueAnimator object.
+     * @param values The set of values to animate between.
+     */
+    public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) {
+        KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
+        if (keyframeSet instanceof IntKeyframeSet) {
+            return new IntPropertyValuesHolder(propertyName, (IntKeyframeSet) keyframeSet);
+        } else if (keyframeSet instanceof FloatKeyframeSet) {
+            return new FloatPropertyValuesHolder(propertyName, (FloatKeyframeSet) keyframeSet);
+        }
+        else {
+            PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName);
+            pvh.mKeyframeSet = keyframeSet;
+            pvh.mValueType = values[0].getType();
+            return pvh;
+        }
+    }
+
+    /**
+     * Constructs and returns a PropertyValuesHolder object with the specified property and set
+     * of values. These values can be of any type, but the type should be consistent so that
+     * an appropriate {@link android.animation.TypeEvaluator} can be found that matches
+     * the common type.
+     * <p>If there is only one value, it is assumed to be the end value of an animation,
+     * and an initial value will be derived, if possible, by calling the property's
+     * {@link android.util.Property#get(Object)} function.
+     * Also, if any value is null, the value will be filled in when the animation
+     * starts in the same way. This mechanism of automatically getting null values only works
+     * if the PropertyValuesHolder object is used in conjunction with
+     * {@link ObjectAnimator}, since otherwise PropertyValuesHolder has
+     * no way of determining what the value should be.
+     * @param property The property associated with this set of values. Should not be null.
+     * @param values The set of values to animate between.
+     */
+    //public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values) {
+    //    KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values);
+    //    if (keyframeSet instanceof IntKeyframeSet) {
+    //        return new IntPropertyValuesHolder(property, (IntKeyframeSet) keyframeSet);
+    //    } else if (keyframeSet instanceof FloatKeyframeSet) {
+    //        return new FloatPropertyValuesHolder(property, (FloatKeyframeSet) keyframeSet);
+    //    }
+    //    else {
+    //        PropertyValuesHolder pvh = new PropertyValuesHolder(property);
+    //        pvh.mKeyframeSet = keyframeSet;
+    //        pvh.mValueType = ((Keyframe)values[0]).getType();
+    //        return pvh;
+    //    }
+    //}
+
+    /**
+     * Set the animated values for this object to this set of ints.
+     * If there is only one value, it is assumed to be the end value of an animation,
+     * and an initial value will be derived, if possible, by calling a getter function
+     * on the object. Also, if any value is null, the value will be filled in when the animation
+     * starts in the same way. This mechanism of automatically getting null values only works
+     * if the PropertyValuesHolder object is used in conjunction
+     * {@link ObjectAnimator}, and with a getter function
+     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
+     * no way of determining what the value should be.
+     *
+     * @param values One or more values that the animation will animate between.
+     */
+    public void setIntValues(int... values) {
+        mValueType = int.class;
+        mKeyframeSet = KeyframeSet.ofInt(values);
+    }
+
+    /**
+     * Set the animated values for this object to this set of floats.
+     * If there is only one value, it is assumed to be the end value of an animation,
+     * and an initial value will be derived, if possible, by calling a getter function
+     * on the object. Also, if any value is null, the value will be filled in when the animation
+     * starts in the same way. This mechanism of automatically getting null values only works
+     * if the PropertyValuesHolder object is used in conjunction
+     * {@link ObjectAnimator}, and with a getter function
+     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
+     * no way of determining what the value should be.
+     *
+     * @param values One or more values that the animation will animate between.
+     */
+    public void setFloatValues(float... values) {
+        mValueType = float.class;
+        mKeyframeSet = KeyframeSet.ofFloat(values);
+    }
+
+    /**
+     * Set the animated values for this object to this set of Keyframes.
+     *
+     * @param values One or more values that the animation will animate between.
+     */
+    public void setKeyframes(Keyframe... values) {
+        int numKeyframes = values.length;
+        Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes,2)];
+        mValueType = values[0].getType();
+        for (int i = 0; i < numKeyframes; ++i) {
+            keyframes[i] = values[i];
+        }
+        mKeyframeSet = new KeyframeSet(keyframes);
+    }
+
+    /**
+     * Set the animated values for this object to this set of Objects.
+     * If there is only one value, it is assumed to be the end value of an animation,
+     * and an initial value will be derived, if possible, by calling a getter function
+     * on the object. Also, if any value is null, the value will be filled in when the animation
+     * starts in the same way. This mechanism of automatically getting null values only works
+     * if the PropertyValuesHolder object is used in conjunction
+     * {@link ObjectAnimator}, and with a getter function
+     * derived automatically from <code>propertyName</code>, since otherwise PropertyValuesHolder has
+     * no way of determining what the value should be.
+     *
+     * @param values One or more values that the animation will animate between.
+     */
+    public void setObjectValues(Object... values) {
+        mValueType = values[0].getClass();
+        mKeyframeSet = KeyframeSet.ofObject(values);
+    }
+
+    /**
+     * Determine the setter or getter function using the JavaBeans convention of setFoo or
+     * getFoo for a property named 'foo'. This function figures out what the name of the
+     * function should be and uses reflection to find the Method with that name on the
+     * target object.
+     *
+     * @param targetClass The class to search for the method
+     * @param prefix "set" or "get", depending on whether we need a setter or getter.
+     * @param valueType The type of the parameter (in the case of a setter). This type
+     * is derived from the values set on this PropertyValuesHolder. This type is used as
+     * a first guess at the parameter type, but we check for methods with several different
+     * types to avoid problems with slight mis-matches between supplied values and actual
+     * value types used on the setter.
+     * @return Method the method associated with mPropertyName.
+     */
+    private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
+        // TODO: faster implementation...
+        Method returnVal = null;
+        String methodName = getMethodName(prefix, mPropertyName);
+        Class args[] = null;
+        if (valueType == null) {
+            try {
+                returnVal = targetClass.getMethod(methodName, args);
+            } catch (NoSuchMethodException e) {
+                Log.e("PropertyValuesHolder", targetClass.getSimpleName() + " - " +
+                        "Couldn't find no-arg method for property " + mPropertyName + ": " + e);
+            }
+        } else {
+            args = new Class[1];
+            Class typeVariants[];
+            if (mValueType.equals(Float.class)) {
+                typeVariants = FLOAT_VARIANTS;
+            } else if (mValueType.equals(Integer.class)) {
+                typeVariants = INTEGER_VARIANTS;
+            } else if (mValueType.equals(Double.class)) {
+                typeVariants = DOUBLE_VARIANTS;
+            } else {
+                typeVariants = new Class[1];
+                typeVariants[0] = mValueType;
+            }
+            for (Class typeVariant : typeVariants) {
+                args[0] = typeVariant;
+                try {
+                    returnVal = targetClass.getMethod(methodName, args);
+                    // change the value type to suit
+                    mValueType = typeVariant;
+                    return returnVal;
+                } catch (NoSuchMethodException e) {
+                    // Swallow the error and keep trying other variants
+                }
+            }
+            // If we got here, then no appropriate function was found
+            Log.e("PropertyValuesHolder",
+                    "Couldn't find " + prefix + "ter property " + mPropertyName +
+                            " for " + targetClass.getSimpleName() +
+                            " with value type "+ mValueType);
+        }
+
+        return returnVal;
+    }
+
+
+    /**
+     * Returns the setter or getter requested. This utility function checks whether the
+     * requested method exists in the propertyMapMap cache. If not, it calls another
+     * utility function to request the Method from the targetClass directly.
+     * @param targetClass The Class on which the requested method should exist.
+     * @param propertyMapMap The cache of setters/getters derived so far.
+     * @param prefix "set" or "get", for the setter or getter.
+     * @param valueType The type of parameter passed into the method (null for getter).
+     * @return Method the method associated with mPropertyName.
+     */
+    private Method setupSetterOrGetter(Class targetClass,
+            HashMap<Class, HashMap<String, Method>> propertyMapMap,
+            String prefix, Class valueType) {
+        Method setterOrGetter = null;
+        try {
+            // Have to lock property map prior to reading it, to guard against
+            // another thread putting something in there after we've checked it
+            // but before we've added an entry to it
+            mPropertyMapLock.writeLock().lock();
+            HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
+            if (propertyMap != null) {
+                setterOrGetter = propertyMap.get(mPropertyName);
+            }
+            if (setterOrGetter == null) {
+                setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
+                if (propertyMap == null) {
+                    propertyMap = new HashMap<String, Method>();
+                    propertyMapMap.put(targetClass, propertyMap);
+                }
+                propertyMap.put(mPropertyName, setterOrGetter);
+            }
+        } finally {
+            mPropertyMapLock.writeLock().unlock();
+        }
+        return setterOrGetter;
+    }
+
+    /**
+     * Utility function to get the setter from targetClass
+     * @param targetClass The Class on which the requested method should exist.
+     */
+    void setupSetter(Class targetClass) {
+        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType);
+    }
+
+    /**
+     * Utility function to get the getter from targetClass
+     */
+    private void setupGetter(Class targetClass) {
+        mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
+    }
+
+    /**
+     * Internal function (called from ObjectAnimator) to set up the setter and getter
+     * prior to running the animation. If the setter has not been manually set for this
+     * object, it will be derived automatically given the property name, target object, and
+     * types of values supplied. If no getter has been set, it will be supplied iff any of the
+     * supplied values was null. If there is a null value, then the getter (supplied or derived)
+     * will be called to set those null values to the current value of the property
+     * on the target object.
+     * @param target The object on which the setter (and possibly getter) exist.
+     */
+    void setupSetterAndGetter(Object target) {
+        //if (mProperty != null) {
+        //    // check to make sure that mProperty is on the class of target
+        //    try {
+        //        Object testValue = mProperty.get(target);
+        //        for (Keyframe kf : mKeyframeSet.mKeyframes) {
+        //            if (!kf.hasValue()) {
+        //                kf.setValue(mProperty.get(target));
+        //            }
+        //        }
+        //        return;
+        //    } catch (ClassCastException e) {
+        //        Log.e("PropertyValuesHolder","No such property (" + mProperty.getName() +
+        //                ") on target object " + target + ". Trying reflection instead");
+        //        mProperty = null;
+        //    }
+        //}
+        Class targetClass = target.getClass();
+        if (mSetter == null) {
+            setupSetter(targetClass);
+        }
+        for (Keyframe kf : mKeyframeSet.mKeyframes) {
+            if (!kf.hasValue()) {
+                if (mGetter == null) {
+                    setupGetter(targetClass);
+                }
+                try {
+                    kf.setValue(mGetter.invoke(target));
+                } catch (InvocationTargetException e) {
+                    Log.e("PropertyValuesHolder", e.toString());
+                } catch (IllegalAccessException e) {
+                    Log.e("PropertyValuesHolder", e.toString());
+                }
+            }
+        }
+    }
+
+    /**
+     * Utility function to set the value stored in a particular Keyframe. The value used is
+     * whatever the value is for the property name specified in the keyframe on the target object.
+     *
+     * @param target The target object from which the current value should be extracted.
+     * @param kf The keyframe which holds the property name and value.
+     */
+    private void setupValue(Object target, Keyframe kf) {
+        //if (mProperty != null) {
+        //    kf.setValue(mProperty.get(target));
+        //}
+        try {
+            if (mGetter == null) {
+                Class targetClass = target.getClass();
+                setupGetter(targetClass);
+            }
+            kf.setValue(mGetter.invoke(target));
+        } catch (InvocationTargetException e) {
+            Log.e("PropertyValuesHolder", e.toString());
+        } catch (IllegalAccessException e) {
+            Log.e("PropertyValuesHolder", e.toString());
+        }
+    }
+
+    /**
+     * This function is called by ObjectAnimator when setting the start values for an animation.
+     * The start values are set according to the current values in the target object. The
+     * property whose value is extracted is whatever is specified by the propertyName of this
+     * PropertyValuesHolder object.
+     *
+     * @param target The object which holds the start values that should be set.
+     */
+    void setupStartValue(Object target) {
+        setupValue(target, mKeyframeSet.mKeyframes.get(0));
+    }
+
+    /**
+     * This function is called by ObjectAnimator when setting the end values for an animation.
+     * The end values are set according to the current values in the target object. The
+     * property whose value is extracted is whatever is specified by the propertyName of this
+     * PropertyValuesHolder object.
+     *
+     * @param target The object which holds the start values that should be set.
+     */
+    void setupEndValue(Object target) {
+        setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1));
+    }
+
+    @Override
+    public PropertyValuesHolder clone() {
+        try {
+            PropertyValuesHolder newPVH = (PropertyValuesHolder) super.clone();
+            newPVH.mPropertyName = mPropertyName;
+            //newPVH.mProperty = mProperty;
+            newPVH.mKeyframeSet = mKeyframeSet.clone();
+            newPVH.mEvaluator = mEvaluator;
+            return newPVH;
+        } catch (CloneNotSupportedException e) {
+            // won't reach here
+            return null;
+        }
+    }
+
+    /**
+     * Internal function to set the value on the target object, using the setter set up
+     * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
+     * to handle turning the value calculated by ValueAnimator into a value set on the object
+     * according to the name of the property.
+     * @param target The target object on which the value is set
+     */
+    void setAnimatedValue(Object target) {
+        //if (mProperty != null) {
+        //    mProperty.set(target, getAnimatedValue());
+        //}
+        if (mSetter != null) {
+            try {
+                mTmpValueArray[0] = getAnimatedValue();
+                mSetter.invoke(target, mTmpValueArray);
+            } catch (InvocationTargetException e) {
+                Log.e("PropertyValuesHolder", e.toString());
+            } catch (IllegalAccessException e) {
+                Log.e("PropertyValuesHolder", e.toString());
+            }
+        }
+    }
+
+    /**
+     * Internal function, called by ValueAnimator, to set up the TypeEvaluator that will be used
+     * to calculate animated values.
+     */
+    void init() {
+        if (mEvaluator == null) {
+            // We already handle int and float automatically, but not their Object
+            // equivalents
+            mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
+                    (mValueType == Float.class) ? sFloatEvaluator :
+                    null;
+        }
+        if (mEvaluator != null) {
+            // KeyframeSet knows how to evaluate the common types - only give it a custom
+            // evaluator if one has been set on this class
+            mKeyframeSet.setEvaluator(mEvaluator);
+        }
+    }
+
+    /**
+     * The TypeEvaluator will the automatically determined based on the type of values
+     * supplied to PropertyValuesHolder. The evaluator can be manually set, however, if so
+     * desired. This may be important in cases where either the type of the values supplied
+     * do not match the way that they should be interpolated between, or if the values
+     * are of a custom type or one not currently understood by the animation system. Currently,
+     * only values of type float and int (and their Object equivalents: Float
+     * and Integer) are  correctly interpolated; all other types require setting a TypeEvaluator.
+     * @param evaluator
+     */
+    public void setEvaluator(TypeEvaluator evaluator) {
+        mEvaluator = evaluator;
+        mKeyframeSet.setEvaluator(evaluator);
+    }
+
+    /**
+     * Function used to calculate the value according to the evaluator set up for
+     * this PropertyValuesHolder object. This function is called by ValueAnimator.animateValue().
+     *
+     * @param fraction The elapsed, interpolated fraction of the animation.
+     */
+    void calculateValue(float fraction) {
+        mAnimatedValue = mKeyframeSet.getValue(fraction);
+    }
+
+    /**
+     * Sets the name of the property that will be animated. This name is used to derive
+     * a setter function that will be called to set animated values.
+     * For example, a property name of <code>foo</code> will result
+     * in a call to the function <code>setFoo()</code> on the target object. If either
+     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
+     * also be derived and called.
+     *
+     * <p>Note that the setter function derived from this property name
+     * must take the same parameter type as the
+     * <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
+     * the setter function will fail.</p>
+     *
+     * @param propertyName The name of the property being animated.
+     */
+    public void setPropertyName(String propertyName) {
+        mPropertyName = propertyName;
+    }
+
+    /**
+     * Sets the property that will be animated.
+     *
+     * <p>Note that if this PropertyValuesHolder object is used with ObjectAnimator, the property
+     * must exist on the target object specified in that ObjectAnimator.</p>
+     *
+     * @param property The property being animated.
+     */
+    //public void setProperty(Property property) {
+    //    mProperty = property;
+    //}
+
+    /**
+     * Gets the name of the property that will be animated. This name will be used to derive
+     * a setter function that will be called to set animated values.
+     * For example, a property name of <code>foo</code> will result
+     * in a call to the function <code>setFoo()</code> on the target object. If either
+     * <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
+     * also be derived and called.
+     */
+    public String getPropertyName() {
+        return mPropertyName;
+    }
+
+    /**
+     * Internal function, called by ValueAnimator and ObjectAnimator, to retrieve the value
+     * most recently calculated in calculateValue().
+     * @return
+     */
+    Object getAnimatedValue() {
+        return mAnimatedValue;
+    }
+
+    @Override
+    public String toString() {
+        return mPropertyName + ": " + mKeyframeSet.toString();
+    }
+
+    /**
+     * Utility method to derive a setter/getter method name from a property name, where the
+     * prefix is typically "set" or "get" and the first letter of the property name is
+     * capitalized.
+     *
+     * @param prefix The precursor to the method name, before the property name begins, typically
+     * "set" or "get".
+     * @param propertyName The name of the property that represents the bulk of the method name
+     * after the prefix. The first letter of this word will be capitalized in the resulting
+     * method name.
+     * @return String the property name converted to a method name according to the conventions
+     * specified above.
+     */
+    static String getMethodName(String prefix, String propertyName) {
+        if (propertyName == null || propertyName.length() == 0) {
+            // shouldn't get here
+            return prefix;
+        }
+        char firstLetter = Character.toUpperCase(propertyName.charAt(0));
+        String theRest = propertyName.substring(1);
+        return prefix + firstLetter + theRest;
+    }
+
+    static class IntPropertyValuesHolder extends PropertyValuesHolder {
+
+        // Cache JNI functions to avoid looking them up twice
+        //private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
+        //        new HashMap<Class, HashMap<String, Integer>>();
+        //int mJniSetter;
+        //private IntProperty mIntProperty;
+
+        IntKeyframeSet mIntKeyframeSet;
+        int mIntAnimatedValue;
+
+        public IntPropertyValuesHolder(String propertyName, IntKeyframeSet keyframeSet) {
+            super(propertyName);
+            mValueType = int.class;
+            mKeyframeSet = keyframeSet;
+            mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
+        }
+
+        //public IntPropertyValuesHolder(Property property, IntKeyframeSet keyframeSet) {
+        //    super(property);
+        //    mValueType = int.class;
+        //    mKeyframeSet = keyframeSet;
+        //    mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
+        //    if (property instanceof  IntProperty) {
+        //        mIntProperty = (IntProperty) mProperty;
+        //    }
+        //}
+
+        public IntPropertyValuesHolder(String propertyName, int... values) {
+            super(propertyName);
+            setIntValues(values);
+        }
+
+        //public IntPropertyValuesHolder(Property property, int... values) {
+        //    super(property);
+        //    setIntValues(values);
+        //    if (property instanceof  IntProperty) {
+        //        mIntProperty = (IntProperty) mProperty;
+        //    }
+        //}
+
+        @Override
+        public void setIntValues(int... values) {
+            super.setIntValues(values);
+            mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet;
+        }
+
+        @Override
+        void calculateValue(float fraction) {
+            mIntAnimatedValue = mIntKeyframeSet.getIntValue(fraction);
+        }
+
+        @Override
+        Object getAnimatedValue() {
+            return mIntAnimatedValue;
+        }
+
+        @Override
+        public IntPropertyValuesHolder clone() {
+            IntPropertyValuesHolder newPVH = (IntPropertyValuesHolder) super.clone();
+            newPVH.mIntKeyframeSet = (IntKeyframeSet) newPVH.mKeyframeSet;
+            return newPVH;
+        }
+
+        /**
+         * Internal function to set the value on the target object, using the setter set up
+         * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
+         * to handle turning the value calculated by ValueAnimator into a value set on the object
+         * according to the name of the property.
+         * @param target The target object on which the value is set
+         */
+        @Override
+        void setAnimatedValue(Object target) {
+            //if (mIntProperty != null) {
+            //    mIntProperty.setValue(target, mIntAnimatedValue);
+            //    return;
+            //}
+            //if (mProperty != null) {
+            //    mProperty.set(target, mIntAnimatedValue);
+            //    return;
+            //}
+            //if (mJniSetter != 0) {
+            //    nCallIntMethod(target, mJniSetter, mIntAnimatedValue);
+            //    return;
+            //}
+            if (mSetter != null) {
+                try {
+                    mTmpValueArray[0] = mIntAnimatedValue;
+                    mSetter.invoke(target, mTmpValueArray);
+                } catch (InvocationTargetException e) {
+                    Log.e("PropertyValuesHolder", e.toString());
+                } catch (IllegalAccessException e) {
+                    Log.e("PropertyValuesHolder", e.toString());
+                }
+            }
+        }
+
+        @Override
+        void setupSetter(Class targetClass) {
+            //if (mProperty != null) {
+            //    return;
+            //}
+            // Check new static hashmap<propName, int> for setter method
+            //try {
+            //    mPropertyMapLock.writeLock().lock();
+            //    HashMap<String, Integer> propertyMap = sJNISetterPropertyMap.get(targetClass);
+            //    if (propertyMap != null) {
+            //        Integer mJniSetterInteger = propertyMap.get(mPropertyName);
+            //        if (mJniSetterInteger != null) {
+            //            mJniSetter = mJniSetterInteger;
+            //        }
+            //    }
+            //    if (mJniSetter == 0) {
+            //        String methodName = getMethodName("set", mPropertyName);
+            //        mJniSetter = nGetIntMethod(targetClass, methodName);
+            //        if (mJniSetter != 0) {
+            //            if (propertyMap == null) {
+            //                propertyMap = new HashMap<String, Integer>();
+            //                sJNISetterPropertyMap.put(targetClass, propertyMap);
+            //            }
+            //            propertyMap.put(mPropertyName, mJniSetter);
+            //        }
+            //    }
+            //} catch (NoSuchMethodError e) {
+            //    Log.d("PropertyValuesHolder",
+            //            "Can't find native method using JNI, use reflection" + e);
+            //} finally {
+            //    mPropertyMapLock.writeLock().unlock();
+            //}
+            //if (mJniSetter == 0) {
+                // Couldn't find method through fast JNI approach - just use reflection
+                super.setupSetter(targetClass);
+            //}
+        }
+    }
+
+    static class FloatPropertyValuesHolder extends PropertyValuesHolder {
+
+        // Cache JNI functions to avoid looking them up twice
+        //private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
+        //        new HashMap<Class, HashMap<String, Integer>>();
+        //int mJniSetter;
+        //private FloatProperty mFloatProperty;
+
+        FloatKeyframeSet mFloatKeyframeSet;
+        float mFloatAnimatedValue;
+
+        public FloatPropertyValuesHolder(String propertyName, FloatKeyframeSet keyframeSet) {
+            super(propertyName);
+            mValueType = float.class;
+            mKeyframeSet = keyframeSet;
+            mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
+        }
+
+        //public FloatPropertyValuesHolder(Property property, FloatKeyframeSet keyframeSet) {
+        //    super(property);
+        //    mValueType = float.class;
+        //    mKeyframeSet = keyframeSet;
+        //    mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
+        //    if (property instanceof FloatProperty) {
+        //        mFloatProperty = (FloatProperty) mProperty;
+        //    }
+        //}
+
+        public FloatPropertyValuesHolder(String propertyName, float... values) {
+            super(propertyName);
+            setFloatValues(values);
+        }
+
+        //public FloatPropertyValuesHolder(Property property, float... values) {
+        //    super(property);
+        //    setFloatValues(values);
+        //    if (property instanceof  FloatProperty) {
+        //        mFloatProperty = (FloatProperty) mProperty;
+        //    }
+        //}
+
+        @Override
+        public void setFloatValues(float... values) {
+            super.setFloatValues(values);
+            mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet;
+        }
+
+        @Override
+        void calculateValue(float fraction) {
+            mFloatAnimatedValue = mFloatKeyframeSet.getFloatValue(fraction);
+        }
+
+        @Override
+        Object getAnimatedValue() {
+            return mFloatAnimatedValue;
+        }
+
+        @Override
+        public FloatPropertyValuesHolder clone() {
+            FloatPropertyValuesHolder newPVH = (FloatPropertyValuesHolder) super.clone();
+            newPVH.mFloatKeyframeSet = (FloatKeyframeSet) newPVH.mKeyframeSet;
+            return newPVH;
+        }
+
+        /**
+         * Internal function to set the value on the target object, using the setter set up
+         * earlier on this PropertyValuesHolder object. This function is called by ObjectAnimator
+         * to handle turning the value calculated by ValueAnimator into a value set on the object
+         * according to the name of the property.
+         * @param target The target object on which the value is set
+         */
+        @Override
+        void setAnimatedValue(Object target) {
+            //if (mFloatProperty != null) {
+            //    mFloatProperty.setValue(target, mFloatAnimatedValue);
+            //    return;
+            //}
+            //if (mProperty != null) {
+            //    mProperty.set(target, mFloatAnimatedValue);
+            //    return;
+            //}
+            //if (mJniSetter != 0) {
+            //    nCallFloatMethod(target, mJniSetter, mFloatAnimatedValue);
+            //    return;
+            //}
+            if (mSetter != null) {
+                try {
+                    mTmpValueArray[0] = mFloatAnimatedValue;
+                    mSetter.invoke(target, mTmpValueArray);
+                } catch (InvocationTargetException e) {
+                    Log.e("PropertyValuesHolder", e.toString());
+                } catch (IllegalAccessException e) {
+                    Log.e("PropertyValuesHolder", e.toString());
+                }
+            }
+        }
+
+        @Override
+        void setupSetter(Class targetClass) {
+            //if (mProperty != null) {
+            //    return;
+            //}
+            // Check new static hashmap<propName, int> for setter method
+            //try {
+            //    mPropertyMapLock.writeLock().lock();
+            //    HashMap<String, Integer> propertyMap = sJNISetterPropertyMap.get(targetClass);
+            //    if (propertyMap != null) {
+            //        Integer mJniSetterInteger = propertyMap.get(mPropertyName);
+            //        if (mJniSetterInteger != null) {
+            //            mJniSetter = mJniSetterInteger;
+            //        }
+            //    }
+            //    if (mJniSetter == 0) {
+            //        String methodName = getMethodName("set", mPropertyName);
+            //        mJniSetter = nGetFloatMethod(targetClass, methodName);
+            //        if (mJniSetter != 0) {
+            //            if (propertyMap == null) {
+            //                propertyMap = new HashMap<String, Integer>();
+            //                sJNISetterPropertyMap.put(targetClass, propertyMap);
+            //            }
+            //            propertyMap.put(mPropertyName, mJniSetter);
+            //        }
+            //    }
+            //} catch (NoSuchMethodError e) {
+            //    Log.d("PropertyValuesHolder",
+            //            "Can't find native method using JNI, use reflection" + e);
+            //} finally {
+            //    mPropertyMapLock.writeLock().unlock();
+            //}
+            //if (mJniSetter == 0) {
+                // Couldn't find method through fast JNI approach - just use reflection
+                super.setupSetter(targetClass);
+            //}
+        }
+
+    }
+
+    //native static private int nGetIntMethod(Class targetClass, String methodName);
+    //native static private int nGetFloatMethod(Class targetClass, String methodName);
+    //native static private void nCallIntMethod(Object target, int methodID, int arg);
+    //native static private void nCallFloatMethod(Object target, int methodID, float arg);
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/TypeEvaluator.java
new file mode 100644 (file)
index 0000000..0ea3192
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+/**
+ * Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators
+ * allow developers to create animations on arbitrary property types, by allowing them to supply
+ * custom evaulators for types that are not automatically understood and used by the animation
+ * system.
+ *
+ * @see ValueAnimator#setEvaluator(TypeEvaluator)
+ */
+public interface TypeEvaluator<T> {
+
+    /**
+     * This function returns the result of linearly interpolating the start and end values, with
+     * <code>fraction</code> representing the proportion between the start and end values. The
+     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
+     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
+     * and <code>t</code> is <code>fraction</code>.
+     *
+     * @param fraction   The fraction from the starting to the ending values
+     * @param startValue The start value.
+     * @param endValue   The end value.
+     * @return A linear interpolation between the start and end values, given the
+     *         <code>fraction</code> parameter.
+     */
+    public T evaluate(float fraction, T startValue, T endValue);
+
+}
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/animation/ValueAnimator.java
new file mode 100644 (file)
index 0000000..d8a12c6
--- /dev/null
@@ -0,0 +1,1265 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.nineoldandroids.animation;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.AndroidRuntimeException;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * This class provides a simple timing engine for running animations
+ * which calculate animated values and set them on target objects.
+ *
+ * <p>There is a single timing pulse that all animations use. It runs in a
+ * custom handler to ensure that property changes happen on the UI thread.</p>
+ *
+ * <p>By default, ValueAnimator uses non-linear time interpolation, via the
+ * {@link AccelerateDecelerateInterpolator} class, which accelerates into and decelerates
+ * out of an animation. This behavior can be changed by calling
+ * {@link ValueAnimator#setInterpolator(TimeInterpolator)}.</p>
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class ValueAnimator extends Animator {
+
+    /**
+     * Internal constants
+     */
+
+    /*
+     * The default amount of time in ms between animation frames
+     */
+    private static final long DEFAULT_FRAME_DELAY = 10;
+
+    /**
+     * Messages sent to timing handler: START is sent when an animation first begins, FRAME is sent
+     * by the handler to itself to process the next animation frame
+     */
+    static final int ANIMATION_START = 0;
+    static final int ANIMATION_FRAME = 1;
+
+    /**
+     * Values used with internal variable mPlayingState to indicate the current state of an
+     * animation.
+     */
+    static final int STOPPED    = 0; // Not yet playing
+    static final int RUNNING    = 1; // Playing normally
+    static final int SEEKED     = 2; // Seeked to some time value
+
+    /**
+     * Internal variables
+     * NOTE: This object implements the clone() method, making a deep copy of any referenced
+     * objects. As other non-trivial fields are added to this class, make sure to add logic
+     * to clone() to make deep copies of them.
+     */
+
+    // The first time that the animation's animateFrame() method is called. This time is used to
+    // determine elapsed time (and therefore the elapsed fraction) in subsequent calls
+    // to animateFrame()
+    long mStartTime;
+
+    /**
+     * Set when setCurrentPlayTime() is called. If negative, animation is not currently seeked
+     * to a value.
+     */
+    long mSeekTime = -1;
+
+    // TODO: We access the following ThreadLocal variables often, some of them on every update.
+    // If ThreadLocal access is significantly expensive, we may want to put all of these
+    // fields into a structure sot hat we just access ThreadLocal once to get the reference
+    // to that structure, then access the structure directly for each field.
+
+    // The static sAnimationHandler processes the internal timing loop on which all animations
+    // are based
+    private static ThreadLocal<AnimationHandler> sAnimationHandler =
+            new ThreadLocal<AnimationHandler>();
+
+    // The per-thread list of all active animations
+    private static final ThreadLocal<ArrayList<ValueAnimator>> sAnimations =
+            new ThreadLocal<ArrayList<ValueAnimator>>() {
+                @Override
+                protected ArrayList<ValueAnimator> initialValue() {
+                    return new ArrayList<ValueAnimator>();
+                }
+            };
+
+    // The per-thread set of animations to be started on the next animation frame
+    private static final ThreadLocal<ArrayList<ValueAnimator>> sPendingAnimations =
+            new ThreadLocal<ArrayList<ValueAnimator>>() {
+                @Override
+                protected ArrayList<ValueAnimator> initialValue() {
+                    return new ArrayList<ValueAnimator>();
+                }
+            };
+
+    /**
+     * Internal per-thread collections used to avoid set collisions as animations start and end
+     * while being processed.
+     */
+    private static final ThreadLocal<ArrayList<ValueAnimator>> sDelayedAnims =
+            new ThreadLocal<ArrayList<ValueAnimator>>() {
+                @Override
+                protected ArrayList<ValueAnimator> initialValue() {
+                    return new ArrayList<ValueAnimator>();
+                }
+            };
+
+    private static final ThreadLocal<ArrayList<ValueAnimator>> sEndingAnims =
+            new ThreadLocal<ArrayList<ValueAnimator>>() {
+                @Override
+                protected ArrayList<ValueAnimator> initialValue() {
+                    return new ArrayList<ValueAnimator>();
+                }
+            };
+
+    private static final ThreadLocal<ArrayList<ValueAnimator>> sReadyAnims =
+            new ThreadLocal<ArrayList<ValueAnimator>>() {
+                @Override
+                protected ArrayList<ValueAnimator> initialValue() {
+                    return new ArrayList<ValueAnimator>();
+                }
+            };
+
+    // The time interpolator to be used if none is set on the animation
+    private static final /*Time*/Interpolator sDefaultInterpolator =
+            new AccelerateDecelerateInterpolator();
+
+    // type evaluators for the primitive types handled by this implementation
+    //private static final TypeEvaluator sIntEvaluator = new IntEvaluator();
+    //private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator();
+
+    /**
+     * Used to indicate whether the animation is currently playing in reverse. This causes the
+     * elapsed fraction to be inverted to calculate the appropriate values.
+     */
+    private boolean mPlayingBackwards = false;
+
+    /**
+     * This variable tracks the current iteration that is playing. When mCurrentIteration exceeds the
+     * repeatCount (if repeatCount!=INFINITE), the animation ends
+     */
+    private int mCurrentIteration = 0;
+
+    /**
+     * Tracks current elapsed/eased fraction, for querying in getAnimatedFraction().
+     */
+    private float mCurrentFraction = 0f;
+
+    /**
+     * Tracks whether a startDelay'd animation has begun playing through the startDelay.
+     */
+    private boolean mStartedDelay = false;
+
+    /**
+     * Tracks the time at which the animation began playing through its startDelay. This is
+     * different from the mStartTime variable, which is used to track when the animation became
+     * active (which is when the startDelay expired and the animation was added to the active
+     * animations list).
+     */
+    private long mDelayStartTime;
+
+    /**
+     * Flag that represents the current state of the animation. Used to figure out when to start
+     * an animation (if state == STOPPED). Also used to end an animation that
+     * has been cancel()'d or end()'d since the last animation frame. Possible values are
+     * STOPPED, RUNNING, SEEKED.
+     */
+    int mPlayingState = STOPPED;
+
+    /**
+     * Additional playing state to indicate whether an animator has been start()'d. There is
+     * some lag between a call to start() and the first animation frame. We should still note
+     * that the animation has been started, even if it's first animation frame has not yet
+     * happened, and reflect that state in isRunning().
+     * Note that delayed animations are different: they are not started until their first
+     * animation frame, which occurs after their delay elapses.
+     */
+    private boolean mRunning = false;
+
+    /**
+     * Additional playing state to indicate whether an animator has been start()'d, whether or
+     * not there is a nonzero startDelay.
+     */
+    private boolean mStarted = false;
+
+    /**
+     * Flag that denotes whether the animation is set up and ready to go. Used to
+     * set up animation that has not yet been started.
+     */
+    boolean mInitialized = false;
+
+    //
+    // Backing variables
+    //
+
+    // How long the animation should last in ms
+    private long mDuration = 300;
+
+    // The amount of time in ms to delay starting the animation after start() is called
+    private long mStartDelay = 0;
+
+    // The number of milliseconds between animation frames
+    private static long sFrameDelay = DEFAULT_FRAME_DELAY;
+
+    // The number of times the animation will repeat. The default is 0, which means the animation
+    // will play only once
+    private int mRepeatCount = 0;
+
+    /**
+     * The type of repetition that will occur when repeatMode is nonzero. RESTART means the
+     * animation will start from the beginning on every new cycle. REVERSE means the animation
+     * will reverse directions on each iteration.
+     */
+    private int mRepeatMode = RESTART;
+
+    /**
+     * The time interpolator to be used. The elapsed fraction of the animation will be passed
+     * through this interpolator to calculate the interpolated fraction, which is then used to
+     * calculate the animated values.
+     */
+    private /*Time*/Interpolator mInterpolator = sDefaultInterpolator;
+
+    /**
+     * The set of listeners to be sent events through the life of an animation.
+     */
+    private ArrayList<AnimatorUpdateListener> mUpdateListeners = null;
+
+    /**
+     * The property/value sets being animated.
+     */
+    PropertyValuesHolder[] mValues;
+
+    /**
+     * A hashmap of the PropertyValuesHolder objects. This map is used to lookup animated values
+     * by property name during calls to getAnimatedValue(String).
+     */
+    HashMap<String, PropertyValuesHolder> mValuesMap;
+
+    /**
+     * Public constants
+     */
+
+    /**
+     * When the animation reaches the end and <code>repeatCount</code> is INFINITE
+     * or a positive value, the animation restarts from the beginning.
+     */
+    public static final int RESTART = 1;
+    /**
+     * When the animation reaches the end and <code>repeatCount</code> is INFINITE
+     * or a positive value, the animation reverses direction on every iteration.
+     */
+    public static final int REVERSE = 2;
+    /**
+     * This value used used with the {@link #setRepeatCount(int)} property to repeat
+     * the animation indefinitely.
+     */
+    public static final int INFINITE = -1;
+
+    /**
+     * Creates a new ValueAnimator object. This default constructor is primarily for
+     * use internally; the factory methods which take parameters are more generally
+     * useful.
+     */
+    public ValueAnimator() {
+    }
+
+    /**
+     * Constructs and returns a ValueAnimator that animates between int values. A single
+     * value implies that that value is the one being animated to. However, this is not typically
+     * useful in a ValueAnimator object because there is no way for the object to determine the
+     * starting value for the animation (unlike ObjectAnimator, which can derive that value
+     * from the target object and property being animated). Therefore, there should typically
+     * be two or more values.
+     *
+     * @param values A set of values that the animation will animate between over time.
+     * @return A ValueAnimator object that is set up to animate between the given values.
+     */
+    public static ValueAnimator ofInt(int... values) {
+        ValueAnimator anim = new ValueAnimator();
+        anim.setIntValues(values);
+        return anim;
+    }
+
+    /**
+     * Constructs and returns a ValueAnimator that animates between float values. A single
+     * value implies that that value is the one being animated to. However, this is not typically
+     * useful in a ValueAnimator object because there is no way for the object to determine the
+     * starting value for the animation (unlike ObjectAnimator, which can derive that value
+     * from the target object and property being animated). Therefore, there should typically
+     * be two or more values.
+     *
+     * @param values A set of values that the animation will animate between over time.
+     * @return A ValueAnimator object that is set up to animate between the given values.
+     */
+    public static ValueAnimator ofFloat(float... values) {
+        ValueAnimator anim = new ValueAnimator();
+        anim.setFloatValues(values);
+        return anim;
+    }
+
+    /**
+     * Constructs and returns a ValueAnimator that animates between the values
+     * specified in the PropertyValuesHolder objects.
+     *
+     * @param values A set of PropertyValuesHolder objects whose values will be animated
+     * between over time.
+     * @return A ValueAnimator object that is set up to animate between the given values.
+     */
+    public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) {
+        ValueAnimator anim = new ValueAnimator();
+        anim.setValues(values);
+        return anim;
+    }
+    /**
+     * Constructs and returns a ValueAnimator that animates between Object values. A single
+     * value implies that that value is the one being animated to. However, this is not typically
+     * useful in a ValueAnimator object because there is no way for the object to determine the
+     * starting value for the animation (unlike ObjectAnimator, which can derive that value
+     * from the target object and property being animated). Therefore, there should typically
+     * be two or more values.
+     *
+     * <p>Since ValueAnimator does not know how to animate between arbitrary Objects, this
+     * factory method also takes a TypeEvaluator object that the ValueAnimator will use
+     * to perform that interpolation.
+     *
+     * @param evaluator A TypeEvaluator that will be called on each animation frame to
+     * provide the ncessry interpolation between the Object values to derive the animated
+     * value.
+     * @param values A set of values that the animation will animate between over time.
+     * @return A ValueAnimator object that is set up to animate between the given values.
+     */
+    public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) {
+        ValueAnimator anim = new ValueAnimator();
+        anim.setObjectValues(values);
+        anim.setEvaluator(evaluator);
+        return anim;
+    }
+
+    /**
+     * Sets int values that will be animated between. A single
+     * value implies that that value is the one being animated to. However, this is not typically
+     * useful in a ValueAnimator object because there is no way for the object to determine the
+     * starting value for the animation (unlike ObjectAnimator, which can derive that value
+     * from the target object and property being animated). Therefore, there should typically
+     * be two or more values.
+     *
+     * <p>If there are already multiple sets of values defined for this ValueAnimator via more
+     * than one PropertyValuesHolder object, this method will set the values for the first
+     * of those objects.</p>
+     *
+     * @param values A set of values that the animation will animate between over time.
+     */
+    public void setIntValues(int... values) {
+        if (values == null || values.length == 0) {
+            return;
+        }
+        if (mValues == null || mValues.length == 0) {
+            setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofInt("", values)});
+        } else {
+            PropertyValuesHolder valuesHolder = mValues[0];
+            valuesHolder.setIntValues(values);
+        }
+        // New property/values/target should cause re-initialization prior to starting
+        mInitialized = false;
+    }
+
+    /**
+     * Sets float values that will be animated between. A single
+     * value implies that that value is the one being animated to. However, this is not typically
+     * useful in a ValueAnimator object because there is no way for the object to determine the
+     * starting value for the animation (unlike ObjectAnimator, which can derive that value
+     * from the target object and property being animated). Therefore, there should typically
+     * be two or more values.
+     *
+     * <p>If there are already multiple sets of values defined for this ValueAnimator via more
+     * than one PropertyValuesHolder object, this method will set the values for the first
+     * of those objects.</p>
+     *
+     * @param values A set of values that the animation will animate between over time.
+     */
+    public void setFloatValues(float... values) {
+        if (values == null || values.length == 0) {
+            return;
+        }
+        if (mValues == null || mValues.length == 0) {
+            setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofFloat("", values)});
+        } else {
+            PropertyValuesHolder valuesHolder = mValues[0];
+            valuesHolder.setFloatValues(values);
+        }
+        // New property/values/target should cause re-initialization prior to starting
+        mInitialized = false;
+    }
+
+    /**
+     * Sets the values to animate between for this animation. A single
+     * value implies that that value is the one being animated to. However, this is not typically
+     * useful in a ValueAnimator object because there is no way for the object to determine the
+     * starting value for the animation (unlike ObjectAnimator, which can derive that value
+     * from the target object and property being animated). Therefore, there should typically
+     * be two or more values.
+     *
+     * <p>If there are already multiple sets of values defined for this ValueAnimator via more
+     * than one PropertyValuesHolder object, this method will set the values for the first
+     * of those objects.</p>
+     *
+     * <p>There should be a TypeEvaluator set on the ValueAnimator that knows how to interpolate
+     * between these value objects. ValueAnimator only knows how to interpolate between the
+     * primitive types specified in the other setValues() methods.</p>
+     *
+     * @param values The set of values to animate between.
+     */
+    public void setObjectValues(Object... values) {
+        if (values == null || values.length == 0) {
+            return;
+        }
+        if (mValues == null || mValues.length == 0) {
+            setValues(new PropertyValuesHolder[]{PropertyValuesHolder.ofObject("",
+                    (TypeEvaluator)null, values)});
+        } else {
+            PropertyValuesHolder valuesHolder = mValues[0];
+            valuesHolder.setObjectValues(values);
+        }
+        // New property/values/target should cause re-initialization prior to starting
+        mInitialized = false;
+    }
+
+    /**
+     * Sets the values, per property, being animated between. This function is called internally
+     * by the constructors of ValueAnimator that take a list of values. But an ValueAnimator can
+     * be constructed without values and this method can be called to set the values manually
+     * instead.
+     *
+     * @param values The set of values, per property, being animated between.
+     */
+    public void setValues(PropertyValuesHolder... values) {
+        int numValues = values.length;
+        mValues = values;
+        mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
+        for (int i = 0; i < numValues; ++i) {
+            PropertyValuesHolder valuesHolder = values[i];
+            mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
+        }
+        // New property/values/target should cause re-initialization prior to starting
+        mInitialized = false;
+    }
+
+    /**
+     * Returns the values that this ValueAnimator animates between. These values are stored in
+     * PropertyValuesHolder objects, even if the ValueAnimator was created with a simple list
+     * of value objects instead.
+     *
+     * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the
+     * values, per property, that define the animation.
+     */
+    public PropertyValuesHolder[] getValues() {
+        return mValues;
+    }
+
+    /**
+     * This function is called immediately before processing the first animation
+     * frame of an animation. If there is a nonzero <code>startDelay</code>, the
+     * function is called after that delay ends.
+     * It takes care of the final initialization steps for the
+     * animation.
+     *
+     *  <p>Overrides of this method should call the superclass method to ensure
+     *  that internal mechanisms for the animation are set up correctly.</p>
+     */
+    void initAnimation() {
+        if (!mInitialized) {
+            int numValues = mValues.length;
+            for (int i = 0; i < numValues; ++i) {
+                mValues[i].init();
+            }
+            mInitialized = true;
+        }
+    }
+
+
+    /**
+     * Sets the length of the animation. The default duration is 300 milliseconds.
+     *
+     * @param duration The length of the animation, in milliseconds. This value cannot
+     * be negative.
+     * @return ValueAnimator The object called with setDuration(). This return
+     * value makes it easier to compose statements together that construct and then set the
+     * duration, as in <code>ValueAnimator.ofInt(0, 10).setDuration(500).start()</code>.
+     */
+    public ValueAnimator setDuration(long duration) {
+        if (duration < 0) {
+            throw new IllegalArgumentException("Animators cannot have negative duration: " +
+                    duration);
+        }
+        mDuration = duration;
+        return this;
+    }
+
+    /**
+     * Gets the length of the animation. The default duration is 300 milliseconds.
+     *
+     * @return The length of the animation, in milliseconds.
+     */
+    public long getDuration() {
+        return mDuration;
+    }
+
+    /**
+     * Sets the position of the animation to the specified point in time. This time should
+     * be between 0 and the total duration of the animation, including any repetition. If
+     * the animation has not yet been started, then it will not advance forward after it is
+     * set to this time; it will simply set the time to this value and perform any appropriate
+     * actions based on that time. If the animation is already running, then setCurrentPlayTime()
+     * will set the current playing time to this value and continue playing from that point.
+     *
+     * @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
+     */
+    public void setCurrentPlayTime(long playTime) {
+        initAnimation();
+        long currentTime = AnimationUtils.currentAnimationTimeMillis();
+        if (mPlayingState != RUNNING) {
+            mSeekTime = playTime;
+            mPlayingState = SEEKED;
+        }
+        mStartTime = currentTime - playTime;
+        animationFrame(currentTime);
+    }
+
+    /**
+     * Gets the current position of the animation in time, which is equal to the current
+     * time minus the time that the animation started. An animation that is not yet started will
+     * return a value of zero.
+     *
+     * @return The current position in time of the animation.
+     */
+    public long getCurrentPlayTime() {
+        if (!mInitialized || mPlayingState == STOPPED) {
+            return 0;
+        }
+        return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
+    }
+
+    /**
+     * This custom, static handler handles the timing pulse that is shared by
+     * all active animations. This approach ensures that the setting of animation
+     * values will happen on the UI thread and that all animations will share
+     * the same times for calculating their values, which makes synchronizing
+     * animations possible.
+     *
+     */
+    private static class AnimationHandler extends Handler {
+        /**
+         * There are only two messages that we care about: ANIMATION_START and
+         * ANIMATION_FRAME. The START message is sent when an animation's start()
+         * method is called. It cannot start synchronously when start() is called
+         * because the call may be on the wrong thread, and it would also not be
+         * synchronized with other animations because it would not start on a common
+         * timing pulse. So each animation sends a START message to the handler, which
+         * causes the handler to place the animation on the active animations queue and
+         * start processing frames for that animation.
+         * The FRAME message is the one that is sent over and over while there are any
+         * active animations to process.
+         */
+        @Override
+        public void handleMessage(Message msg) {
+            boolean callAgain = true;
+            ArrayList<ValueAnimator> animations = sAnimations.get();
+            ArrayList<ValueAnimator> delayedAnims = sDelayedAnims.get();
+            switch (msg.what) {
+                // TODO: should we avoid sending frame message when starting if we
+                // were already running?
+                case ANIMATION_START:
+                    ArrayList<ValueAnimator> pendingAnimations = sPendingAnimations.get();
+                    if (animations.size() > 0 || delayedAnims.size() > 0) {
+                        callAgain = false;
+                    }
+                    // pendingAnims holds any animations that have requested to be started
+                    // We're going to clear sPendingAnimations, but starting animation may
+                    // cause more to be added to the pending list (for example, if one animation
+                    // starting triggers another starting). So we loop until sPendingAnimations
+                    // is empty.
+                    while (pendingAnimations.size() > 0) {
+                        ArrayList<ValueAnimator> pendingCopy =
+                                (ArrayList<ValueAnimator>) pendingAnimations.clone();
+                        pendingAnimations.clear();
+                        int count = pendingCopy.size();
+                        for (int i = 0; i < count; ++i) {
+                            ValueAnimator anim = pendingCopy.get(i);
+                            // If the animation has a startDelay, place it on the delayed list
+                            if (anim.mStartDelay == 0) {
+                                anim.startAnimation();
+                            } else {
+                                delayedAnims.add(anim);
+                            }
+                        }
+                    }
+                    // fall through to process first frame of new animations
+                case ANIMATION_FRAME:
+                    // currentTime holds the common time for all animations processed
+                    // during this frame
+                    long currentTime = AnimationUtils.currentAnimationTimeMillis();
+                    ArrayList<ValueAnimator> readyAnims = sReadyAnims.get();
+                    ArrayList<ValueAnimator> endingAnims = sEndingAnims.get();
+
+                    // First, process animations currently sitting on the delayed queue, adding
+                    // them to the active animations if they are ready
+                    int numDelayedAnims = delayedAnims.size();
+                    for (int i = 0; i < numDelayedAnims; ++i) {
+                        ValueAnimator anim = delayedAnims.get(i);
+                        if (anim.delayedAnimationFrame(currentTime)) {
+                            readyAnims.add(anim);
+                        }
+                    }
+                    int numReadyAnims = readyAnims.size();
+                    if (numReadyAnims > 0) {
+                        for (int i = 0; i < numReadyAnims; ++i) {
+                            ValueAnimator anim = readyAnims.get(i);
+                            anim.startAnimation();
+                            anim.mRunning = true;
+                            delayedAnims.remove(anim);
+                        }
+                        readyAnims.clear();
+                    }
+
+                    // Now process all active animations. The return value from animationFrame()
+                    // tells the handler whether it should now be ended
+                    int numAnims = animations.size();
+                    int i = 0;
+                    while (i < numAnims) {
+                        ValueAnimator anim = animations.get(i);
+                        if (anim.animationFrame(currentTime)) {
+                            endingAnims.add(anim);
+                        }
+                        if (animations.size() == numAnims) {
+                            ++i;
+                        } else {
+                            // An animation might be canceled or ended by client code
+                            // during the animation frame. Check to see if this happened by
+                            // seeing whether the current index is the same as it was before
+                            // calling animationFrame(). Another approach would be to copy
+                            // animations to a temporary list and process that list instead,
+                            // but that entails garbage and processing overhead that would
+                            // be nice to avoid.
+                            --numAnims;
+                            endingAnims.remove(anim);
+                        }
+                    }
+                    if (endingAnims.size() > 0) {
+                        for (i = 0; i < endingAnims.size(); ++i) {
+                            endingAnims.get(i).endAnimation();
+                        }
+                        endingAnims.clear();
+                    }
+
+                    // If there are still active or delayed animations, call the handler again
+                    // after the frameDelay
+                    if (callAgain && (!animations.isEmpty() || !delayedAnims.isEmpty())) {
+                        sendEmptyMessageDelayed(ANIMATION_FRAME, Math.max(0, sFrameDelay -
+                            (AnimationUtils.currentAnimationTimeMillis() - currentTime)));
+                    }
+                    break;
+            }
+        }
+    }
+
+    /**
+     * The amount of time, in milliseconds, to delay starting the animation after
+     * {@link #start()} is called.
+     *
+     * @return the number of milliseconds to delay running the animation
+     */
+    public long getStartDelay() {
+        return mStartDelay;
+    }
+
+    /**
+     * The amount of time, in milliseconds, to delay starting the animation after
+     * {@link #start()} is called.
+
+     * @param startDelay The amount of the delay, in milliseconds
+     */
+    public void setStartDelay(long startDelay) {
+        this.mStartDelay = startDelay;
+    }
+
+    /**
+     * The amount of time, in milliseconds, between each frame of the animation. This is a
+     * requested time that the animation will attempt to honor, but the actual delay between
+     * frames may be different, depending on system load and capabilities. This is a static
+     * function because the same delay will be applied to all animations, since they are all
+     * run off of a single timing loop.
+     *
+     * @return the requested time between frames, in milliseconds
+     */
+    public static long getFrameDelay() {
+        return sFrameDelay;
+    }
+
+    /**
+     * The amount of time, in milliseconds, between each frame of the animation. This is a
+     * requested time that the animation will attempt to honor, but the actual delay between
+     * frames may be different, depending on system load and capabilities. This is a static
+     * function because the same delay will be applied to all animations, since they are all
+     * run off of a single timing loop.
+     *
+     * @param frameDelay the requested time between frames, in milliseconds
+     */
+    public static void setFrameDelay(long frameDelay) {
+        sFrameDelay = frameDelay;
+    }
+
+    /**
+     * The most recent value calculated by this <code>ValueAnimator</code> when there is just one
+     * property being animated. This value is only sensible while the animation is running. The main
+     * purpose for this read-only property is to retrieve the value from the <code>ValueAnimator</code>
+     * during a call to {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
+     * is called during each animation frame, immediately after the value is calculated.
+     *
+     * @return animatedValue The value most recently calculated by this <code>ValueAnimator</code> for
+     * the single property being animated. If there are several properties being animated
+     * (specified by several PropertyValuesHolder objects in the constructor), this function
+     * returns the animated value for the first of those objects.
+     */
+    public Object getAnimatedValue() {
+        if (mValues != null && mValues.length > 0) {
+            return mValues[0].getAnimatedValue();
+        }
+        // Shouldn't get here; should always have values unless ValueAnimator was set up wrong
+        return null;
+    }
+
+    /**
+     * The most recent value calculated by this <code>ValueAnimator</code> for <code>propertyName</code>.
+     * The main purpose for this read-only property is to retrieve the value from the
+     * <code>ValueAnimator</code> during a call to
+     * {@link AnimatorUpdateListener#onAnimationUpdate(ValueAnimator)}, which
+     * is called during each animation frame, immediately after the value is calculated.
+     *
+     * @return animatedValue The value most recently calculated for the named property
+     * by this <code>ValueAnimator</code>.
+     */
+    public Object getAnimatedValue(String propertyName) {
+        PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName);
+        if (valuesHolder != null) {
+            return valuesHolder.getAnimatedValue();
+        } else {
+            // At least avoid crashing if called with bogus propertyName
+            return null;
+        }
+    }
+
+    /**
+     * Sets how many times the animation should be repeated. If the repeat
+     * count is 0, the animation is never repeated. If the repeat count is
+     * greater than 0 or {@link #INFINITE}, the repeat mode will be taken
+     * into account. The repeat count is 0 by default.
+     *
+     * @param value the number of times the animation should be repeated
+     */
+    public void setRepeatCount(int value) {
+        mRepeatCount = value;
+    }
+    /**
+     * Defines how many times the animation should repeat. The default value
+     * is 0.
+     *
+     * @return the number of times the animation should repeat, or {@link #INFINITE}
+     */
+    public int getRepeatCount() {
+        return mRepeatCount;
+    }
+
+    /**
+     * Defines what this animation should do when it reaches the end. This
+     * setting is applied only when the repeat count is either greater than
+     * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
+     *
+     * @param value {@link #RESTART} or {@link #REVERSE}
+     */
+    public void setRepeatMode(int value) {
+        mRepeatMode = value;
+    }
+
+    /**
+     * Defines what this animation should do when it reaches the end.
+     *
+     * @return either one of {@link #REVERSE} or {@link #RESTART}
+     */
+    public int getRepeatMode() {
+        return mRepeatMode;
+    }
+
+    /**
+     * Adds a listener to the set of listeners that are sent update events through the life of
+     * an animation. This method is called on all listeners for every frame of the animation,
+     * after the values for the animation have been calculated.
+     *
+     * @param listener the listener to be added to the current set of listeners for this animation.
+     */
+    public void addUpdateListener(AnimatorUpdateListener listener) {
+        if (mUpdateListeners == null) {
+            mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
+        }
+        mUpdateListeners.add(listener);
+    }
+
+    /**
+     * Removes all listeners from the set listening to frame updates for this animation.
+     */
+    public void removeAllUpdateListeners() {
+        if (mUpdateListeners == null) {
+            return;
+        }
+        mUpdateListeners.clear();
+        mUpdateListeners = null;
+    }
+
+    /**
+     * Removes a listener from the set listening to frame updates for this animation.
+     *
+     * @param listener the listener to be removed from the current set of update listeners
+     * for this animation.
+     */
+    public void removeUpdateListener(AnimatorUpdateListener listener) {
+        if (mUpdateListeners == null) {
+            return;
+        }
+        mUpdateListeners.remove(listener);
+        if (mUpdateListeners.size() == 0) {
+            mUpdateListeners = null;
+        }
+    }
+
+
+    /**
+     * The time interpolator used in calculating the elapsed fraction of this animation. The
+     * interpolator determines whether the animation runs with linear or non-linear motion,
+     * such as acceleration and deceleration. The default value is
+     * {@link android.view.animation.AccelerateDecelerateInterpolator}
+     *
+     * @param value the interpolator to be used by this animation. A value of <code>null</code>
+     * will result in linear interpolation.
+     */
+    @Override
+    public void setInterpolator(/*Time*/Interpolator value) {
+        if (value != null) {
+            mInterpolator = value;
+        } else {
+            mInterpolator = new LinearInterpolator();
+        }
+    }
+
+    /**
+     * Returns the timing interpolator that this ValueAnimator uses.
+     *
+     * @return The timing interpolator for this ValueAnimator.
+     */
+    public /*Time*/Interpolator getInterpolator() {
+        return mInterpolator;
+    }
+
+    /**
+     * The type evaluator to be used when calculating the animated values of this animation.
+     * The system will automatically assign a float or int evaluator based on the type
+     * of <code>startValue</code> and <code>endValue</code> in the constructor. But if these values
+     * are not one of these primitive types, or if different evaluation is desired (such as is
+     * necessary with int values that represent colors), a custom evaluator needs to be assigned.
+     * For example, when running an animation on color values, the {@link ArgbEvaluator}
+     * should be used to get correct RGB color interpolation.
+     *
+     * <p>If this ValueAnimator has only one set of values being animated between, this evaluator
+     * will be used for that set. If there are several sets of values being animated, which is
+     * the case if PropertyValuesHOlder objects were set on the ValueAnimator, then the evaluator
+     * is assigned just to the first PropertyValuesHolder object.</p>
+     *
+     * @param value the evaluator to be used this animation
+     */
+    public void setEvaluator(TypeEvaluator value) {
+        if (value != null && mValues != null && mValues.length > 0) {
+            mValues[0].setEvaluator(value);
+        }
+    }
+
+    /**
+     * Start the animation playing. This version of start() takes a boolean flag that indicates
+     * whether the animation should play in reverse. The flag is usually false, but may be set
+     * to true if called from the reverse() method.
+     *
+     * <p>The animation started by calling this method will be run on the thread that called
+     * this method. This thread should have a Looper on it (a runtime exception will be thrown if
+     * this is not the case). Also, if the animation will animate
+     * properties of objects in the view hierarchy, then the calling thread should be the UI
+     * thread for that view hierarchy.</p>
+     *
+     * @param playBackwards Whether the ValueAnimator should start playing in reverse.
+     */
+    private void start(boolean playBackwards) {
+        if (Looper.myLooper() == null) {
+            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
+        }
+        mPlayingBackwards = playBackwards;
+        mCurrentIteration = 0;
+        mPlayingState = STOPPED;
+        mStarted = true;
+        mStartedDelay = false;
+        sPendingAnimations.get().add(this);
+        if (mStartDelay == 0) {
+            // This sets the initial value of the animation, prior to actually starting it running
+            setCurrentPlayTime(getCurrentPlayTime());
+            mPlayingState = STOPPED;
+            mRunning = true;
+
+            if (mListeners != null) {
+                ArrayList<AnimatorListener> tmpListeners =
+                        (ArrayList<AnimatorListener>) mListeners.clone();
+                int numListeners = tmpListeners.size();
+                for (int i = 0; i < numListeners; ++i) {
+                    tmpListeners.get(i).onAnimationStart(this);
+                }
+            }
+        }
+        AnimationHandler animationHandler = sAnimationHandler.get();
+        if (animationHandler == null) {
+            animationHandler = new AnimationHandler();
+            sAnimationHandler.set(animationHandler);
+        }
+        animationHandler.sendEmptyMessage(ANIMATION_START);
+    }
+
+    @Override
+    public void start() {
+        start(false);
+    }
+
+    @Override
+    public void cancel() {
+        // Only cancel if the animation is actually running or has been started and is about
+        // to run
+        if (mPlayingState != STOPPED || sPendingAnimations.get().contains(this) ||
+                sDelayedAnims.get().contains(this)) {
+            // Only notify listeners if the animator has actually started
+            if (mRunning && mListeners != null) {
+                ArrayList<AnimatorListener> tmpListeners =
+                        (ArrayList<AnimatorListener>) mListeners.clone();
+                for (AnimatorListener listener : tmpListeners) {
+                    listener.onAnimationCancel(this);
+                }
+            }
+            endAnimation();
+        }
+    }
+
+    @Override
+    public void end() {
+        if (!sAnimations.get().contains(this) && !sPendingAnimations.get().contains(this)) {
+            // Special case if the animation has not yet started; get it ready for ending
+            mStartedDelay = false;
+            startAnimation();
+        } else if (!mInitialized) {
+            initAnimation();
+        }
+        // The final value set on the target varies, depending on whether the animation
+        // was supposed to repeat an odd number of times
+        if (mRepeatCount > 0 && (mRepeatCount & 0x01) == 1) {
+            animateValue(0f);
+        } else {
+            animateValue(1f);
+        }
+        endAnimation();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return (mPlayingState == RUNNING || mRunning);
+    }
+
+    @Override
+    public boolean isStarted() {
+        return mStarted;
+    }
+
+    /**
+     * Plays the ValueAnimator in reverse. If the animation is already running,
+     * it will stop itself and play backwards from the point reached when reverse was called.
+     * If the animation is not currently running, then it will start from the end and
+     * play backwards. This behavior is only set for the current animation; future playing
+     * of the animation will use the default behavior of playing forward.
+     */
+    public void reverse() {
+        mPlayingBackwards = !mPlayingBackwards;
+        if (mPlayingState == RUNNING) {
+            long currentTime = AnimationUtils.currentAnimationTimeMillis();
+            long currentPlayTime = currentTime - mStartTime;
+            long timeLeft = mDuration - currentPlayTime;
+            mStartTime = currentTime - timeLeft;
+        } else {
+            start(true);
+        }
+    }
+
+    /**
+     * Called internally to end an animation by removing it from the animations list. Must be
+     * called on the UI thread.
+     */
+    private void endAnimation() {
+        sAnimations.get().remove(this);
+        sPendingAnimations.get().remove(this);
+        sDelayedAnims.get().remove(this);
+        mPlayingState = STOPPED;
+        if (mRunning && mListeners != null) {
+            ArrayList<AnimatorListener> tmpListeners =
+                    (ArrayList<AnimatorListener>) mListeners.clone();
+            int numListeners = tmpListeners.size();
+            for (int i = 0; i < numListeners; ++i) {
+                tmpListeners.get(i).onAnimationEnd(this);
+            }
+        }
+        mRunning = false;
+        mStarted = false;
+    }
+
+    /**
+     * Called internally to start an animation by adding it to the active animations list. Must be
+     * called on the UI thread.
+     */
+    private void startAnimation() {
+        initAnimation();
+        sAnimations.get().add(this);
+        if (mStartDelay > 0 && mListeners != null) {
+            // Listeners were already notified in start() if startDelay is 0; this is
+            // just for delayed animations
+            ArrayList<AnimatorListener> tmpListeners =
+                    (ArrayList<AnimatorListener>) mListeners.clone();
+            int numListeners = tmpListeners.size();
+            for (int i = 0; i < numListeners; ++i) {
+                tmpListeners.get(i).onAnimationStart(this);
+            }
+        }
+    }
+
+    /**
+     * Internal function called to process an animation frame on an animation that is currently
+     * sleeping through its <code>startDelay</code> phase. The return value indicates whether it
+     * should be woken up and put on the active animations queue.
+     *
+     * @param currentTime The current animation time, used to calculate whether the animation
+     * has exceeded its <code>startDelay</code> and should be started.
+     * @return True if the animation's <code>startDelay</code> has been exceeded and the animation
+     * should be added to the set of active animations.
+     */
+    private boolean delayedAnimationFrame(long currentTime) {
+        if (!mStartedDelay) {
+            mStartedDelay = true;
+            mDelayStartTime = currentTime;
+        } else {
+            long deltaTime = currentTime - mDelayStartTime;
+            if (deltaTime > mStartDelay) {
+                // startDelay ended - start the anim and record the
+                // mStartTime appropriately
+                mStartTime = currentTime - (deltaTime - mStartDelay);
+                mPlayingState = RUNNING;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * This internal function processes a single animation frame for a given animation. The
+     * currentTime parameter is the timing pulse sent by the handler, used to calculate the
+     * elapsed duration, and therefore
+     * the elapsed fraction, of the animation. The return value indicates whether the animation
+     * should be ended (which happens when the elapsed time of the animation exceeds the
+     * animation's duration, including the repeatCount).
+     *
+     * @param currentTime The current time, as tracked by the static timing handler
+     * @return true if the animation's duration, including any repetitions due to
+     * <code>repeatCount</code> has been exceeded and the animation should be ended.
+     */
+    boolean animationFrame(long currentTime) {
+        boolean done = false;
+
+        if (mPlayingState == STOPPED) {
+            mPlayingState = RUNNING;
+            if (mSeekTime < 0) {
+                mStartTime = currentTime;
+            } else {
+                mStartTime = currentTime - mSeekTime;
+                // Now that we're playing, reset the seek time
+                mSeekTime = -1;
+            }
+        }
+        switch (mPlayingState) {
+        case RUNNING:
+        case SEEKED:
+            float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
+            if (fraction >= 1f) {
+                if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
+                    // Time to repeat
+                    if (mListeners != null) {
+                        int numListeners = mListeners.size();
+                        for (int i = 0; i < numListeners; ++i) {
+                            mListeners.get(i).onAnimationRepeat(this);
+                        }
+                    }
+                    if (mRepeatMode == REVERSE) {
+                        mPlayingBackwards = mPlayingBackwards ? false : true;
+                    }
+                    mCurrentIteration += (int)fraction;
+                    fraction = fraction % 1f;
+                    mStartTime += mDuration;
+                } else {
+                    done = true;
+                    fraction = Math.min(fraction, 1.0f);
+                }
+            }
+            if (mPlayingBackwards) {
+                fraction = 1f - fraction;
+            }
+            animateValue(fraction);
+            break;
+        }
+
+        return done;
+    }
+
+    /**
+     * Returns the current animation fraction, which is the elapsed/interpolated fraction used in
+     * the most recent frame update on the animation.
+     *
+     * @return Elapsed/interpolated fraction of the animation.
+     */
+    public float getAnimatedFraction() {
+        return mCurrentFraction;
+    }
+
+    /**
+     * This method is called with the elapsed fraction of the animation during every
+     * animation frame. This function turns the elapsed fraction into an interpolated fraction
+     * and then into an animated value (from the evaluator. The function is called mostly during
+     * animation updates, but it is also called when the <code>end()</code>
+     * function is called, to set the final value on the property.
+     *
+     * <p>Overrides of this method must call the superclass to perform the calculation
+     * of the animated value.</p>
+     *
+     * @param fraction The elapsed fraction of the animation.
+     */
+    void animateValue(float fraction) {
+        fraction = mInterpolator.getInterpolation(fraction);
+        mCurrentFraction = fraction;
+        int numValues = mValues.length;
+        for (int i = 0; i < numValues; ++i) {
+            mValues[i].calculateValue(fraction);
+        }
+        if (mUpdateListeners != null) {
+            int numListeners = mUpdateListeners.size();
+            for (int i = 0; i < numListeners; ++i) {
+                mUpdateListeners.get(i).onAnimationUpdate(this);
+            }
+        }
+    }
+
+    @Override
+    public ValueAnimator clone() {
+        final ValueAnimator anim = (ValueAnimator) super.clone();
+        if (mUpdateListeners != null) {
+            ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
+            anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>();
+            int numListeners = oldListeners.size();
+            for (int i = 0; i < numListeners; ++i) {
+                anim.mUpdateListeners.add(oldListeners.get(i));
+            }
+        }
+        anim.mSeekTime = -1;
+        anim.mPlayingBackwards = false;
+        anim.mCurrentIteration = 0;
+        anim.mInitialized = false;
+        anim.mPlayingState = STOPPED;
+        anim.mStartedDelay = false;
+        PropertyValuesHolder[] oldValues = mValues;
+        if (oldValues != null) {
+            int numValues = oldValues.length;
+            anim.mValues = new PropertyValuesHolder[numValues];
+            anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
+            for (int i = 0; i < numValues; ++i) {
+                PropertyValuesHolder newValuesHolder = oldValues[i].clone();
+                anim.mValues[i] = newValuesHolder;
+                anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder);
+            }
+        }
+        return anim;
+    }
+
+    /**
+     * Implementors of this interface can add themselves as update listeners
+     * to an <code>ValueAnimator</code> instance to receive callbacks on every animation
+     * frame, after the current frame's values have been calculated for that
+     * <code>ValueAnimator</code>.
+     */
+    public static interface AnimatorUpdateListener {
+        /**
+         * <p>Notifies the occurrence of another frame of the animation.</p>
+         *
+         * @param animation The animation which was repeated.
+         */
+        void onAnimationUpdate(ValueAnimator animation);
+
+    }
+
+    /**
+     * Return the number of animations currently running.
+     *
+     * Used by StrictMode internally to annotate violations.  Only
+     * called on the main thread.
+     *
+     * @hide
+     */
+    public static int getCurrentAnimationsCount() {
+        return sAnimations.get().size();
+    }
+
+    /**
+     * Clear all animations on this thread, without canceling or ending them.
+     * This should be used with caution.
+     *
+     * @hide
+     */
+    public static void clearAllAnimations() {
+        sAnimations.get().clear();
+        sPendingAnimations.get().clear();
+        sDelayedAnims.get().clear();
+    }
+
+    @Override
+    public String toString() {
+        String returnVal = "ValueAnimator@" + Integer.toHexString(hashCode());
+        if (mValues != null) {
+            for (int i = 0; i < mValues.length; ++i) {
+                returnVal += "\n    " + mValues[i].toString();
+            }
+        }
+        return returnVal;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/view/NineViewGroup.java
new file mode 100644 (file)
index 0000000..7b830b9
--- /dev/null
@@ -0,0 +1,79 @@
+package com.actionbarsherlock.internal.nineoldandroids.view;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+
+import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
+
+public abstract class NineViewGroup extends ViewGroup {
+    private final AnimatorProxy mProxy;
+
+    public NineViewGroup(Context context) {
+        super(context);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+    public NineViewGroup(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+    public NineViewGroup(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        if (mProxy != null) {
+            if (visibility == GONE) {
+                clearAnimation();
+            } else if (visibility == VISIBLE) {
+                setAnimation(mProxy);
+            }
+        }
+        super.setVisibility(visibility);
+    }
+
+    public float getAlpha() {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            return mProxy.getAlpha();
+        } else {
+            return super.getAlpha();
+        }
+    }
+    public void setAlpha(float alpha) {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            mProxy.setAlpha(alpha);
+        } else {
+            super.setAlpha(alpha);
+        }
+    }
+    public float getTranslationX() {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            return mProxy.getTranslationX();
+        } else {
+            return super.getTranslationX();
+        }
+    }
+    public void setTranslationX(float translationX) {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            mProxy.setTranslationX(translationX);
+        } else {
+            super.setTranslationX(translationX);
+        }
+    }
+    public float getTranslationY() {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            return mProxy.getTranslationY();
+        } else {
+            return super.getTranslationY();
+        }
+    }
+    public void setTranslationY(float translationY) {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            mProxy.setTranslationY(translationY);
+        } else {
+            super.setTranslationY(translationY);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/view/animation/AnimatorProxy.java
new file mode 100644 (file)
index 0000000..067d049
--- /dev/null
@@ -0,0 +1,212 @@
+package com.actionbarsherlock.internal.nineoldandroids.view.animation;
+
+import java.lang.ref.WeakReference;
+import java.util.WeakHashMap;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.os.Build;
+import android.util.FloatMath;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+public final class AnimatorProxy extends Animation {
+    public static final boolean NEEDS_PROXY = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
+
+    private static final WeakHashMap<View, AnimatorProxy> PROXIES =
+            new WeakHashMap<View, AnimatorProxy>();
+
+    public static AnimatorProxy wrap(View view) {
+        AnimatorProxy proxy = PROXIES.get(view);
+        if (proxy == null) {
+            proxy = new AnimatorProxy(view);
+            PROXIES.put(view, proxy);
+        }
+        return proxy;
+    }
+
+    private final WeakReference<View> mView;
+
+    private float mAlpha = 1;
+    private float mScaleX = 1;
+    private float mScaleY = 1;
+    private float mTranslationX;
+    private float mTranslationY;
+
+    private final RectF mBefore = new RectF();
+    private final RectF mAfter = new RectF();
+    private final Matrix mTempMatrix = new Matrix();
+
+    private AnimatorProxy(View view) {
+        setDuration(0); //perform transformation immediately
+        setFillAfter(true); //persist transformation beyond duration
+        view.setAnimation(this);
+        mView = new WeakReference<View>(view);
+    }
+
+    public float getAlpha() {
+        return mAlpha;
+    }
+    public void setAlpha(float alpha) {
+        if (mAlpha != alpha) {
+            mAlpha = alpha;
+            View view = mView.get();
+            if (view != null) {
+                view.invalidate();
+            }
+        }
+    }
+    public float getScaleX() {
+        return mScaleX;
+    }
+    public void setScaleX(float scaleX) {
+        if (mScaleX != scaleX) {
+            prepareForUpdate();
+            mScaleX = scaleX;
+            invalidateAfterUpdate();
+        }
+    }
+    public float getScaleY() {
+        return mScaleY;
+    }
+    public void setScaleY(float scaleY) {
+        if (mScaleY != scaleY) {
+            prepareForUpdate();
+            mScaleY = scaleY;
+            invalidateAfterUpdate();
+        }
+    }
+    public int getScrollX() {
+        View view = mView.get();
+        if (view == null) {
+            return 0;
+        }
+        return view.getScrollX();
+    }
+    public void setScrollX(int value) {
+        View view = mView.get();
+        if (view != null) {
+            view.scrollTo(value, view.getScrollY());
+        }
+    }
+    public int getScrollY() {
+        View view = mView.get();
+        if (view == null) {
+            return 0;
+        }
+        return view.getScrollY();
+    }
+    public void setScrollY(int value) {
+        View view = mView.get();
+        if (view != null) {
+            view.scrollTo(view.getScrollY(), value);
+        }
+    }
+
+    public float getTranslationX() {
+        return mTranslationX;
+    }
+    public void setTranslationX(float translationX) {
+        if (mTranslationX != translationX) {
+            prepareForUpdate();
+            mTranslationX = translationX;
+            invalidateAfterUpdate();
+        }
+    }
+    public float getTranslationY() {
+        return mTranslationY;
+    }
+    public void setTranslationY(float translationY) {
+        if (mTranslationY != translationY) {
+            prepareForUpdate();
+            mTranslationY = translationY;
+            invalidateAfterUpdate();
+        }
+    }
+
+    private void prepareForUpdate() {
+        View view = mView.get();
+        if (view != null) {
+            computeRect(mBefore, view);
+        }
+    }
+    private void invalidateAfterUpdate() {
+        View view = mView.get();
+        if (view == null) {
+            return;
+        }
+        View parent = (View)view.getParent();
+        if (parent == null) {
+            return;
+        }
+
+        view.setAnimation(this);
+
+        final RectF after = mAfter;
+        computeRect(after, view);
+        after.union(mBefore);
+
+        parent.invalidate(
+                (int) FloatMath.floor(after.left),
+                (int) FloatMath.floor(after.top),
+                (int) FloatMath.ceil(after.right),
+                (int) FloatMath.ceil(after.bottom));
+    }
+
+    private void computeRect(final RectF r, View view) {
+        // compute current rectangle according to matrix transformation
+        final float w = view.getWidth();
+        final float h = view.getHeight();
+
+        // use a rectangle at 0,0 to make sure we don't run into issues with scaling
+        r.set(0, 0, w, h);
+
+        final Matrix m = mTempMatrix;
+        m.reset();
+        transformMatrix(m, view);
+        mTempMatrix.mapRect(r);
+
+        r.offset(view.getLeft(), view.getTop());
+
+        // Straighten coords if rotations flipped them
+        if (r.right < r.left) {
+            final float f = r.right;
+            r.right = r.left;
+            r.left = f;
+        }
+        if (r.bottom < r.top) {
+            final float f = r.top;
+            r.top = r.bottom;
+            r.bottom = f;
+        }
+    }
+
+    private void transformMatrix(Matrix m, View view) {
+        final float w = view.getWidth();
+        final float h = view.getHeight();
+
+        final float sX = mScaleX;
+        final float sY = mScaleY;
+        if ((sX != 1.0f) || (sY != 1.0f)) {
+            final float deltaSX = ((sX * w) - w) / 2f;
+            final float deltaSY = ((sY * h) - h) / 2f;
+            m.postScale(sX, sY);
+            m.postTranslate(-deltaSX, -deltaSY);
+        }
+        m.postTranslate(mTranslationX, mTranslationY);
+    }
+
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        View view = mView.get();
+        if (view != null) {
+            t.setAlpha(mAlpha);
+            transformMatrix(t.getMatrix(), view);
+        }
+    }
+
+    @Override
+    public void reset() {
+        /* Do nothing. */
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineFrameLayout.java
new file mode 100644 (file)
index 0000000..2c428e9
--- /dev/null
@@ -0,0 +1,65 @@
+package com.actionbarsherlock.internal.nineoldandroids.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
+
+public class NineFrameLayout extends FrameLayout {
+    private final AnimatorProxy mProxy;
+
+    public NineFrameLayout(Context context) {
+        super(context);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+    public NineFrameLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+    public NineFrameLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        if (mProxy != null) {
+            if (visibility == GONE) {
+                clearAnimation();
+            } else if (visibility == VISIBLE) {
+                setAnimation(mProxy);
+            }
+        }
+        super.setVisibility(visibility);
+    }
+
+    public float getAlpha() {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            return mProxy.getAlpha();
+        } else {
+            return super.getAlpha();
+        }
+    }
+    public void setAlpha(float alpha) {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            mProxy.setAlpha(alpha);
+        } else {
+            super.setAlpha(alpha);
+        }
+    }
+    public float getTranslationY() {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            return mProxy.getTranslationY();
+        } else {
+            return super.getTranslationY();
+        }
+    }
+    public void setTranslationY(float translationY) {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            mProxy.setTranslationY(translationY);
+        } else {
+            super.setTranslationY(translationY);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineHorizontalScrollView.java
new file mode 100644 (file)
index 0000000..129b5aa
--- /dev/null
@@ -0,0 +1,41 @@
+package com.actionbarsherlock.internal.nineoldandroids.widget;
+
+import android.content.Context;
+import android.widget.HorizontalScrollView;
+import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
+
+public class NineHorizontalScrollView extends HorizontalScrollView {
+    private final AnimatorProxy mProxy;
+
+    public NineHorizontalScrollView(Context context) {
+        super(context);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        if (mProxy != null) {
+            if (visibility == GONE) {
+                clearAnimation();
+            } else if (visibility == VISIBLE) {
+                setAnimation(mProxy);
+            }
+        }
+        super.setVisibility(visibility);
+    }
+
+    public float getAlpha() {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            return mProxy.getAlpha();
+        } else {
+            return super.getAlpha();
+        }
+    }
+    public void setAlpha(float alpha) {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            mProxy.setAlpha(alpha);
+        } else {
+            super.setAlpha(alpha);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/nineoldandroids/widget/NineLinearLayout.java
new file mode 100644 (file)
index 0000000..a670b1f
--- /dev/null
@@ -0,0 +1,65 @@
+package com.actionbarsherlock.internal.nineoldandroids.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
+
+public class NineLinearLayout extends LinearLayout {
+    private final AnimatorProxy mProxy;
+
+    public NineLinearLayout(Context context) {
+        super(context);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+    public NineLinearLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+    public NineLinearLayout(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        if (mProxy != null) {
+            if (visibility == GONE) {
+                clearAnimation();
+            } else if (visibility == VISIBLE) {
+                setAnimation(mProxy);
+            }
+        }
+        super.setVisibility(visibility);
+    }
+
+    public float getAlpha() {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            return mProxy.getAlpha();
+        } else {
+            return super.getAlpha();
+        }
+    }
+    public void setAlpha(float alpha) {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            mProxy.setAlpha(alpha);
+        } else {
+            super.setAlpha(alpha);
+        }
+    }
+    public float getTranslationX() {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            return mProxy.getTranslationX();
+        } else {
+            return super.getTranslationX();
+        }
+    }
+    public void setTranslationX(float translationX) {
+        if (AnimatorProxy.NEEDS_PROXY) {
+            mProxy.setTranslationX(translationX);
+        } else {
+            super.setTranslationX(translationX);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/ActionProviderWrapper.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/ActionProviderWrapper.java
new file mode 100644 (file)
index 0000000..b136d50
--- /dev/null
@@ -0,0 +1,40 @@
+package com.actionbarsherlock.internal.view;
+
+import com.actionbarsherlock.internal.view.menu.SubMenuWrapper;
+import com.actionbarsherlock.view.ActionProvider;
+import android.view.View;
+
+public class ActionProviderWrapper extends android.view.ActionProvider {
+    private final ActionProvider mProvider;
+
+
+    public ActionProviderWrapper(ActionProvider provider) {
+        super(null/*TODO*/); //XXX this *should* be unused
+        mProvider = provider;
+    }
+
+
+    public ActionProvider unwrap() {
+        return mProvider;
+    }
+
+    @Override
+    public View onCreateActionView() {
+        return mProvider.onCreateActionView();
+    }
+
+    @Override
+    public boolean hasSubMenu() {
+        return mProvider.hasSubMenu();
+    }
+
+    @Override
+    public boolean onPerformDefaultAction() {
+        return mProvider.onPerformDefaultAction();
+    }
+
+    @Override
+    public void onPrepareSubMenu(android.view.SubMenu subMenu) {
+        mProvider.onPrepareSubMenu(new SubMenuWrapper(subMenu));
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/StandaloneActionMode.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/StandaloneActionMode.java
new file mode 100644 (file)
index 0000000..0a87bd3
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.actionbarsherlock.internal.view;
+
+import android.content.Context;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+
+import java.lang.ref.WeakReference;
+
+import com.actionbarsherlock.internal.view.menu.MenuBuilder;
+import com.actionbarsherlock.internal.view.menu.MenuPopupHelper;
+import com.actionbarsherlock.internal.view.menu.SubMenuBuilder;
+import com.actionbarsherlock.internal.widget.ActionBarContextView;
+import com.actionbarsherlock.view.ActionMode;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuInflater;
+import com.actionbarsherlock.view.MenuItem;
+
+public class StandaloneActionMode extends ActionMode implements MenuBuilder.Callback {
+    private Context mContext;
+    private ActionBarContextView mContextView;
+    private ActionMode.Callback mCallback;
+    private WeakReference<View> mCustomView;
+    private boolean mFinished;
+    private boolean mFocusable;
+
+    private MenuBuilder mMenu;
+
+    public StandaloneActionMode(Context context, ActionBarContextView view,
+            ActionMode.Callback callback, boolean isFocusable) {
+        mContext = context;
+        mContextView = view;
+        mCallback = callback;
+
+        mMenu = new MenuBuilder(context).setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        mMenu.setCallback(this);
+        mFocusable = isFocusable;
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        mContextView.setTitle(title);
+    }
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        mContextView.setSubtitle(subtitle);
+    }
+
+    @Override
+    public void setTitle(int resId) {
+        setTitle(mContext.getString(resId));
+    }
+
+    @Override
+    public void setSubtitle(int resId) {
+        setSubtitle(mContext.getString(resId));
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        mContextView.setCustomView(view);
+        mCustomView = view != null ? new WeakReference<View>(view) : null;
+    }
+
+    @Override
+    public void invalidate() {
+        mCallback.onPrepareActionMode(this, mMenu);
+    }
+
+    @Override
+    public void finish() {
+        if (mFinished) {
+            return;
+        }
+        mFinished = true;
+
+        mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+        mCallback.onDestroyActionMode(this);
+    }
+
+    @Override
+    public Menu getMenu() {
+        return mMenu;
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mContextView.getTitle();
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        return mContextView.getSubtitle();
+    }
+
+    @Override
+    public View getCustomView() {
+        return mCustomView != null ? mCustomView.get() : null;
+    }
+
+    @Override
+    public MenuInflater getMenuInflater() {
+        return new MenuInflater(mContext);
+    }
+
+    public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+        return mCallback.onActionItemClicked(this, item);
+    }
+
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+    }
+
+    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+        if (!subMenu.hasVisibleItems()) {
+            return true;
+        }
+
+        new MenuPopupHelper(mContext, subMenu).show();
+        return true;
+    }
+
+    public void onCloseSubMenu(SubMenuBuilder menu) {
+    }
+
+    public void onMenuModeChange(MenuBuilder menu) {
+        invalidate();
+        mContextView.showOverflowMenu();
+    }
+
+    public boolean isUiFocusable() {
+        return mFocusable;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/View_HasStateListenerSupport.java
new file mode 100644 (file)
index 0000000..7d45e81
--- /dev/null
@@ -0,0 +1,6 @@
+package com.actionbarsherlock.internal.view;
+
+public interface View_HasStateListenerSupport {
+    void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener);
+    void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener);
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/View_OnAttachStateChangeListener.java
new file mode 100644 (file)
index 0000000..3869d32
--- /dev/null
@@ -0,0 +1,8 @@
+package com.actionbarsherlock.internal.view;
+
+import android.view.View;
+
+public interface View_OnAttachStateChangeListener {
+    void onViewAttachedToWindow(View v);
+    void onViewDetachedFromWindow(View v);
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenu.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenu.java
new file mode 100644 (file)
index 0000000..0354ad1
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.view.KeyEvent;
+
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.SubMenu;
+
+/**
+ * @hide
+ */
+public class ActionMenu implements Menu {
+    private Context mContext;
+
+    private boolean mIsQwerty;
+
+    private ArrayList<ActionMenuItem> mItems;
+
+    public ActionMenu(Context context) {
+        mContext = context;
+        mItems = new ArrayList<ActionMenuItem>();
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public MenuItem add(CharSequence title) {
+        return add(0, 0, 0, title);
+    }
+
+    public MenuItem add(int titleRes) {
+        return add(0, 0, 0, titleRes);
+    }
+
+    public MenuItem add(int groupId, int itemId, int order, int titleRes) {
+        return add(groupId, itemId, order, mContext.getResources().getString(titleRes));
+    }
+
+    public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
+        ActionMenuItem item = new ActionMenuItem(getContext(),
+                groupId, itemId, 0, order, title);
+        mItems.add(order, item);
+        return item;
+    }
+
+    public int addIntentOptions(int groupId, int itemId, int order,
+            ComponentName caller, Intent[] specifics, Intent intent, int flags,
+            MenuItem[] outSpecificItems) {
+        PackageManager pm = mContext.getPackageManager();
+        final List<ResolveInfo> lri =
+                pm.queryIntentActivityOptions(caller, specifics, intent, 0);
+        final int N = lri != null ? lri.size() : 0;
+
+        if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
+            removeGroup(groupId);
+        }
+
+        for (int i=0; i<N; i++) {
+            final ResolveInfo ri = lri.get(i);
+            Intent rintent = new Intent(
+                ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
+            rintent.setComponent(new ComponentName(
+                    ri.activityInfo.applicationInfo.packageName,
+                    ri.activityInfo.name));
+            final MenuItem item = add(groupId, itemId, order, ri.loadLabel(pm))
+                    .setIcon(ri.loadIcon(pm))
+                    .setIntent(rintent);
+            if (outSpecificItems != null && ri.specificIndex >= 0) {
+                outSpecificItems[ri.specificIndex] = item;
+            }
+        }
+
+        return N;
+    }
+
+    public SubMenu addSubMenu(CharSequence title) {
+        // TODO Implement submenus
+        return null;
+    }
+
+    public SubMenu addSubMenu(int titleRes) {
+        // TODO Implement submenus
+        return null;
+    }
+
+    public SubMenu addSubMenu(int groupId, int itemId, int order,
+            CharSequence title) {
+        // TODO Implement submenus
+        return null;
+    }
+
+    public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
+        // TODO Implement submenus
+        return null;
+    }
+
+    public void clear() {
+        mItems.clear();
+    }
+
+    public void close() {
+    }
+
+    private int findItemIndex(int id) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+        for (int i = 0; i < itemCount; i++) {
+            if (items.get(i).getItemId() == id) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    public MenuItem findItem(int id) {
+        return mItems.get(findItemIndex(id));
+    }
+
+    public MenuItem getItem(int index) {
+        return mItems.get(index);
+    }
+
+    public boolean hasVisibleItems() {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+
+        for (int i = 0; i < itemCount; i++) {
+            if (items.get(i).isVisible()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) {
+        // TODO Make this smarter.
+        final boolean qwerty = mIsQwerty;
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+
+        for (int i = 0; i < itemCount; i++) {
+            ActionMenuItem item = items.get(i);
+            final char shortcut = qwerty ? item.getAlphabeticShortcut() :
+                    item.getNumericShortcut();
+            if (keyCode == shortcut) {
+                return item;
+            }
+        }
+        return null;
+    }
+
+    public boolean isShortcutKey(int keyCode, KeyEvent event) {
+        return findItemWithShortcut(keyCode, event) != null;
+    }
+
+    public boolean performIdentifierAction(int id, int flags) {
+        final int index = findItemIndex(id);
+        if (index < 0) {
+            return false;
+        }
+
+        return mItems.get(index).invoke();
+    }
+
+    public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
+        ActionMenuItem item = findItemWithShortcut(keyCode, event);
+        if (item == null) {
+            return false;
+        }
+
+        return item.invoke();
+    }
+
+    public void removeGroup(int groupId) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        int itemCount = items.size();
+        int i = 0;
+        while (i < itemCount) {
+            if (items.get(i).getGroupId() == groupId) {
+                items.remove(i);
+                itemCount--;
+            } else {
+                i++;
+            }
+        }
+    }
+
+    public void removeItem(int id) {
+        mItems.remove(findItemIndex(id));
+    }
+
+    public void setGroupCheckable(int group, boolean checkable,
+            boolean exclusive) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+
+        for (int i = 0; i < itemCount; i++) {
+            ActionMenuItem item = items.get(i);
+            if (item.getGroupId() == group) {
+                item.setCheckable(checkable);
+                item.setExclusiveCheckable(exclusive);
+            }
+        }
+    }
+
+    public void setGroupEnabled(int group, boolean enabled) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+
+        for (int i = 0; i < itemCount; i++) {
+            ActionMenuItem item = items.get(i);
+            if (item.getGroupId() == group) {
+                item.setEnabled(enabled);
+            }
+        }
+    }
+
+    public void setGroupVisible(int group, boolean visible) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+
+        for (int i = 0; i < itemCount; i++) {
+            ActionMenuItem item = items.get(i);
+            if (item.getGroupId() == group) {
+                item.setVisible(visible);
+            }
+        }
+    }
+
+    public void setQwertyMode(boolean isQwerty) {
+        mIsQwerty = isQwerty;
+    }
+
+    public int size() {
+        return mItems.size();
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuItem.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuItem.java
new file mode 100644 (file)
index 0000000..510b974
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View;
+
+import com.actionbarsherlock.view.ActionProvider;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.SubMenu;
+
+/**
+ * @hide
+ */
+public class ActionMenuItem implements MenuItem {
+    private final int mId;
+    private final int mGroup;
+    //UNUSED private final int mCategoryOrder;
+    private final int mOrdering;
+
+    private CharSequence mTitle;
+    private CharSequence mTitleCondensed;
+    private Intent mIntent;
+    private char mShortcutNumericChar;
+    private char mShortcutAlphabeticChar;
+
+    private Drawable mIconDrawable;
+    //UNUSED private int mIconResId = NO_ICON;
+
+    private Context mContext;
+
+    private MenuItem.OnMenuItemClickListener mClickListener;
+
+    //UNUSED private static final int NO_ICON = 0;
+
+    private int mFlags = ENABLED;
+    private static final int CHECKABLE      = 0x00000001;
+    private static final int CHECKED        = 0x00000002;
+    private static final int EXCLUSIVE      = 0x00000004;
+    private static final int HIDDEN         = 0x00000008;
+    private static final int ENABLED        = 0x00000010;
+
+    public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering,
+            CharSequence title) {
+        mContext = context;
+        mId = id;
+        mGroup = group;
+        //UNUSED mCategoryOrder = categoryOrder;
+        mOrdering = ordering;
+        mTitle = title;
+    }
+
+    public char getAlphabeticShortcut() {
+        return mShortcutAlphabeticChar;
+    }
+
+    public int getGroupId() {
+        return mGroup;
+    }
+
+    public Drawable getIcon() {
+        return mIconDrawable;
+    }
+
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    public int getItemId() {
+        return mId;
+    }
+
+    public ContextMenuInfo getMenuInfo() {
+        return null;
+    }
+
+    public char getNumericShortcut() {
+        return mShortcutNumericChar;
+    }
+
+    public int getOrder() {
+        return mOrdering;
+    }
+
+    public SubMenu getSubMenu() {
+        return null;
+    }
+
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    public CharSequence getTitleCondensed() {
+        return mTitleCondensed;
+    }
+
+    public boolean hasSubMenu() {
+        return false;
+    }
+
+    public boolean isCheckable() {
+        return (mFlags & CHECKABLE) != 0;
+    }
+
+    public boolean isChecked() {
+        return (mFlags & CHECKED) != 0;
+    }
+
+    public boolean isEnabled() {
+        return (mFlags & ENABLED) != 0;
+    }
+
+    public boolean isVisible() {
+        return (mFlags & HIDDEN) == 0;
+    }
+
+    public MenuItem setAlphabeticShortcut(char alphaChar) {
+        mShortcutAlphabeticChar = alphaChar;
+        return this;
+    }
+
+    public MenuItem setCheckable(boolean checkable) {
+        mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
+        return this;
+    }
+
+    public ActionMenuItem setExclusiveCheckable(boolean exclusive) {
+        mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
+        return this;
+    }
+
+    public MenuItem setChecked(boolean checked) {
+        mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
+        return this;
+    }
+
+    public MenuItem setEnabled(boolean enabled) {
+        mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);
+        return this;
+    }
+
+    public MenuItem setIcon(Drawable icon) {
+        mIconDrawable = icon;
+        //UNUSED mIconResId = NO_ICON;
+        return this;
+    }
+
+    public MenuItem setIcon(int iconRes) {
+        //UNUSED mIconResId = iconRes;
+        mIconDrawable = mContext.getResources().getDrawable(iconRes);
+        return this;
+    }
+
+    public MenuItem setIntent(Intent intent) {
+        mIntent = intent;
+        return this;
+    }
+
+    public MenuItem setNumericShortcut(char numericChar) {
+        mShortcutNumericChar = numericChar;
+        return this;
+    }
+
+    public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
+        mClickListener = menuItemClickListener;
+        return this;
+    }
+
+    public MenuItem setShortcut(char numericChar, char alphaChar) {
+        mShortcutNumericChar = numericChar;
+        mShortcutAlphabeticChar = alphaChar;
+        return this;
+    }
+
+    public MenuItem setTitle(CharSequence title) {
+        mTitle = title;
+        return this;
+    }
+
+    public MenuItem setTitle(int title) {
+        mTitle = mContext.getResources().getString(title);
+        return this;
+    }
+
+    public MenuItem setTitleCondensed(CharSequence title) {
+        mTitleCondensed = title;
+        return this;
+    }
+
+    public MenuItem setVisible(boolean visible) {
+        mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN);
+        return this;
+    }
+
+    public boolean invoke() {
+        if (mClickListener != null && mClickListener.onMenuItemClick(this)) {
+            return true;
+        }
+
+        if (mIntent != null) {
+            mContext.startActivity(mIntent);
+            return true;
+        }
+
+        return false;
+    }
+
+    public void setShowAsAction(int show) {
+        // Do nothing. ActionMenuItems always show as action buttons.
+    }
+
+    public MenuItem setActionView(View actionView) {
+        throw new UnsupportedOperationException();
+    }
+
+    public View getActionView() {
+        return null;
+    }
+
+    @Override
+    public MenuItem setActionView(int resId) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ActionProvider getActionProvider() {
+        return null;
+    }
+
+    @Override
+    public MenuItem setActionProvider(ActionProvider actionProvider) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public MenuItem setShowAsActionFlags(int actionEnum) {
+        setShowAsAction(actionEnum);
+        return this;
+    }
+
+    @Override
+    public boolean expandActionView() {
+        return false;
+    }
+
+    @Override
+    public boolean collapseActionView() {
+        return false;
+    }
+
+    @Override
+    public boolean isActionViewExpanded() {
+        return false;
+    }
+
+    @Override
+    public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
+        // No need to save the listener; ActionMenuItem does not support collapsing items.
+        return this;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuItemView.java
new file mode 100644 (file)
index 0000000..dcb50f3
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import java.util.HashSet;
+import java.util.Set;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.Toast;
+
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
+import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
+import com.actionbarsherlock.internal.widget.CapitalizingButton;
+
+import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
+
+/**
+ * @hide
+ */
+public class ActionMenuItemView extends LinearLayout
+        implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener,
+        ActionMenuView.ActionMenuChildView, View_HasStateListenerSupport {
+    //UNUSED private static final String TAG = "ActionMenuItemView";
+
+    private MenuItemImpl mItemData;
+    private CharSequence mTitle;
+    private MenuBuilder.ItemInvoker mItemInvoker;
+
+    private ImageButton mImageButton;
+    private CapitalizingButton mTextButton;
+    private boolean mAllowTextWithIcon;
+    private boolean mExpandedFormat;
+    private int mMinWidth;
+
+    private final Set<View_OnAttachStateChangeListener> mListeners = new HashSet<View_OnAttachStateChangeListener>();
+
+    public ActionMenuItemView(Context context) {
+        this(context, null);
+    }
+
+    public ActionMenuItemView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) {
+        //TODO super(context, attrs, defStyle);
+        super(context, attrs);
+        mAllowTextWithIcon = getResources_getBoolean(context,
+                R.bool.abs__config_allowActionMenuItemTextWithIcon);
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.SherlockActionMenuItemView, 0, 0);
+        mMinWidth = a.getDimensionPixelSize(
+                R.styleable.SherlockActionMenuItemView_android_minWidth, 0);
+        a.recycle();
+    }
+
+    @Override
+    public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
+        mListeners.add(listener);
+    }
+
+    @Override
+    public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
+        mListeners.remove(listener);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        for (View_OnAttachStateChangeListener listener : mListeners) {
+            listener.onViewAttachedToWindow(this);
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        for (View_OnAttachStateChangeListener listener : mListeners) {
+            listener.onViewDetachedFromWindow(this);
+        }
+    }
+
+    @Override
+    public void onFinishInflate() {
+
+        mImageButton = (ImageButton) findViewById(R.id.abs__imageButton);
+        mTextButton = (CapitalizingButton) findViewById(R.id.abs__textButton);
+        mImageButton.setOnClickListener(this);
+        mTextButton.setOnClickListener(this);
+        mImageButton.setOnLongClickListener(this);
+        setOnClickListener(this);
+        setOnLongClickListener(this);
+    }
+
+    public MenuItemImpl getItemData() {
+        return mItemData;
+    }
+
+    public void initialize(MenuItemImpl itemData, int menuType) {
+        mItemData = itemData;
+
+        setIcon(itemData.getIcon());
+        setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon
+        setId(itemData.getItemId());
+
+        setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
+        setEnabled(itemData.isEnabled());
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        mImageButton.setEnabled(enabled);
+        mTextButton.setEnabled(enabled);
+    }
+
+    public void onClick(View v) {
+        if (mItemInvoker != null) {
+            mItemInvoker.invokeItem(mItemData);
+        }
+    }
+
+    public void setItemInvoker(MenuBuilder.ItemInvoker invoker) {
+        mItemInvoker = invoker;
+    }
+
+    public boolean prefersCondensedTitle() {
+        return true;
+    }
+
+    public void setCheckable(boolean checkable) {
+        // TODO Support checkable action items
+    }
+
+    public void setChecked(boolean checked) {
+        // TODO Support checkable action items
+    }
+
+    public void setExpandedFormat(boolean expandedFormat) {
+        if (mExpandedFormat != expandedFormat) {
+            mExpandedFormat = expandedFormat;
+            if (mItemData != null) {
+                mItemData.actionFormatChanged();
+            }
+        }
+    }
+
+    private void updateTextButtonVisibility() {
+        boolean visible = !TextUtils.isEmpty(mTextButton.getText());
+        visible &= mImageButton.getDrawable() == null ||
+                (mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat));
+
+        mTextButton.setVisibility(visible ? VISIBLE : GONE);
+    }
+
+    public void setIcon(Drawable icon) {
+        mImageButton.setImageDrawable(icon);
+        if (icon != null) {
+            mImageButton.setVisibility(VISIBLE);
+        } else {
+            mImageButton.setVisibility(GONE);
+        }
+
+        updateTextButtonVisibility();
+    }
+
+    public boolean hasText() {
+        return mTextButton.getVisibility() != GONE;
+    }
+
+    public void setShortcut(boolean showShortcut, char shortcutKey) {
+        // Action buttons don't show text for shortcut keys.
+    }
+
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+
+        mTextButton.setTextCompat(mTitle);
+
+        setContentDescription(mTitle);
+        updateTextButtonVisibility();
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        onPopulateAccessibilityEvent(event);
+        return true;
+    }
+
+    @Override
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            super.onPopulateAccessibilityEvent(event);
+        }
+        final CharSequence cdesc = getContentDescription();
+        if (!TextUtils.isEmpty(cdesc)) {
+            event.getText().add(cdesc);
+        }
+    }
+
+    @Override
+    public boolean dispatchHoverEvent(MotionEvent event) {
+        // Don't allow children to hover; we want this to be treated as a single component.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            return onHoverEvent(event);
+        }
+        return false;
+    }
+
+    public boolean showsIcon() {
+        return true;
+    }
+
+    public boolean needsDividerBefore() {
+        return hasText() && mItemData.getIcon() == null;
+    }
+
+    public boolean needsDividerAfter() {
+        return hasText();
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        if (hasText()) {
+            // Don't show the cheat sheet for items that already show text.
+            return false;
+        }
+
+        final int[] screenPos = new int[2];
+        final Rect displayFrame = new Rect();
+        getLocationOnScreen(screenPos);
+        getWindowVisibleDisplayFrame(displayFrame);
+
+        final Context context = getContext();
+        final int width = getWidth();
+        final int height = getHeight();
+        final int midy = screenPos[1] + height / 2;
+        final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
+
+        Toast cheatSheet = Toast.makeText(context, mItemData.getTitle(), Toast.LENGTH_SHORT);
+        if (midy < displayFrame.height()) {
+            // Show along the top; follow action buttons
+            cheatSheet.setGravity(Gravity.TOP | Gravity.RIGHT,
+                    screenWidth - screenPos[0] - width / 2, height);
+        } else {
+            // Show along the bottom center
+            cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
+        }
+        cheatSheet.show();
+        return true;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        final int specSize = MeasureSpec.getSize(widthMeasureSpec);
+        final int oldMeasuredWidth = getMeasuredWidth();
+        final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, mMinWidth)
+                : mMinWidth;
+
+        if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) {
+            // Remeasure at exactly the minimum width.
+            super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
+                    heightMeasureSpec);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuPresenter.java
new file mode 100644 (file)
index 0000000..6f568c6
--- /dev/null
@@ -0,0 +1,721 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getInteger;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseBooleanArray;
+import android.view.SoundEffectConstants;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
+import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
+import com.actionbarsherlock.internal.view.menu.ActionMenuView.ActionMenuChildView;
+import com.actionbarsherlock.view.ActionProvider;
+import com.actionbarsherlock.view.MenuItem;
+
+/**
+ * MenuPresenter for building action menus as seen in the action bar and action modes.
+ */
+public class ActionMenuPresenter extends BaseMenuPresenter
+        implements ActionProvider.SubUiVisibilityListener {
+    //UNUSED private static final String TAG = "ActionMenuPresenter";
+
+    private View mOverflowButton;
+    private boolean mReserveOverflow;
+    private boolean mReserveOverflowSet;
+    private int mWidthLimit;
+    private int mActionItemWidthLimit;
+    private int mMaxItems;
+    private boolean mMaxItemsSet;
+    private boolean mStrictWidthLimit;
+    private boolean mWidthLimitSet;
+    private boolean mExpandedActionViewsExclusive;
+
+    private int mMinCellSize;
+
+    // Group IDs that have been added as actions - used temporarily, allocated here for reuse.
+    private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
+
+    private View mScrapActionButtonView;
+
+    private OverflowPopup mOverflowPopup;
+    private ActionButtonSubmenu mActionButtonPopup;
+
+    private OpenOverflowRunnable mPostedOpenRunnable;
+
+    final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
+    int mOpenSubMenuId;
+
+    public ActionMenuPresenter(Context context) {
+        super(context, R.layout.abs__action_menu_layout,
+                R.layout.abs__action_menu_item_layout);
+    }
+
+    @Override
+    public void initForMenu(Context context, MenuBuilder menu) {
+        super.initForMenu(context, menu);
+
+        final Resources res = context.getResources();
+
+        if (!mReserveOverflowSet) {
+            mReserveOverflow = reserveOverflow(mContext);
+        }
+
+        if (!mWidthLimitSet) {
+            mWidthLimit = res.getDisplayMetrics().widthPixels / 2;
+        }
+
+        // Measure for initial configuration
+        if (!mMaxItemsSet) {
+            mMaxItems = getResources_getInteger(context, R.integer.abs__max_action_buttons);
+        }
+
+        int width = mWidthLimit;
+        if (mReserveOverflow) {
+            if (mOverflowButton == null) {
+                mOverflowButton = new OverflowMenuButton(mSystemContext);
+                final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+                mOverflowButton.measure(spec, spec);
+            }
+            width -= mOverflowButton.getMeasuredWidth();
+        } else {
+            mOverflowButton = null;
+        }
+
+        mActionItemWidthLimit = width;
+
+        mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density);
+
+        // Drop a scrap view as it may no longer reflect the proper context/config.
+        mScrapActionButtonView = null;
+    }
+
+    public static boolean reserveOverflow(Context context) {
+        //Check for theme-forced overflow action item
+        TypedArray a = context.getTheme().obtainStyledAttributes(R.styleable.SherlockTheme);
+        boolean result = a.getBoolean(R.styleable.SherlockTheme_absForceOverflow, false);
+        a.recycle();
+        if (result) {
+            return true;
+        }
+
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB);
+        } else {
+            return !HasPermanentMenuKey.get(context);
+        }
+    }
+
+    private static class HasPermanentMenuKey {
+        public static boolean get(Context context) {
+            return ViewConfiguration.get(context).hasPermanentMenuKey();
+        }
+    }
+
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (!mMaxItemsSet) {
+            mMaxItems = getResources_getInteger(mContext,
+                    R.integer.abs__max_action_buttons);
+            if (mMenu != null) {
+                mMenu.onItemsChanged(true);
+            }
+        }
+    }
+
+    public void setWidthLimit(int width, boolean strict) {
+        mWidthLimit = width;
+        mStrictWidthLimit = strict;
+        mWidthLimitSet = true;
+    }
+
+    public void setReserveOverflow(boolean reserveOverflow) {
+        mReserveOverflow = reserveOverflow;
+        mReserveOverflowSet = true;
+    }
+
+    public void setItemLimit(int itemCount) {
+        mMaxItems = itemCount;
+        mMaxItemsSet = true;
+    }
+
+    public void setExpandedActionViewsExclusive(boolean isExclusive) {
+        mExpandedActionViewsExclusive = isExclusive;
+    }
+
+    @Override
+    public MenuView getMenuView(ViewGroup root) {
+        MenuView result = super.getMenuView(root);
+        ((ActionMenuView) result).setPresenter(this);
+        return result;
+    }
+
+    @Override
+    public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
+        View actionView = item.getActionView();
+        if (actionView == null || item.hasCollapsibleActionView()) {
+            if (!(convertView instanceof ActionMenuItemView)) {
+                convertView = null;
+            }
+            actionView = super.getItemView(item, convertView, parent);
+        }
+        actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
+
+        final ActionMenuView menuParent = (ActionMenuView) parent;
+        final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
+        if (!menuParent.checkLayoutParams(lp)) {
+            actionView.setLayoutParams(menuParent.generateLayoutParams(lp));
+        }
+        return actionView;
+    }
+
+    @Override
+    public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) {
+        itemView.initialize(item, 0);
+
+        final ActionMenuView menuView = (ActionMenuView) mMenuView;
+        ActionMenuItemView actionItemView = (ActionMenuItemView) itemView;
+        actionItemView.setItemInvoker(menuView);
+    }
+
+    @Override
+    public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
+        return item.isActionButton();
+    }
+
+    @Override
+    public void updateMenuView(boolean cleared) {
+        super.updateMenuView(cleared);
+
+        if (mMenu != null) {
+            final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems();
+            final int count = actionItems.size();
+            for (int i = 0; i < count; i++) {
+                final ActionProvider provider = actionItems.get(i).getActionProvider();
+                if (provider != null) {
+                    provider.setSubUiVisibilityListener(this);
+                }
+            }
+        }
+
+        final ArrayList<MenuItemImpl> nonActionItems = mMenu != null ?
+                mMenu.getNonActionItems() : null;
+
+        boolean hasOverflow = false;
+        if (mReserveOverflow && nonActionItems != null) {
+            final int count = nonActionItems.size();
+            if (count == 1) {
+                hasOverflow = !nonActionItems.get(0).isActionViewExpanded();
+            } else {
+                hasOverflow = count > 0;
+            }
+        }
+
+        if (hasOverflow) {
+            if (mOverflowButton == null) {
+                mOverflowButton = new OverflowMenuButton(mSystemContext);
+            }
+            ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
+            if (parent != mMenuView) {
+                if (parent != null) {
+                    parent.removeView(mOverflowButton);
+                }
+                ActionMenuView menuView = (ActionMenuView) mMenuView;
+                menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams());
+            }
+        } else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) {
+            ((ViewGroup) mMenuView).removeView(mOverflowButton);
+        }
+
+        ((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow);
+    }
+
+    @Override
+    public boolean filterLeftoverView(ViewGroup parent, int childIndex) {
+        if (parent.getChildAt(childIndex) == mOverflowButton) return false;
+        return super.filterLeftoverView(parent, childIndex);
+    }
+
+    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+        if (!subMenu.hasVisibleItems()) return false;
+
+        SubMenuBuilder topSubMenu = subMenu;
+        while (topSubMenu.getParentMenu() != mMenu) {
+            topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu();
+        }
+        View anchor = findViewForItem(topSubMenu.getItem());
+        if (anchor == null) {
+            if (mOverflowButton == null) return false;
+            anchor = mOverflowButton;
+        }
+
+        mOpenSubMenuId = subMenu.getItem().getItemId();
+        mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
+        mActionButtonPopup.setAnchorView(anchor);
+        mActionButtonPopup.show();
+        super.onSubMenuSelected(subMenu);
+        return true;
+    }
+
+    private View findViewForItem(MenuItem item) {
+        final ViewGroup parent = (ViewGroup) mMenuView;
+        if (parent == null) return null;
+
+        final int count = parent.getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = parent.getChildAt(i);
+            if (child instanceof MenuView.ItemView &&
+                    ((MenuView.ItemView) child).getItemData() == item) {
+                return child;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Display the overflow menu if one is present.
+     * @return true if the overflow menu was shown, false otherwise.
+     */
+    public boolean showOverflowMenu() {
+        if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
+                mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) {
+            OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
+            mPostedOpenRunnable = new OpenOverflowRunnable(popup);
+            // Post this for later; we might still need a layout for the anchor to be right.
+            ((View) mMenuView).post(mPostedOpenRunnable);
+
+            // ActionMenuPresenter uses null as a callback argument here
+            // to indicate overflow is opening.
+            super.onSubMenuSelected(null);
+
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Hide the overflow menu if it is currently showing.
+     *
+     * @return true if the overflow menu was hidden, false otherwise.
+     */
+    public boolean hideOverflowMenu() {
+        if (mPostedOpenRunnable != null && mMenuView != null) {
+            ((View) mMenuView).removeCallbacks(mPostedOpenRunnable);
+            mPostedOpenRunnable = null;
+            return true;
+        }
+
+        MenuPopupHelper popup = mOverflowPopup;
+        if (popup != null) {
+            popup.dismiss();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Dismiss all popup menus - overflow and submenus.
+     * @return true if popups were dismissed, false otherwise. (This can be because none were open.)
+     */
+    public boolean dismissPopupMenus() {
+        boolean result = hideOverflowMenu();
+        result |= hideSubMenus();
+        return result;
+    }
+
+    /**
+     * Dismiss all submenu popups.
+     *
+     * @return true if popups were dismissed, false otherwise. (This can be because none were open.)
+     */
+    public boolean hideSubMenus() {
+        if (mActionButtonPopup != null) {
+            mActionButtonPopup.dismiss();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * @return true if the overflow menu is currently showing
+     */
+    public boolean isOverflowMenuShowing() {
+        return mOverflowPopup != null && mOverflowPopup.isShowing();
+    }
+
+    /**
+     * @return true if space has been reserved in the action menu for an overflow item.
+     */
+    public boolean isOverflowReserved() {
+        return mReserveOverflow;
+    }
+
+    public boolean flagActionItems() {
+        final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
+        final int itemsSize = visibleItems.size();
+        int maxActions = mMaxItems;
+        int widthLimit = mActionItemWidthLimit;
+        final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final ViewGroup parent = (ViewGroup) mMenuView;
+
+        int requiredItems = 0;
+        int requestedItems = 0;
+        int firstActionWidth = 0;
+        boolean hasOverflow = false;
+        for (int i = 0; i < itemsSize; i++) {
+            MenuItemImpl item = visibleItems.get(i);
+            if (item.requiresActionButton()) {
+                requiredItems++;
+            } else if (item.requestsActionButton()) {
+                requestedItems++;
+            } else {
+                hasOverflow = true;
+            }
+            if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) {
+                // Overflow everything if we have an expanded action view and we're
+                // space constrained.
+                maxActions = 0;
+            }
+        }
+
+        // Reserve a spot for the overflow item if needed.
+        if (mReserveOverflow &&
+                (hasOverflow || requiredItems + requestedItems > maxActions)) {
+            maxActions--;
+        }
+        maxActions -= requiredItems;
+
+        final SparseBooleanArray seenGroups = mActionButtonGroups;
+        seenGroups.clear();
+
+        int cellSize = 0;
+        int cellsRemaining = 0;
+        if (mStrictWidthLimit) {
+            cellsRemaining = widthLimit / mMinCellSize;
+            final int cellSizeRemaining = widthLimit % mMinCellSize;
+            cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining;
+        }
+
+        // Flag as many more requested items as will fit.
+        for (int i = 0; i < itemsSize; i++) {
+            MenuItemImpl item = visibleItems.get(i);
+
+            if (item.requiresActionButton()) {
+                View v = getItemView(item, mScrapActionButtonView, parent);
+                if (mScrapActionButtonView == null) {
+                    mScrapActionButtonView = v;
+                }
+                if (mStrictWidthLimit) {
+                    cellsRemaining -= ActionMenuView.measureChildForCells(v,
+                            cellSize, cellsRemaining, querySpec, 0);
+                } else {
+                    v.measure(querySpec, querySpec);
+                }
+                final int measuredWidth = v.getMeasuredWidth();
+                widthLimit -= measuredWidth;
+                if (firstActionWidth == 0) {
+                    firstActionWidth = measuredWidth;
+                }
+                final int groupId = item.getGroupId();
+                if (groupId != 0) {
+                    seenGroups.put(groupId, true);
+                }
+                item.setIsActionButton(true);
+            } else if (item.requestsActionButton()) {
+                // Items in a group with other items that already have an action slot
+                // can break the max actions rule, but not the width limit.
+                final int groupId = item.getGroupId();
+                final boolean inGroup = seenGroups.get(groupId);
+                boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0 &&
+                        (!mStrictWidthLimit || cellsRemaining > 0);
+
+                if (isAction) {
+                    View v = getItemView(item, mScrapActionButtonView, parent);
+                    if (mScrapActionButtonView == null) {
+                        mScrapActionButtonView = v;
+                    }
+                    if (mStrictWidthLimit) {
+                        final int cells = ActionMenuView.measureChildForCells(v,
+                                cellSize, cellsRemaining, querySpec, 0);
+                        cellsRemaining -= cells;
+                        if (cells == 0) {
+                            isAction = false;
+                        }
+                    } else {
+                        v.measure(querySpec, querySpec);
+                    }
+                    final int measuredWidth = v.getMeasuredWidth();
+                    widthLimit -= measuredWidth;
+                    if (firstActionWidth == 0) {
+                        firstActionWidth = measuredWidth;
+                    }
+
+                    if (mStrictWidthLimit) {
+                        isAction &= widthLimit >= 0;
+                    } else {
+                        // Did this push the entire first item past the limit?
+                        isAction &= widthLimit + firstActionWidth > 0;
+                    }
+                }
+
+                if (isAction && groupId != 0) {
+                    seenGroups.put(groupId, true);
+                } else if (inGroup) {
+                    // We broke the width limit. Demote the whole group, they all overflow now.
+                    seenGroups.put(groupId, false);
+                    for (int j = 0; j < i; j++) {
+                        MenuItemImpl areYouMyGroupie = visibleItems.get(j);
+                        if (areYouMyGroupie.getGroupId() == groupId) {
+                            // Give back the action slot
+                            if (areYouMyGroupie.isActionButton()) maxActions++;
+                            areYouMyGroupie.setIsActionButton(false);
+                        }
+                    }
+                }
+
+                if (isAction) maxActions--;
+
+                item.setIsActionButton(isAction);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        dismissPopupMenus();
+        super.onCloseMenu(menu, allMenusAreClosing);
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        SavedState state = new SavedState();
+        state.openSubMenuId = mOpenSubMenuId;
+        return state;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        SavedState saved = (SavedState) state;
+        if (saved.openSubMenuId > 0) {
+            MenuItem item = mMenu.findItem(saved.openSubMenuId);
+            if (item != null) {
+                SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+                onSubMenuSelected(subMenu);
+            }
+        }
+    }
+
+    @Override
+    public void onSubUiVisibilityChanged(boolean isVisible) {
+        if (isVisible) {
+            // Not a submenu, but treat it like one.
+            super.onSubMenuSelected(null);
+        } else {
+            mMenu.close(false);
+        }
+    }
+
+    private static class SavedState implements Parcelable {
+        public int openSubMenuId;
+
+        SavedState() {
+        }
+
+        SavedState(Parcel in) {
+            openSubMenuId = in.readInt();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(openSubMenuId);
+        }
+
+        @SuppressWarnings("unused")
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    private class OverflowMenuButton extends ImageButton implements ActionMenuChildView, View_HasStateListenerSupport {
+        private final Set<View_OnAttachStateChangeListener> mListeners = new HashSet<View_OnAttachStateChangeListener>();
+
+        public OverflowMenuButton(Context context) {
+            super(context, null, R.attr.actionOverflowButtonStyle);
+
+            setClickable(true);
+            setFocusable(true);
+            setVisibility(VISIBLE);
+            setEnabled(true);
+        }
+
+        @Override
+        public boolean performClick() {
+            if (super.performClick()) {
+                return true;
+            }
+
+            playSoundEffect(SoundEffectConstants.CLICK);
+            showOverflowMenu();
+            return true;
+        }
+
+        public boolean needsDividerBefore() {
+            return false;
+        }
+
+        public boolean needsDividerAfter() {
+            return false;
+        }
+
+        @Override
+        protected void onAttachedToWindow() {
+            super.onAttachedToWindow();
+            for (View_OnAttachStateChangeListener listener : mListeners) {
+                listener.onViewAttachedToWindow(this);
+            }
+        }
+
+        @Override
+        protected void onDetachedFromWindow() {
+            super.onDetachedFromWindow();
+            for (View_OnAttachStateChangeListener listener : mListeners) {
+                listener.onViewDetachedFromWindow(this);
+            }
+        }
+
+        @Override
+        public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
+            mListeners.add(listener);
+        }
+
+        @Override
+        public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
+            mListeners.remove(listener);
+        }
+    }
+
+    private class OverflowPopup extends MenuPopupHelper {
+        public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
+                boolean overflowOnly) {
+            super(context, menu, anchorView, overflowOnly);
+            setCallback(mPopupPresenterCallback);
+        }
+
+        @Override
+        public void onDismiss() {
+            super.onDismiss();
+            mMenu.close();
+            mOverflowPopup = null;
+        }
+    }
+
+    private class ActionButtonSubmenu extends MenuPopupHelper {
+        //UNUSED private SubMenuBuilder mSubMenu;
+
+        public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
+            super(context, subMenu);
+            //UNUSED mSubMenu = subMenu;
+
+            MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
+            if (!item.isActionButton()) {
+                // Give a reasonable anchor to nested submenus.
+                setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
+            }
+
+            setCallback(mPopupPresenterCallback);
+
+            boolean preserveIconSpacing = false;
+            final int count = subMenu.size();
+            for (int i = 0; i < count; i++) {
+                MenuItem childItem = subMenu.getItem(i);
+                if (childItem.isVisible() && childItem.getIcon() != null) {
+                    preserveIconSpacing = true;
+                    break;
+                }
+            }
+            setForceShowIcon(preserveIconSpacing);
+        }
+
+        @Override
+        public void onDismiss() {
+            super.onDismiss();
+            mActionButtonPopup = null;
+            mOpenSubMenuId = 0;
+        }
+    }
+
+    private class PopupPresenterCallback implements MenuPresenter.Callback {
+
+        @Override
+        public boolean onOpenSubMenu(MenuBuilder subMenu) {
+            if (subMenu == null) return false;
+
+            mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
+            return false;
+        }
+
+        @Override
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+            if (menu instanceof SubMenuBuilder) {
+                ((SubMenuBuilder) menu).getRootMenu().close(false);
+            }
+        }
+    }
+
+    private class OpenOverflowRunnable implements Runnable {
+        private OverflowPopup mPopup;
+
+        public OpenOverflowRunnable(OverflowPopup popup) {
+            mPopup = popup;
+        }
+
+        public void run() {
+            mMenu.changeMenuMode();
+            final View menuView = (View) mMenuView;
+            if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
+                mOverflowPopup = mPopup;
+            }
+            mPostedOpenRunnable = null;
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ActionMenuView.java
new file mode 100644 (file)
index 0000000..e090677
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.actionbarsherlock.internal.view.menu;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.Canvas;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.LinearLayout;
+import com.actionbarsherlock.internal.widget.IcsLinearLayout;
+
+/**
+ * @hide
+ */
+public class ActionMenuView extends IcsLinearLayout implements MenuBuilder.ItemInvoker, MenuView {
+    //UNUSED private static final String TAG = "ActionMenuView";
+    private static final boolean IS_FROYO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
+
+    static final int MIN_CELL_SIZE = 56; // dips
+    static final int GENERATED_ITEM_PADDING = 4; // dips
+
+    private MenuBuilder mMenu;
+
+    private boolean mReserveOverflow;
+    private ActionMenuPresenter mPresenter;
+    private boolean mFormatItems;
+    private int mFormatItemsWidth;
+    private int mMinCellSize;
+    private int mGeneratedItemPadding;
+    //UNUSED private int mMeasuredExtraWidth;
+
+    private boolean mFirst = true;
+
+    public ActionMenuView(Context context) {
+        this(context, null);
+    }
+
+    public ActionMenuView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setBaselineAligned(false);
+        final float density = context.getResources().getDisplayMetrics().density;
+        mMinCellSize = (int) (MIN_CELL_SIZE * density);
+        mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density);
+    }
+
+    public void setPresenter(ActionMenuPresenter presenter) {
+        mPresenter = presenter;
+    }
+
+    public boolean isExpandedFormat() {
+        return mFormatItems;
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (IS_FROYO) {
+            super.onConfigurationChanged(newConfig);
+        }
+        mPresenter.updateMenuView(false);
+
+        if (mPresenter != null && mPresenter.isOverflowMenuShowing()) {
+            mPresenter.hideOverflowMenu();
+            mPresenter.showOverflowMenu();
+        }
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        //Need to trigger a relayout since we may have been added extremely
+        //late in the initial rendering (e.g., when contained in a ViewPager).
+        //See: https://github.com/JakeWharton/ActionBarSherlock/issues/272
+        if (!IS_FROYO && mFirst) {
+            mFirst = false;
+            requestLayout();
+            return;
+        }
+        super.onDraw(canvas);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // If we've been given an exact size to match, apply special formatting during layout.
+        final boolean wasFormatted = mFormatItems;
+        mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
+
+        if (wasFormatted != mFormatItems) {
+            mFormatItemsWidth = 0; // Reset this when switching modes
+        }
+
+        // Special formatting can change whether items can fit as action buttons.
+        // Kick the menu and update presenters when this changes.
+        final int widthSize = MeasureSpec.getMode(widthMeasureSpec);
+        if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) {
+            mFormatItemsWidth = widthSize;
+            mMenu.onItemsChanged(true);
+        }
+
+        if (mFormatItems) {
+            onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
+        } else {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) {
+        // We already know the width mode is EXACTLY if we're here.
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+        final int widthPadding = getPaddingLeft() + getPaddingRight();
+        final int heightPadding = getPaddingTop() + getPaddingBottom();
+
+        widthSize -= widthPadding;
+
+        // Divide the view into cells.
+        final int cellCount = widthSize / mMinCellSize;
+        final int cellSizeRemaining = widthSize % mMinCellSize;
+
+        if (cellCount == 0) {
+            // Give up, nothing fits.
+            setMeasuredDimension(widthSize, 0);
+            return;
+        }
+
+        final int cellSize = mMinCellSize + cellSizeRemaining / cellCount;
+
+        int cellsRemaining = cellCount;
+        int maxChildHeight = 0;
+        int maxCellsUsed = 0;
+        int expandableItemCount = 0;
+        int visibleItemCount = 0;
+        boolean hasOverflow = false;
+
+        // This is used as a bitfield to locate the smallest items present. Assumes childCount < 64.
+        long smallestItemsAt = 0;
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() == GONE) continue;
+
+            final boolean isGeneratedItem = child instanceof ActionMenuItemView;
+            visibleItemCount++;
+
+            if (isGeneratedItem) {
+                // Reset padding for generated menu item views; it may change below
+                // and views are recycled.
+                child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0);
+            }
+
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            lp.expanded = false;
+            lp.extraPixels = 0;
+            lp.cellsUsed = 0;
+            lp.expandable = false;
+            lp.leftMargin = 0;
+            lp.rightMargin = 0;
+            lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText();
+
+            // Overflow always gets 1 cell. No more, no less.
+            final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining;
+
+            final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable,
+                    heightMeasureSpec, heightPadding);
+
+            maxCellsUsed = Math.max(maxCellsUsed, cellsUsed);
+            if (lp.expandable) expandableItemCount++;
+            if (lp.isOverflowButton) hasOverflow = true;
+
+            cellsRemaining -= cellsUsed;
+            maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
+            if (cellsUsed == 1) smallestItemsAt |= (1 << i);
+        }
+
+        // When we have overflow and a single expanded (text) item, we want to try centering it
+        // visually in the available space even though overflow consumes some of it.
+        final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2;
+
+        // Divide space for remaining cells if we have items that can expand.
+        // Try distributing whole leftover cells to smaller items first.
+
+        boolean needsExpansion = false;
+        while (expandableItemCount > 0 && cellsRemaining > 0) {
+            int minCells = Integer.MAX_VALUE;
+            long minCellsAt = 0; // Bit locations are indices of relevant child views
+            int minCellsItemCount = 0;
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+                // Don't try to expand items that shouldn't.
+                if (!lp.expandable) continue;
+
+                // Mark indices of children that can receive an extra cell.
+                if (lp.cellsUsed < minCells) {
+                    minCells = lp.cellsUsed;
+                    minCellsAt = 1 << i;
+                    minCellsItemCount = 1;
+                } else if (lp.cellsUsed == minCells) {
+                    minCellsAt |= 1 << i;
+                    minCellsItemCount++;
+                }
+            }
+
+            // Items that get expanded will always be in the set of smallest items when we're done.
+            smallestItemsAt |= minCellsAt;
+
+            if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
+
+            // We have enough cells, all minimum size items will be incremented.
+            minCells++;
+
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if ((minCellsAt & (1 << i)) == 0) {
+                    // If this item is already at our small item count, mark it for later.
+                    if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i;
+                    continue;
+                }
+
+                if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) {
+                    // Add padding to this item such that it centers.
+                    child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0);
+                }
+                lp.cellsUsed++;
+                lp.expanded = true;
+                cellsRemaining--;
+            }
+
+            needsExpansion = true;
+        }
+
+        // Divide any space left that wouldn't divide along cell boundaries
+        // evenly among the smallest items
+
+        final boolean singleItem = !hasOverflow && visibleItemCount == 1;
+        if (cellsRemaining > 0 && smallestItemsAt != 0 &&
+                (cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) {
+            float expandCount = Long.bitCount(smallestItemsAt);
+
+            if (!singleItem) {
+                // The items at the far edges may only expand by half in order to pin to either side.
+                if ((smallestItemsAt & 1) != 0) {
+                    LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams();
+                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
+                }
+                if ((smallestItemsAt & (1 << (childCount - 1))) != 0) {
+                    LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams());
+                    if (!lp.preventEdgeOffset) expandCount -= 0.5f;
+                }
+            }
+
+            final int extraPixels = expandCount > 0 ?
+                    (int) (cellsRemaining * cellSize / expandCount) : 0;
+
+            for (int i = 0; i < childCount; i++) {
+                if ((smallestItemsAt & (1 << i)) == 0) continue;
+
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (child instanceof ActionMenuItemView) {
+                    // If this is one of our views, expand and measure at the larger size.
+                    lp.extraPixels = extraPixels;
+                    lp.expanded = true;
+                    if (i == 0 && !lp.preventEdgeOffset) {
+                        // First item gets part of its new padding pushed out of sight.
+                        // The last item will get this implicitly from layout.
+                        lp.leftMargin = -extraPixels / 2;
+                    }
+                    needsExpansion = true;
+                } else if (lp.isOverflowButton) {
+                    lp.extraPixels = extraPixels;
+                    lp.expanded = true;
+                    lp.rightMargin = -extraPixels / 2;
+                    needsExpansion = true;
+                } else {
+                    // If we don't know what it is, give it some margins instead
+                    // and let it center within its space. We still want to pin
+                    // against the edges.
+                    if (i != 0) {
+                        lp.leftMargin = extraPixels / 2;
+                    }
+                    if (i != childCount - 1) {
+                        lp.rightMargin = extraPixels / 2;
+                    }
+                }
+            }
+
+            cellsRemaining = 0;
+        }
+
+        // Remeasure any items that have had extra space allocated to them.
+        if (needsExpansion) {
+            int heightSpec = MeasureSpec.makeMeasureSpec(heightSize - heightPadding, heightMode);
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+                if (!lp.expanded) continue;
+
+                final int width = lp.cellsUsed * cellSize + lp.extraPixels;
+                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightSpec);
+            }
+        }
+
+        if (heightMode != MeasureSpec.EXACTLY) {
+            heightSize = maxChildHeight;
+        }
+
+        setMeasuredDimension(widthSize, heightSize);
+        //UNUSED mMeasuredExtraWidth = cellsRemaining * cellSize;
+    }
+
+    /**
+     * Measure a child view to fit within cell-based formatting. The child's width
+     * will be measured to a whole multiple of cellSize.
+     *
+     * <p>Sets the expandable and cellsUsed fields of LayoutParams.
+     *
+     * @param child Child to measure
+     * @param cellSize Size of one cell
+     * @param cellsRemaining Number of cells remaining that this view can expand to fill
+     * @param parentHeightMeasureSpec MeasureSpec used by the parent view
+     * @param parentHeightPadding Padding present in the parent view
+     * @return Number of cells this child was measured to occupy
+     */
+    static int measureChildForCells(View child, int cellSize, int cellsRemaining,
+            int parentHeightMeasureSpec, int parentHeightPadding) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+
+        final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) -
+                parentHeightPadding;
+        final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
+        final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
+
+        int cellsUsed = 0;
+        if (cellsRemaining > 0) {
+            final int childWidthSpec = MeasureSpec.makeMeasureSpec(
+                    cellSize * cellsRemaining, MeasureSpec.AT_MOST);
+            child.measure(childWidthSpec, childHeightSpec);
+
+            final int measuredWidth = child.getMeasuredWidth();
+            cellsUsed = measuredWidth / cellSize;
+            if (measuredWidth % cellSize != 0) cellsUsed++;
+        }
+
+        final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
+                (ActionMenuItemView) child : null;
+        final boolean expandable = !lp.isOverflowButton && itemView != null && itemView.hasText();
+        lp.expandable = expandable;
+
+        lp.cellsUsed = cellsUsed;
+        final int targetWidth = cellsUsed * cellSize;
+        child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
+                childHeightSpec);
+        return cellsUsed;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        if (!mFormatItems) {
+            super.onLayout(changed, left, top, right, bottom);
+            return;
+        }
+
+        final int childCount = getChildCount();
+        final int midVertical = (top + bottom) / 2;
+        final int dividerWidth = 0;//getDividerWidth();
+        int overflowWidth = 0;
+        //UNUSED int nonOverflowWidth = 0;
+        int nonOverflowCount = 0;
+        int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
+        boolean hasOverflow = false;
+        for (int i = 0; i < childCount; i++) {
+            final View v = getChildAt(i);
+            if (v.getVisibility() == GONE) {
+                continue;
+            }
+
+            LayoutParams p = (LayoutParams) v.getLayoutParams();
+            if (p.isOverflowButton) {
+                overflowWidth = v.getMeasuredWidth();
+                if (hasDividerBeforeChildAt(i)) {
+                    overflowWidth += dividerWidth;
+                }
+
+                int height = v.getMeasuredHeight();
+                int r = getWidth() - getPaddingRight() - p.rightMargin;
+                int l = r - overflowWidth;
+                int t = midVertical - (height / 2);
+                int b = t + height;
+                v.layout(l, t, r, b);
+
+                widthRemaining -= overflowWidth;
+                hasOverflow = true;
+            } else {
+                final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
+                //UNUSED nonOverflowWidth += size;
+                widthRemaining -= size;
+                //if (hasDividerBeforeChildAt(i)) {
+                    //UNUSED nonOverflowWidth += dividerWidth;
+                //}
+                nonOverflowCount++;
+            }
+        }
+
+        if (childCount == 1 && !hasOverflow) {
+            // Center a single child
+            final View v = getChildAt(0);
+            final int width = v.getMeasuredWidth();
+            final int height = v.getMeasuredHeight();
+            final int midHorizontal = (right - left) / 2;
+            final int l = midHorizontal - width / 2;
+            final int t = midVertical - height / 2;
+            v.layout(l, t, l + width, t + height);
+            return;
+        }
+
+        final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1);
+        final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0);
+
+        int startLeft = getPaddingLeft();
+        for (int i = 0; i < childCount; i++) {
+            final View v = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+            if (v.getVisibility() == GONE || lp.isOverflowButton) {
+                continue;
+            }
+
+            startLeft += lp.leftMargin;
+            int width = v.getMeasuredWidth();
+            int height = v.getMeasuredHeight();
+            int t = midVertical - height / 2;
+            v.layout(startLeft, t, startLeft + width, t + height);
+            startLeft += width + lp.rightMargin + spacerSize;
+        }
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mPresenter.dismissPopupMenus();
+    }
+
+    public boolean isOverflowReserved() {
+        return mReserveOverflow;
+    }
+
+    public void setOverflowReserved(boolean reserveOverflow) {
+        mReserveOverflow = reserveOverflow;
+    }
+
+    @Override
+    protected LayoutParams generateDefaultLayoutParams() {
+        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.WRAP_CONTENT);
+        params.gravity = Gravity.CENTER_VERTICAL;
+        return params;
+    }
+
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        if (p instanceof LayoutParams) {
+            LayoutParams result = new LayoutParams((LayoutParams) p);
+            if (result.gravity <= Gravity.NO_GRAVITY) {
+                result.gravity = Gravity.CENTER_VERTICAL;
+            }
+            return result;
+        }
+        return generateDefaultLayoutParams();
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return p != null && p instanceof LayoutParams;
+    }
+
+    public LayoutParams generateOverflowButtonLayoutParams() {
+        LayoutParams result = generateDefaultLayoutParams();
+        result.isOverflowButton = true;
+        return result;
+    }
+
+    public boolean invokeItem(MenuItemImpl item) {
+        return mMenu.performItemAction(item, 0);
+    }
+
+    public int getWindowAnimations() {
+        return 0;
+    }
+
+    public void initialize(MenuBuilder menu) {
+        mMenu = menu;
+    }
+
+    //@Override
+    protected boolean hasDividerBeforeChildAt(int childIndex) {
+        final View childBefore = getChildAt(childIndex - 1);
+        final View child = getChildAt(childIndex);
+        boolean result = false;
+        if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) {
+            result |= ((ActionMenuChildView) childBefore).needsDividerAfter();
+        }
+        if (childIndex > 0 && child instanceof ActionMenuChildView) {
+            result |= ((ActionMenuChildView) child).needsDividerBefore();
+        }
+        return result;
+    }
+
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        return false;
+    }
+
+    public interface ActionMenuChildView {
+        public boolean needsDividerBefore();
+        public boolean needsDividerAfter();
+    }
+
+    public static class LayoutParams extends LinearLayout.LayoutParams {
+        public boolean isOverflowButton;
+        public int cellsUsed;
+        public int extraPixels;
+        public boolean expandable;
+        public boolean preventEdgeOffset;
+
+        public boolean expanded;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+        }
+
+        public LayoutParams(LayoutParams other) {
+            super((LinearLayout.LayoutParams) other);
+            isOverflowButton = other.isOverflowButton;
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+            isOverflowButton = false;
+        }
+
+        public LayoutParams(int width, int height, boolean isOverflowButton) {
+            super(width, height);
+            this.isOverflowButton = isOverflowButton;
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/BaseMenuPresenter.java
new file mode 100644 (file)
index 0000000..6da26f2
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import java.util.ArrayList;
+import android.content.Context;
+import android.os.Build;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Base class for MenuPresenters that have a consistent container view and item
+ * views. Behaves similarly to an AdapterView in that existing item views will
+ * be reused if possible when items change.
+ */
+public abstract class BaseMenuPresenter implements MenuPresenter {
+    private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
+
+    protected Context mSystemContext;
+    protected Context mContext;
+    protected MenuBuilder mMenu;
+    protected LayoutInflater mSystemInflater;
+    protected LayoutInflater mInflater;
+    private Callback mCallback;
+
+    private int mMenuLayoutRes;
+    private int mItemLayoutRes;
+
+    protected MenuView mMenuView;
+
+    private int mId;
+
+    /**
+     * Construct a new BaseMenuPresenter.
+     *
+     * @param context Context for generating system-supplied views
+     * @param menuLayoutRes Layout resource ID for the menu container view
+     * @param itemLayoutRes Layout resource ID for a single item view
+     */
+    public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) {
+        mSystemContext = context;
+        mSystemInflater = LayoutInflater.from(context);
+        mMenuLayoutRes = menuLayoutRes;
+        mItemLayoutRes = itemLayoutRes;
+    }
+
+    @Override
+    public void initForMenu(Context context, MenuBuilder menu) {
+        mContext = context;
+        mInflater = LayoutInflater.from(mContext);
+        mMenu = menu;
+    }
+
+    @Override
+    public MenuView getMenuView(ViewGroup root) {
+        if (mMenuView == null) {
+            mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false);
+            mMenuView.initialize(mMenu);
+            updateMenuView(true);
+        }
+
+        return mMenuView;
+    }
+
+    /**
+     * Reuses item views when it can
+     */
+    public void updateMenuView(boolean cleared) {
+        final ViewGroup parent = (ViewGroup) mMenuView;
+        if (parent == null) return;
+
+        int childIndex = 0;
+        if (mMenu != null) {
+            mMenu.flagActionItems();
+            ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
+            final int itemCount = visibleItems.size();
+            for (int i = 0; i < itemCount; i++) {
+                MenuItemImpl item = visibleItems.get(i);
+                if (shouldIncludeItem(childIndex, item)) {
+                    final View convertView = parent.getChildAt(childIndex);
+                    final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
+                            ((MenuView.ItemView) convertView).getItemData() : null;
+                    final View itemView = getItemView(item, convertView, parent);
+                    if (item != oldItem) {
+                        // Don't let old states linger with new data.
+                        itemView.setPressed(false);
+                        if (IS_HONEYCOMB) itemView.jumpDrawablesToCurrentState();
+                    }
+                    if (itemView != convertView) {
+                        addItemView(itemView, childIndex);
+                    }
+                    childIndex++;
+                }
+            }
+        }
+
+        // Remove leftover views.
+        while (childIndex < parent.getChildCount()) {
+            if (!filterLeftoverView(parent, childIndex)) {
+                childIndex++;
+            }
+        }
+    }
+
+    /**
+     * Add an item view at the given index.
+     *
+     * @param itemView View to add
+     * @param childIndex Index within the parent to insert at
+     */
+    protected void addItemView(View itemView, int childIndex) {
+        final ViewGroup currentParent = (ViewGroup) itemView.getParent();
+        if (currentParent != null) {
+            currentParent.removeView(itemView);
+        }
+        ((ViewGroup) mMenuView).addView(itemView, childIndex);
+    }
+
+    /**
+     * Filter the child view at index and remove it if appropriate.
+     * @param parent Parent to filter from
+     * @param childIndex Index to filter
+     * @return true if the child view at index was removed
+     */
+    protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
+        parent.removeViewAt(childIndex);
+        return true;
+    }
+
+    public void setCallback(Callback cb) {
+        mCallback = cb;
+    }
+
+    /**
+     * Create a new item view that can be re-bound to other item data later.
+     *
+     * @return The new item view
+     */
+    public MenuView.ItemView createItemView(ViewGroup parent) {
+        return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false);
+    }
+
+    /**
+     * Prepare an item view for use. See AdapterView for the basic idea at work here.
+     * This may require creating a new item view, but well-behaved implementations will
+     * re-use the view passed as convertView if present. The returned view will be populated
+     * with data from the item parameter.
+     *
+     * @param item Item to present
+     * @param convertView Existing view to reuse
+     * @param parent Intended parent view - use for inflation.
+     * @return View that presents the requested menu item
+     */
+    public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
+        MenuView.ItemView itemView;
+        if (convertView instanceof MenuView.ItemView) {
+            itemView = (MenuView.ItemView) convertView;
+        } else {
+            itemView = createItemView(parent);
+        }
+        bindItemView(item, itemView);
+        return (View) itemView;
+    }
+
+    /**
+     * Bind item data to an existing item view.
+     *
+     * @param item Item to bind
+     * @param itemView View to populate with item data
+     */
+    public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
+
+    /**
+     * Filter item by child index and item data.
+     *
+     * @param childIndex Indended presentation index of this item
+     * @param item Item to present
+     * @return true if this item should be included in this menu presentation; false otherwise
+     */
+    public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
+        return true;
+    }
+
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        if (mCallback != null) {
+            mCallback.onCloseMenu(menu, allMenusAreClosing);
+        }
+    }
+
+    public boolean onSubMenuSelected(SubMenuBuilder menu) {
+        if (mCallback != null) {
+            return mCallback.onOpenSubMenu(menu);
+        }
+        return false;
+    }
+
+    public boolean flagActionItems() {
+        return false;
+    }
+
+    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    public void setId(int id) {
+        mId = id;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ListMenuItemView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/ListMenuItemView.java
new file mode 100644 (file)
index 0000000..ac25c37
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import com.actionbarsherlock.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+/**
+ * The item view for each item in the ListView-based MenuViews.
+ */
+public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
+    private MenuItemImpl mItemData;
+
+    private ImageView mIconView;
+    private RadioButton mRadioButton;
+    private TextView mTitleView;
+    private CheckBox mCheckBox;
+    private TextView mShortcutView;
+
+    private Drawable mBackground;
+    private int mTextAppearance;
+    private Context mTextAppearanceContext;
+    private boolean mPreserveIconSpacing;
+
+    //UNUSED private int mMenuType;
+
+    private LayoutInflater mInflater;
+
+    private boolean mForceShowIcon;
+
+    final Context mContext;
+
+    public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs);
+        mContext = context;
+
+        TypedArray a =
+            context.obtainStyledAttributes(
+                attrs, R.styleable.SherlockMenuView, defStyle, 0);
+
+        mBackground = a.getDrawable(R.styleable.SherlockMenuView_itemBackground);
+        mTextAppearance = a.getResourceId(R.styleable.
+                                          SherlockMenuView_itemTextAppearance, -1);
+        mPreserveIconSpacing = a.getBoolean(
+                R.styleable.SherlockMenuView_preserveIconSpacing, false);
+        mTextAppearanceContext = context;
+
+        a.recycle();
+    }
+
+    public ListMenuItemView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        setBackgroundDrawable(mBackground);
+
+        mTitleView = (TextView) findViewById(R.id.abs__title);
+        if (mTextAppearance != -1) {
+            mTitleView.setTextAppearance(mTextAppearanceContext,
+                                         mTextAppearance);
+        }
+
+        mShortcutView = (TextView) findViewById(R.id.abs__shortcut);
+    }
+
+    public void initialize(MenuItemImpl itemData, int menuType) {
+        mItemData = itemData;
+        //UNUSED mMenuType = menuType;
+
+        setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
+
+        setTitle(itemData.getTitleForItemView(this));
+        setCheckable(itemData.isCheckable());
+        setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
+        setIcon(itemData.getIcon());
+        setEnabled(itemData.isEnabled());
+    }
+
+    public void setForceShowIcon(boolean forceShow) {
+        mPreserveIconSpacing = mForceShowIcon = forceShow;
+    }
+
+    public void setTitle(CharSequence title) {
+        if (title != null) {
+            mTitleView.setText(title);
+
+            if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE);
+        } else {
+            if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE);
+        }
+    }
+
+    public MenuItemImpl getItemData() {
+        return mItemData;
+    }
+
+    public void setCheckable(boolean checkable) {
+
+        if (!checkable && mRadioButton == null && mCheckBox == null) {
+            return;
+        }
+
+        if (mRadioButton == null) {
+            insertRadioButton();
+        }
+        if (mCheckBox == null) {
+            insertCheckBox();
+        }
+
+        // Depending on whether its exclusive check or not, the checkbox or
+        // radio button will be the one in use (and the other will be otherCompoundButton)
+        final CompoundButton compoundButton;
+        final CompoundButton otherCompoundButton;
+
+        if (mItemData.isExclusiveCheckable()) {
+            compoundButton = mRadioButton;
+            otherCompoundButton = mCheckBox;
+        } else {
+            compoundButton = mCheckBox;
+            otherCompoundButton = mRadioButton;
+        }
+
+        if (checkable) {
+            compoundButton.setChecked(mItemData.isChecked());
+
+            final int newVisibility = checkable ? VISIBLE : GONE;
+            if (compoundButton.getVisibility() != newVisibility) {
+                compoundButton.setVisibility(newVisibility);
+            }
+
+            // Make sure the other compound button isn't visible
+            if (otherCompoundButton.getVisibility() != GONE) {
+                otherCompoundButton.setVisibility(GONE);
+            }
+        } else {
+            mCheckBox.setVisibility(GONE);
+            mRadioButton.setVisibility(GONE);
+        }
+    }
+
+    public void setChecked(boolean checked) {
+        CompoundButton compoundButton;
+
+        if (mItemData.isExclusiveCheckable()) {
+            if (mRadioButton == null) {
+                insertRadioButton();
+            }
+            compoundButton = mRadioButton;
+        } else {
+            if (mCheckBox == null) {
+                insertCheckBox();
+            }
+            compoundButton = mCheckBox;
+        }
+
+        compoundButton.setChecked(checked);
+    }
+
+    public void setShortcut(boolean showShortcut, char shortcutKey) {
+        final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
+                ? VISIBLE : GONE;
+
+        if (newVisibility == VISIBLE) {
+            mShortcutView.setText(mItemData.getShortcutLabel());
+        }
+
+        if (mShortcutView.getVisibility() != newVisibility) {
+            mShortcutView.setVisibility(newVisibility);
+        }
+    }
+
+    public void setIcon(Drawable icon) {
+        final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
+        if (!showIcon && !mPreserveIconSpacing) {
+            return;
+        }
+
+        if (mIconView == null && icon == null && !mPreserveIconSpacing) {
+            return;
+        }
+
+        if (mIconView == null) {
+            insertIconView();
+        }
+
+        if (icon != null || mPreserveIconSpacing) {
+            mIconView.setImageDrawable(showIcon ? icon : null);
+
+            if (mIconView.getVisibility() != VISIBLE) {
+                mIconView.setVisibility(VISIBLE);
+            }
+        } else {
+            mIconView.setVisibility(GONE);
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mIconView != null && mPreserveIconSpacing) {
+            // Enforce minimum icon spacing
+            ViewGroup.LayoutParams lp = getLayoutParams();
+            LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+            if (lp.height > 0 && iconLp.width <= 0) {
+                iconLp.width = lp.height;
+            }
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    private void insertIconView() {
+        LayoutInflater inflater = getInflater();
+        mIconView = (ImageView) inflater.inflate(R.layout.abs__list_menu_item_icon,
+                this, false);
+        addView(mIconView, 0);
+    }
+
+    private void insertRadioButton() {
+        LayoutInflater inflater = getInflater();
+        mRadioButton =
+                (RadioButton) inflater.inflate(R.layout.abs__list_menu_item_radio,
+                this, false);
+        addView(mRadioButton);
+    }
+
+    private void insertCheckBox() {
+        LayoutInflater inflater = getInflater();
+        mCheckBox =
+                (CheckBox) inflater.inflate(R.layout.abs__list_menu_item_checkbox,
+                this, false);
+        addView(mCheckBox);
+    }
+
+    public boolean prefersCondensedTitle() {
+        return false;
+    }
+
+    public boolean showsIcon() {
+        return mForceShowIcon;
+    }
+
+    private LayoutInflater getInflater() {
+        if (mInflater == null) {
+            mInflater = LayoutInflater.from(mContext);
+        }
+        return mInflater;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuBuilder.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuBuilder.java
new file mode 100644 (file)
index 0000000..179b8f0
--- /dev/null
@@ -0,0 +1,1335 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.SparseArray;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.view.ActionProvider;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.SubMenu;
+
+/**
+ * Implementation of the {@link android.view.Menu} interface for creating a
+ * standard menu UI.
+ */
+public class MenuBuilder implements Menu {
+    //UNUSED private static final String TAG = "MenuBuilder";
+
+    private static final String PRESENTER_KEY = "android:menu:presenters";
+    private static final String ACTION_VIEW_STATES_KEY = "android:menu:actionviewstates";
+    private static final String EXPANDED_ACTION_VIEW_ID = "android:menu:expandedactionview";
+
+    private static final int[]  sCategoryToOrder = new int[] {
+        1, /* No category */
+        4, /* CONTAINER */
+        5, /* SYSTEM */
+        3, /* SECONDARY */
+        2, /* ALTERNATIVE */
+        0, /* SELECTED_ALTERNATIVE */
+    };
+
+    private final Context mContext;
+    private final Resources mResources;
+
+    /**
+     * Whether the shortcuts should be qwerty-accessible. Use isQwertyMode()
+     * instead of accessing this directly.
+     */
+    private boolean mQwertyMode;
+
+    /**
+     * Whether the shortcuts should be visible on menus. Use isShortcutsVisible()
+     * instead of accessing this directly.
+     */
+    private boolean mShortcutsVisible;
+
+    /**
+     * Callback that will receive the various menu-related events generated by
+     * this class. Use getCallback to get a reference to the callback.
+     */
+    private Callback mCallback;
+
+    /** Contains all of the items for this menu */
+    private ArrayList<MenuItemImpl> mItems;
+
+    /** Contains only the items that are currently visible.  This will be created/refreshed from
+     * {@link #getVisibleItems()} */
+    private ArrayList<MenuItemImpl> mVisibleItems;
+    /**
+     * Whether or not the items (or any one item's shown state) has changed since it was last
+     * fetched from {@link #getVisibleItems()}
+     */
+    private boolean mIsVisibleItemsStale;
+
+    /**
+     * Contains only the items that should appear in the Action Bar, if present.
+     */
+    private ArrayList<MenuItemImpl> mActionItems;
+    /**
+     * Contains items that should NOT appear in the Action Bar, if present.
+     */
+    private ArrayList<MenuItemImpl> mNonActionItems;
+
+    /**
+     * Whether or not the items (or any one item's action state) has changed since it was
+     * last fetched.
+     */
+    private boolean mIsActionItemsStale;
+
+    /**
+     * Default value for how added items should show in the action list.
+     */
+    private int mDefaultShowAsAction = MenuItem.SHOW_AS_ACTION_NEVER;
+
+    /**
+     * Current use case is Context Menus: As Views populate the context menu, each one has
+     * extra information that should be passed along.  This is the current menu info that
+     * should be set on all items added to this menu.
+     */
+    private ContextMenuInfo mCurrentMenuInfo;
+
+    /** Header title for menu types that have a header (context and submenus) */
+    CharSequence mHeaderTitle;
+    /** Header icon for menu types that have a header and support icons (context) */
+    Drawable mHeaderIcon;
+    /** Header custom view for menu types that have a header and support custom views (context) */
+    View mHeaderView;
+
+    /**
+     * Contains the state of the View hierarchy for all menu views when the menu
+     * was frozen.
+     */
+    //UNUSED private SparseArray<Parcelable> mFrozenViewStates;
+
+    /**
+     * Prevents onItemsChanged from doing its junk, useful for batching commands
+     * that may individually call onItemsChanged.
+     */
+    private boolean mPreventDispatchingItemsChanged = false;
+    private boolean mItemsChangedWhileDispatchPrevented = false;
+
+    private boolean mOptionalIconsVisible = false;
+
+    private boolean mIsClosing = false;
+
+    private ArrayList<MenuItemImpl> mTempShortcutItemList = new ArrayList<MenuItemImpl>();
+
+    private CopyOnWriteArrayList<WeakReference<MenuPresenter>> mPresenters =
+            new CopyOnWriteArrayList<WeakReference<MenuPresenter>>();
+
+    /**
+     * Currently expanded menu item; must be collapsed when we clear.
+     */
+    private MenuItemImpl mExpandedItem;
+
+    /**
+     * Called by menu to notify of close and selection changes.
+     */
+    public interface Callback {
+        /**
+         * Called when a menu item is selected.
+         * @param menu The menu that is the parent of the item
+         * @param item The menu item that is selected
+         * @return whether the menu item selection was handled
+         */
+        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item);
+
+        /**
+         * Called when the mode of the menu changes (for example, from icon to expanded).
+         *
+         * @param menu the menu that has changed modes
+         */
+        public void onMenuModeChange(MenuBuilder menu);
+    }
+
+    /**
+     * Called by menu items to execute their associated action
+     */
+    public interface ItemInvoker {
+        public boolean invokeItem(MenuItemImpl item);
+    }
+
+    public MenuBuilder(Context context) {
+        mContext = context;
+        mResources = context.getResources();
+
+        mItems = new ArrayList<MenuItemImpl>();
+
+        mVisibleItems = new ArrayList<MenuItemImpl>();
+        mIsVisibleItemsStale = true;
+
+        mActionItems = new ArrayList<MenuItemImpl>();
+        mNonActionItems = new ArrayList<MenuItemImpl>();
+        mIsActionItemsStale = true;
+
+        setShortcutsVisibleInner(true);
+    }
+
+    public MenuBuilder setDefaultShowAsAction(int defaultShowAsAction) {
+        mDefaultShowAsAction = defaultShowAsAction;
+        return this;
+    }
+
+    /**
+     * Add a presenter to this menu. This will only hold a WeakReference;
+     * you do not need to explicitly remove a presenter, but you can using
+     * {@link #removeMenuPresenter(MenuPresenter)}.
+     *
+     * @param presenter The presenter to add
+     */
+    public void addMenuPresenter(MenuPresenter presenter) {
+        mPresenters.add(new WeakReference<MenuPresenter>(presenter));
+        presenter.initForMenu(mContext, this);
+        mIsActionItemsStale = true;
+    }
+
+    /**
+     * Remove a presenter from this menu. That presenter will no longer
+     * receive notifications of updates to this menu's data.
+     *
+     * @param presenter The presenter to remove
+     */
+    public void removeMenuPresenter(MenuPresenter presenter) {
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter item = ref.get();
+            if (item == null || item == presenter) {
+                mPresenters.remove(ref);
+            }
+        }
+    }
+
+    private void dispatchPresenterUpdate(boolean cleared) {
+        if (mPresenters.isEmpty()) return;
+
+        stopDispatchingItemsChanged();
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter presenter = ref.get();
+            if (presenter == null) {
+                mPresenters.remove(ref);
+            } else {
+                presenter.updateMenuView(cleared);
+            }
+        }
+        startDispatchingItemsChanged();
+    }
+
+    private boolean dispatchSubMenuSelected(SubMenuBuilder subMenu) {
+        if (mPresenters.isEmpty()) return false;
+
+        boolean result = false;
+
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter presenter = ref.get();
+            if (presenter == null) {
+                mPresenters.remove(ref);
+            } else if (!result) {
+                result = presenter.onSubMenuSelected(subMenu);
+            }
+        }
+        return result;
+    }
+
+    private void dispatchSaveInstanceState(Bundle outState) {
+        if (mPresenters.isEmpty()) return;
+
+        SparseArray<Parcelable> presenterStates = new SparseArray<Parcelable>();
+
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter presenter = ref.get();
+            if (presenter == null) {
+                mPresenters.remove(ref);
+            } else {
+                final int id = presenter.getId();
+                if (id > 0) {
+                    final Parcelable state = presenter.onSaveInstanceState();
+                    if (state != null) {
+                        presenterStates.put(id, state);
+                    }
+                }
+            }
+        }
+
+        outState.putSparseParcelableArray(PRESENTER_KEY, presenterStates);
+    }
+
+    private void dispatchRestoreInstanceState(Bundle state) {
+        SparseArray<Parcelable> presenterStates = state.getSparseParcelableArray(PRESENTER_KEY);
+
+        if (presenterStates == null || mPresenters.isEmpty()) return;
+
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter presenter = ref.get();
+            if (presenter == null) {
+                mPresenters.remove(ref);
+            } else {
+                final int id = presenter.getId();
+                if (id > 0) {
+                    Parcelable parcel = presenterStates.get(id);
+                    if (parcel != null) {
+                        presenter.onRestoreInstanceState(parcel);
+                    }
+                }
+            }
+        }
+    }
+
+    public void savePresenterStates(Bundle outState) {
+        dispatchSaveInstanceState(outState);
+    }
+
+    public void restorePresenterStates(Bundle state) {
+        dispatchRestoreInstanceState(state);
+    }
+
+    public void saveActionViewStates(Bundle outStates) {
+        SparseArray<Parcelable> viewStates = null;
+
+        final int itemCount = size();
+        for (int i = 0; i < itemCount; i++) {
+            final MenuItem item = getItem(i);
+            final View v = item.getActionView();
+            if (v != null && v.getId() != View.NO_ID) {
+                if (viewStates == null) {
+                    viewStates = new SparseArray<Parcelable>();
+                }
+                v.saveHierarchyState(viewStates);
+                if (item.isActionViewExpanded()) {
+                    outStates.putInt(EXPANDED_ACTION_VIEW_ID, item.getItemId());
+                }
+            }
+            if (item.hasSubMenu()) {
+                final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+                subMenu.saveActionViewStates(outStates);
+            }
+        }
+
+        if (viewStates != null) {
+            outStates.putSparseParcelableArray(getActionViewStatesKey(), viewStates);
+        }
+    }
+
+    public void restoreActionViewStates(Bundle states) {
+        if (states == null) {
+            return;
+        }
+
+        SparseArray<Parcelable> viewStates = states.getSparseParcelableArray(
+                getActionViewStatesKey());
+
+        final int itemCount = size();
+        for (int i = 0; i < itemCount; i++) {
+            final MenuItem item = getItem(i);
+            final View v = item.getActionView();
+            if (v != null && v.getId() != View.NO_ID) {
+                v.restoreHierarchyState(viewStates);
+            }
+            if (item.hasSubMenu()) {
+                final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+                subMenu.restoreActionViewStates(states);
+            }
+        }
+
+        final int expandedId = states.getInt(EXPANDED_ACTION_VIEW_ID);
+        if (expandedId > 0) {
+            MenuItem itemToExpand = findItem(expandedId);
+            if (itemToExpand != null) {
+                itemToExpand.expandActionView();
+            }
+        }
+    }
+
+    protected String getActionViewStatesKey() {
+        return ACTION_VIEW_STATES_KEY;
+    }
+
+    public void setCallback(Callback cb) {
+        mCallback = cb;
+    }
+
+    /**
+     * Adds an item to the menu.  The other add methods funnel to this.
+     */
+    private MenuItem addInternal(int group, int id, int categoryOrder, CharSequence title) {
+        final int ordering = getOrdering(categoryOrder);
+
+        final MenuItemImpl item = new MenuItemImpl(this, group, id, categoryOrder,
+                ordering, title, mDefaultShowAsAction);
+
+        if (mCurrentMenuInfo != null) {
+            // Pass along the current menu info
+            item.setMenuInfo(mCurrentMenuInfo);
+        }
+
+        mItems.add(findInsertIndex(mItems, ordering), item);
+        onItemsChanged(true);
+
+        return item;
+    }
+
+    public MenuItem add(CharSequence title) {
+        return addInternal(0, 0, 0, title);
+    }
+
+    public MenuItem add(int titleRes) {
+        return addInternal(0, 0, 0, mResources.getString(titleRes));
+    }
+
+    public MenuItem add(int group, int id, int categoryOrder, CharSequence title) {
+        return addInternal(group, id, categoryOrder, title);
+    }
+
+    public MenuItem add(int group, int id, int categoryOrder, int title) {
+        return addInternal(group, id, categoryOrder, mResources.getString(title));
+    }
+
+    public SubMenu addSubMenu(CharSequence title) {
+        return addSubMenu(0, 0, 0, title);
+    }
+
+    public SubMenu addSubMenu(int titleRes) {
+        return addSubMenu(0, 0, 0, mResources.getString(titleRes));
+    }
+
+    public SubMenu addSubMenu(int group, int id, int categoryOrder, CharSequence title) {
+        final MenuItemImpl item = (MenuItemImpl) addInternal(group, id, categoryOrder, title);
+        final SubMenuBuilder subMenu = new SubMenuBuilder(mContext, this, item);
+        item.setSubMenu(subMenu);
+
+        return subMenu;
+    }
+
+    public SubMenu addSubMenu(int group, int id, int categoryOrder, int title) {
+        return addSubMenu(group, id, categoryOrder, mResources.getString(title));
+    }
+
+    public int addIntentOptions(int group, int id, int categoryOrder, ComponentName caller,
+            Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
+        PackageManager pm = mContext.getPackageManager();
+        final List<ResolveInfo> lri =
+                pm.queryIntentActivityOptions(caller, specifics, intent, 0);
+        final int N = lri != null ? lri.size() : 0;
+
+        if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
+            removeGroup(group);
+        }
+
+        for (int i=0; i<N; i++) {
+            final ResolveInfo ri = lri.get(i);
+            Intent rintent = new Intent(
+                ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
+            rintent.setComponent(new ComponentName(
+                    ri.activityInfo.applicationInfo.packageName,
+                    ri.activityInfo.name));
+            final MenuItem item = add(group, id, categoryOrder, ri.loadLabel(pm))
+                    .setIcon(ri.loadIcon(pm))
+                    .setIntent(rintent);
+            if (outSpecificItems != null && ri.specificIndex >= 0) {
+                outSpecificItems[ri.specificIndex] = item;
+            }
+        }
+
+        return N;
+    }
+
+    public void removeItem(int id) {
+        removeItemAtInt(findItemIndex(id), true);
+    }
+
+    public void removeGroup(int group) {
+        final int i = findGroupIndex(group);
+
+        if (i >= 0) {
+            final int maxRemovable = mItems.size() - i;
+            int numRemoved = 0;
+            while ((numRemoved++ < maxRemovable) && (mItems.get(i).getGroupId() == group)) {
+                // Don't force update for each one, this method will do it at the end
+                removeItemAtInt(i, false);
+            }
+
+            // Notify menu views
+            onItemsChanged(true);
+        }
+    }
+
+    /**
+     * Remove the item at the given index and optionally forces menu views to
+     * update.
+     *
+     * @param index The index of the item to be removed. If this index is
+     *            invalid an exception is thrown.
+     * @param updateChildrenOnMenuViews Whether to force update on menu views.
+     *            Please make sure you eventually call this after your batch of
+     *            removals.
+     */
+    private void removeItemAtInt(int index, boolean updateChildrenOnMenuViews) {
+        if ((index < 0) || (index >= mItems.size())) return;
+
+        mItems.remove(index);
+
+        if (updateChildrenOnMenuViews) onItemsChanged(true);
+    }
+
+    public void removeItemAt(int index) {
+        removeItemAtInt(index, true);
+    }
+
+    public void clearAll() {
+        mPreventDispatchingItemsChanged = true;
+        clear();
+        clearHeader();
+        mPreventDispatchingItemsChanged = false;
+        mItemsChangedWhileDispatchPrevented = false;
+        onItemsChanged(true);
+    }
+
+    public void clear() {
+        if (mExpandedItem != null) {
+            collapseItemActionView(mExpandedItem);
+        }
+        mItems.clear();
+
+        onItemsChanged(true);
+    }
+
+    void setExclusiveItemChecked(MenuItem item) {
+        final int group = item.getGroupId();
+
+        final int N = mItems.size();
+        for (int i = 0; i < N; i++) {
+            MenuItemImpl curItem = mItems.get(i);
+            if (curItem.getGroupId() == group) {
+                if (!curItem.isExclusiveCheckable()) continue;
+                if (!curItem.isCheckable()) continue;
+
+                // Check the item meant to be checked, uncheck the others (that are in the group)
+                curItem.setCheckedInt(curItem == item);
+            }
+        }
+    }
+
+    public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
+        final int N = mItems.size();
+
+        for (int i = 0; i < N; i++) {
+            MenuItemImpl item = mItems.get(i);
+            if (item.getGroupId() == group) {
+                item.setExclusiveCheckable(exclusive);
+                item.setCheckable(checkable);
+            }
+        }
+    }
+
+    public void setGroupVisible(int group, boolean visible) {
+        final int N = mItems.size();
+
+        // We handle the notification of items being changed ourselves, so we use setVisibleInt rather
+        // than setVisible and at the end notify of items being changed
+
+        boolean changedAtLeastOneItem = false;
+        for (int i = 0; i < N; i++) {
+            MenuItemImpl item = mItems.get(i);
+            if (item.getGroupId() == group) {
+                if (item.setVisibleInt(visible)) changedAtLeastOneItem = true;
+            }
+        }
+
+        if (changedAtLeastOneItem) onItemsChanged(true);
+    }
+
+    public void setGroupEnabled(int group, boolean enabled) {
+        final int N = mItems.size();
+
+        for (int i = 0; i < N; i++) {
+            MenuItemImpl item = mItems.get(i);
+            if (item.getGroupId() == group) {
+                item.setEnabled(enabled);
+            }
+        }
+    }
+
+    public boolean hasVisibleItems() {
+        final int size = size();
+
+        for (int i = 0; i < size; i++) {
+            MenuItemImpl item = mItems.get(i);
+            if (item.isVisible()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public MenuItem findItem(int id) {
+        final int size = size();
+        for (int i = 0; i < size; i++) {
+            MenuItemImpl item = mItems.get(i);
+            if (item.getItemId() == id) {
+                return item;
+            } else if (item.hasSubMenu()) {
+                MenuItem possibleItem = item.getSubMenu().findItem(id);
+
+                if (possibleItem != null) {
+                    return possibleItem;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    public int findItemIndex(int id) {
+        final int size = size();
+
+        for (int i = 0; i < size; i++) {
+            MenuItemImpl item = mItems.get(i);
+            if (item.getItemId() == id) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    public int findGroupIndex(int group) {
+        return findGroupIndex(group, 0);
+    }
+
+    public int findGroupIndex(int group, int start) {
+        final int size = size();
+
+        if (start < 0) {
+            start = 0;
+        }
+
+        for (int i = start; i < size; i++) {
+            final MenuItemImpl item = mItems.get(i);
+
+            if (item.getGroupId() == group) {
+                return i;
+            }
+        }
+
+        return -1;
+    }
+
+    public int size() {
+        return mItems.size();
+    }
+
+    /** {@inheritDoc} */
+    public MenuItem getItem(int index) {
+        return mItems.get(index);
+    }
+
+    public boolean isShortcutKey(int keyCode, KeyEvent event) {
+        return findItemWithShortcutForKey(keyCode, event) != null;
+    }
+
+    public void setQwertyMode(boolean isQwerty) {
+        mQwertyMode = isQwerty;
+
+        onItemsChanged(false);
+    }
+
+    /**
+     * Returns the ordering across all items. This will grab the category from
+     * the upper bits, find out how to order the category with respect to other
+     * categories, and combine it with the lower bits.
+     *
+     * @param categoryOrder The category order for a particular item (if it has
+     *            not been or/add with a category, the default category is
+     *            assumed).
+     * @return An ordering integer that can be used to order this item across
+     *         all the items (even from other categories).
+     */
+    private static int getOrdering(int categoryOrder) {
+        final int index = (categoryOrder & CATEGORY_MASK) >> CATEGORY_SHIFT;
+
+        if (index < 0 || index >= sCategoryToOrder.length) {
+            throw new IllegalArgumentException("order does not contain a valid category.");
+        }
+
+        return (sCategoryToOrder[index] << CATEGORY_SHIFT) | (categoryOrder & USER_MASK);
+    }
+
+    /**
+     * @return whether the menu shortcuts are in qwerty mode or not
+     */
+    boolean isQwertyMode() {
+        return mQwertyMode;
+    }
+
+    /**
+     * Sets whether the shortcuts should be visible on menus.  Devices without hardware
+     * key input will never make shortcuts visible even if this method is passed 'true'.
+     *
+     * @param shortcutsVisible Whether shortcuts should be visible (if true and a
+     *            menu item does not have a shortcut defined, that item will
+     *            still NOT show a shortcut)
+     */
+    public void setShortcutsVisible(boolean shortcutsVisible) {
+        if (mShortcutsVisible == shortcutsVisible) return;
+
+        setShortcutsVisibleInner(shortcutsVisible);
+        onItemsChanged(false);
+    }
+
+    private void setShortcutsVisibleInner(boolean shortcutsVisible) {
+        mShortcutsVisible = shortcutsVisible
+                && mResources.getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS
+                && mResources.getBoolean(
+                        R.bool.abs__config_showMenuShortcutsWhenKeyboardPresent);
+    }
+
+    /**
+     * @return Whether shortcuts should be visible on menus.
+     */
+    public boolean isShortcutsVisible() {
+        return mShortcutsVisible;
+    }
+
+    Resources getResources() {
+        return mResources;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) {
+        return mCallback != null && mCallback.onMenuItemSelected(menu, item);
+    }
+
+    /**
+     * Dispatch a mode change event to this menu's callback.
+     */
+    public void changeMenuMode() {
+        if (mCallback != null) {
+            mCallback.onMenuModeChange(this);
+        }
+    }
+
+    private static int findInsertIndex(ArrayList<MenuItemImpl> items, int ordering) {
+        for (int i = items.size() - 1; i >= 0; i--) {
+            MenuItemImpl item = items.get(i);
+            if (item.getOrdering() <= ordering) {
+                return i + 1;
+            }
+        }
+
+        return 0;
+    }
+
+    public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
+        final MenuItemImpl item = findItemWithShortcutForKey(keyCode, event);
+
+        boolean handled = false;
+
+        if (item != null) {
+            handled = performItemAction(item, flags);
+        }
+
+        if ((flags & FLAG_ALWAYS_PERFORM_CLOSE) != 0) {
+            close(true);
+        }
+
+        return handled;
+    }
+
+    /*
+     * This function will return all the menu and sub-menu items that can
+     * be directly (the shortcut directly corresponds) and indirectly
+     * (the ALT-enabled char corresponds to the shortcut) associated
+     * with the keyCode.
+     */
+    @SuppressWarnings("deprecation")
+    void findItemsWithShortcutForKey(List<MenuItemImpl> items, int keyCode, KeyEvent event) {
+        final boolean qwerty = isQwertyMode();
+        final int metaState = event.getMetaState();
+        final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
+        // Get the chars associated with the keyCode (i.e using any chording combo)
+        final boolean isKeyCodeMapped = event.getKeyData(possibleChars);
+        // The delete key is not mapped to '\b' so we treat it specially
+        if (!isKeyCodeMapped && (keyCode != KeyEvent.KEYCODE_DEL)) {
+            return;
+        }
+
+        // Look for an item whose shortcut is this key.
+        final int N = mItems.size();
+        for (int i = 0; i < N; i++) {
+            MenuItemImpl item = mItems.get(i);
+            if (item.hasSubMenu()) {
+                ((MenuBuilder)item.getSubMenu()).findItemsWithShortcutForKey(items, keyCode, event);
+            }
+            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() : item.getNumericShortcut();
+            if (((metaState & (KeyEvent.META_SHIFT_ON | KeyEvent.META_SYM_ON)) == 0) &&
+                  (shortcutChar != 0) &&
+                  (shortcutChar == possibleChars.meta[0]
+                      || shortcutChar == possibleChars.meta[2]
+                      || (qwerty && shortcutChar == '\b' &&
+                          keyCode == KeyEvent.KEYCODE_DEL)) &&
+                  item.isEnabled()) {
+                items.add(item);
+            }
+        }
+    }
+
+    /*
+     * We want to return the menu item associated with the key, but if there is no
+     * ambiguity (i.e. there is only one menu item corresponding to the key) we want
+     * to return it even if it's not an exact match; this allow the user to
+     * _not_ use the ALT key for example, making the use of shortcuts slightly more
+     * user-friendly. An example is on the G1, '!' and '1' are on the same key, and
+     * in Gmail, Menu+1 will trigger Menu+! (the actual shortcut).
+     *
+     * On the other hand, if two (or more) shortcuts corresponds to the same key,
+     * we have to only return the exact match.
+     */
+    @SuppressWarnings("deprecation")
+    MenuItemImpl findItemWithShortcutForKey(int keyCode, KeyEvent event) {
+        // Get all items that can be associated directly or indirectly with the keyCode
+        ArrayList<MenuItemImpl> items = mTempShortcutItemList;
+        items.clear();
+        findItemsWithShortcutForKey(items, keyCode, event);
+
+        if (items.isEmpty()) {
+            return null;
+        }
+
+        final int metaState = event.getMetaState();
+        final KeyCharacterMap.KeyData possibleChars = new KeyCharacterMap.KeyData();
+        // Get the chars associated with the keyCode (i.e using any chording combo)
+        event.getKeyData(possibleChars);
+
+        // If we have only one element, we can safely returns it
+        final int size = items.size();
+        if (size == 1) {
+            return items.get(0);
+        }
+
+        final boolean qwerty = isQwertyMode();
+        // If we found more than one item associated with the key,
+        // we have to return the exact match
+        for (int i = 0; i < size; i++) {
+            final MenuItemImpl item = items.get(i);
+            final char shortcutChar = qwerty ? item.getAlphabeticShortcut() :
+                    item.getNumericShortcut();
+            if ((shortcutChar == possibleChars.meta[0] &&
+                    (metaState & KeyEvent.META_ALT_ON) == 0)
+                || (shortcutChar == possibleChars.meta[2] &&
+                    (metaState & KeyEvent.META_ALT_ON) != 0)
+                || (qwerty && shortcutChar == '\b' &&
+                    keyCode == KeyEvent.KEYCODE_DEL)) {
+                return item;
+            }
+        }
+        return null;
+    }
+
+    public boolean performIdentifierAction(int id, int flags) {
+        // Look for an item whose identifier is the id.
+        return performItemAction(findItem(id), flags);
+    }
+
+    public boolean performItemAction(MenuItem item, int flags) {
+        MenuItemImpl itemImpl = (MenuItemImpl) item;
+
+        if (itemImpl == null || !itemImpl.isEnabled()) {
+            return false;
+        }
+
+        boolean invoked = itemImpl.invoke();
+
+        if (itemImpl.hasCollapsibleActionView()) {
+            invoked |= itemImpl.expandActionView();
+            if (invoked) close(true);
+        } else if (item.hasSubMenu()) {
+            close(false);
+
+            final SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
+            final ActionProvider provider = item.getActionProvider();
+            if (provider != null && provider.hasSubMenu()) {
+                provider.onPrepareSubMenu(subMenu);
+            }
+            invoked |= dispatchSubMenuSelected(subMenu);
+            if (!invoked) close(true);
+        } else {
+            if ((flags & FLAG_PERFORM_NO_CLOSE) == 0) {
+                close(true);
+            }
+        }
+
+        return invoked;
+    }
+
+    /**
+     * Closes the visible menu.
+     *
+     * @param allMenusAreClosing Whether the menus are completely closing (true),
+     *            or whether there is another menu coming in this menu's place
+     *            (false). For example, if the menu is closing because a
+     *            sub menu is about to be shown, <var>allMenusAreClosing</var>
+     *            is false.
+     */
+    final void close(boolean allMenusAreClosing) {
+        if (mIsClosing) return;
+
+        mIsClosing = true;
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter presenter = ref.get();
+            if (presenter == null) {
+                mPresenters.remove(ref);
+            } else {
+                presenter.onCloseMenu(this, allMenusAreClosing);
+            }
+        }
+        mIsClosing = false;
+    }
+
+    /** {@inheritDoc} */
+    public void close() {
+        close(true);
+    }
+
+    /**
+     * Called when an item is added or removed.
+     *
+     * @param structureChanged true if the menu structure changed,
+     *                         false if only item properties changed.
+     *                         (Visibility is a structural property since it affects layout.)
+     */
+    void onItemsChanged(boolean structureChanged) {
+        if (!mPreventDispatchingItemsChanged) {
+            if (structureChanged) {
+                mIsVisibleItemsStale = true;
+                mIsActionItemsStale = true;
+            }
+
+            dispatchPresenterUpdate(structureChanged);
+        } else {
+            mItemsChangedWhileDispatchPrevented = true;
+        }
+    }
+
+    /**
+     * Stop dispatching item changed events to presenters until
+     * {@link #startDispatchingItemsChanged()} is called. Useful when
+     * many menu operations are going to be performed as a batch.
+     */
+    public void stopDispatchingItemsChanged() {
+        if (!mPreventDispatchingItemsChanged) {
+            mPreventDispatchingItemsChanged = true;
+            mItemsChangedWhileDispatchPrevented = false;
+        }
+    }
+
+    public void startDispatchingItemsChanged() {
+        mPreventDispatchingItemsChanged = false;
+
+        if (mItemsChangedWhileDispatchPrevented) {
+            mItemsChangedWhileDispatchPrevented = false;
+            onItemsChanged(true);
+        }
+    }
+
+    /**
+     * Called by {@link MenuItemImpl} when its visible flag is changed.
+     * @param item The item that has gone through a visibility change.
+     */
+    void onItemVisibleChanged(MenuItemImpl item) {
+        // Notify of items being changed
+        mIsVisibleItemsStale = true;
+        onItemsChanged(true);
+    }
+
+    /**
+     * Called by {@link MenuItemImpl} when its action request status is changed.
+     * @param item The item that has gone through a change in action request status.
+     */
+    void onItemActionRequestChanged(MenuItemImpl item) {
+        // Notify of items being changed
+        mIsActionItemsStale = true;
+        onItemsChanged(true);
+    }
+
+    ArrayList<MenuItemImpl> getVisibleItems() {
+        if (!mIsVisibleItemsStale) return mVisibleItems;
+
+        // Refresh the visible items
+        mVisibleItems.clear();
+
+        final int itemsSize = mItems.size();
+        MenuItemImpl item;
+        for (int i = 0; i < itemsSize; i++) {
+            item = mItems.get(i);
+            if (item.isVisible()) mVisibleItems.add(item);
+        }
+
+        mIsVisibleItemsStale = false;
+        mIsActionItemsStale = true;
+
+        return mVisibleItems;
+    }
+
+    /**
+     * This method determines which menu items get to be 'action items' that will appear
+     * in an action bar and which items should be 'overflow items' in a secondary menu.
+     * The rules are as follows:
+     *
+     * <p>Items are considered for inclusion in the order specified within the menu.
+     * There is a limit of mMaxActionItems as a total count, optionally including the overflow
+     * menu button itself. This is a soft limit; if an item shares a group ID with an item
+     * previously included as an action item, the new item will stay with its group and become
+     * an action item itself even if it breaks the max item count limit. This is done to
+     * limit the conceptual complexity of the items presented within an action bar. Only a few
+     * unrelated concepts should be presented to the user in this space, and groups are treated
+     * as a single concept.
+     *
+     * <p>There is also a hard limit of consumed measurable space: mActionWidthLimit. This
+     * limit may be broken by a single item that exceeds the remaining space, but no further
+     * items may be added. If an item that is part of a group cannot fit within the remaining
+     * measured width, the entire group will be demoted to overflow. This is done to ensure room
+     * for navigation and other affordances in the action bar as well as reduce general UI clutter.
+     *
+     * <p>The space freed by demoting a full group cannot be consumed by future menu items.
+     * Once items begin to overflow, all future items become overflow items as well. This is
+     * to avoid inadvertent reordering that may break the app's intended design.
+     */
+    public void flagActionItems() {
+        if (!mIsActionItemsStale) {
+            return;
+        }
+
+        // Presenters flag action items as needed.
+        boolean flagged = false;
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter presenter = ref.get();
+            if (presenter == null) {
+                mPresenters.remove(ref);
+            } else {
+                flagged |= presenter.flagActionItems();
+            }
+        }
+
+        if (flagged) {
+            mActionItems.clear();
+            mNonActionItems.clear();
+            ArrayList<MenuItemImpl> visibleItems = getVisibleItems();
+            final int itemsSize = visibleItems.size();
+            for (int i = 0; i < itemsSize; i++) {
+                MenuItemImpl item = visibleItems.get(i);
+                if (item.isActionButton()) {
+                    mActionItems.add(item);
+                } else {
+                    mNonActionItems.add(item);
+                }
+            }
+        } else {
+            // Nobody flagged anything, everything is a non-action item.
+            // (This happens during a first pass with no action-item presenters.)
+            mActionItems.clear();
+            mNonActionItems.clear();
+            mNonActionItems.addAll(getVisibleItems());
+        }
+        mIsActionItemsStale = false;
+    }
+
+    ArrayList<MenuItemImpl> getActionItems() {
+        flagActionItems();
+        return mActionItems;
+    }
+
+    ArrayList<MenuItemImpl> getNonActionItems() {
+        flagActionItems();
+        return mNonActionItems;
+    }
+
+    public void clearHeader() {
+        mHeaderIcon = null;
+        mHeaderTitle = null;
+        mHeaderView = null;
+
+        onItemsChanged(false);
+    }
+
+    private void setHeaderInternal(final int titleRes, final CharSequence title, final int iconRes,
+            final Drawable icon, final View view) {
+        final Resources r = getResources();
+
+        if (view != null) {
+            mHeaderView = view;
+
+            // If using a custom view, then the title and icon aren't used
+            mHeaderTitle = null;
+            mHeaderIcon = null;
+        } else {
+            if (titleRes > 0) {
+                mHeaderTitle = r.getText(titleRes);
+            } else if (title != null) {
+                mHeaderTitle = title;
+            }
+
+            if (iconRes > 0) {
+                mHeaderIcon = r.getDrawable(iconRes);
+            } else if (icon != null) {
+                mHeaderIcon = icon;
+            }
+
+            // If using the title or icon, then a custom view isn't used
+            mHeaderView = null;
+        }
+
+        // Notify of change
+        onItemsChanged(false);
+    }
+
+    /**
+     * Sets the header's title. This replaces the header view. Called by the
+     * builder-style methods of subclasses.
+     *
+     * @param title The new title.
+     * @return This MenuBuilder so additional setters can be called.
+     */
+    protected MenuBuilder setHeaderTitleInt(CharSequence title) {
+        setHeaderInternal(0, title, 0, null, null);
+        return this;
+    }
+
+    /**
+     * Sets the header's title. This replaces the header view. Called by the
+     * builder-style methods of subclasses.
+     *
+     * @param titleRes The new title (as a resource ID).
+     * @return This MenuBuilder so additional setters can be called.
+     */
+    protected MenuBuilder setHeaderTitleInt(int titleRes) {
+        setHeaderInternal(titleRes, null, 0, null, null);
+        return this;
+    }
+
+    /**
+     * Sets the header's icon. This replaces the header view. Called by the
+     * builder-style methods of subclasses.
+     *
+     * @param icon The new icon.
+     * @return This MenuBuilder so additional setters can be called.
+     */
+    protected MenuBuilder setHeaderIconInt(Drawable icon) {
+        setHeaderInternal(0, null, 0, icon, null);
+        return this;
+    }
+
+    /**
+     * Sets the header's icon. This replaces the header view. Called by the
+     * builder-style methods of subclasses.
+     *
+     * @param iconRes The new icon (as a resource ID).
+     * @return This MenuBuilder so additional setters can be called.
+     */
+    protected MenuBuilder setHeaderIconInt(int iconRes) {
+        setHeaderInternal(0, null, iconRes, null, null);
+        return this;
+    }
+
+    /**
+     * Sets the header's view. This replaces the title and icon. Called by the
+     * builder-style methods of subclasses.
+     *
+     * @param view The new view.
+     * @return This MenuBuilder so additional setters can be called.
+     */
+    protected MenuBuilder setHeaderViewInt(View view) {
+        setHeaderInternal(0, null, 0, null, view);
+        return this;
+    }
+
+    public CharSequence getHeaderTitle() {
+        return mHeaderTitle;
+    }
+
+    public Drawable getHeaderIcon() {
+        return mHeaderIcon;
+    }
+
+    public View getHeaderView() {
+        return mHeaderView;
+    }
+
+    /**
+     * Gets the root menu (if this is a submenu, find its root menu).
+     * @return The root menu.
+     */
+    public MenuBuilder getRootMenu() {
+        return this;
+    }
+
+    /**
+     * Sets the current menu info that is set on all items added to this menu
+     * (until this is called again with different menu info, in which case that
+     * one will be added to all subsequent item additions).
+     *
+     * @param menuInfo The extra menu information to add.
+     */
+    public void setCurrentMenuInfo(ContextMenuInfo menuInfo) {
+        mCurrentMenuInfo = menuInfo;
+    }
+
+    void setOptionalIconsVisible(boolean visible) {
+        mOptionalIconsVisible = visible;
+    }
+
+    boolean getOptionalIconsVisible() {
+        return mOptionalIconsVisible;
+    }
+
+    public boolean expandItemActionView(MenuItemImpl item) {
+        if (mPresenters.isEmpty()) return false;
+
+        boolean expanded = false;
+
+        stopDispatchingItemsChanged();
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter presenter = ref.get();
+            if (presenter == null) {
+                mPresenters.remove(ref);
+            } else if ((expanded = presenter.expandItemActionView(this, item))) {
+                break;
+            }
+        }
+        startDispatchingItemsChanged();
+
+        if (expanded) {
+            mExpandedItem = item;
+        }
+        return expanded;
+    }
+
+    public boolean collapseItemActionView(MenuItemImpl item) {
+        if (mPresenters.isEmpty() || mExpandedItem != item) return false;
+
+        boolean collapsed = false;
+
+        stopDispatchingItemsChanged();
+        for (WeakReference<MenuPresenter> ref : mPresenters) {
+            final MenuPresenter presenter = ref.get();
+            if (presenter == null) {
+                mPresenters.remove(ref);
+            } else if ((collapsed = presenter.collapseItemActionView(this, item))) {
+                break;
+            }
+        }
+        startDispatchingItemsChanged();
+
+        if (collapsed) {
+            mExpandedItem = null;
+        }
+        return collapsed;
+    }
+
+    public MenuItemImpl getExpandedItem() {
+        return mExpandedItem;
+    }
+
+    public boolean bindNativeOverflow(android.view.Menu menu, android.view.MenuItem.OnMenuItemClickListener listener, HashMap<android.view.MenuItem, MenuItemImpl> map) {
+        final List<MenuItemImpl> nonActionItems = getNonActionItems();
+        if (nonActionItems == null || nonActionItems.size() == 0) {
+            return false;
+        }
+
+        boolean visible = false;
+        menu.clear();
+        for (MenuItemImpl nonActionItem : nonActionItems) {
+            if (!nonActionItem.isVisible()) {
+                continue;
+            }
+            visible = true;
+
+            android.view.MenuItem nativeItem;
+            if (nonActionItem.hasSubMenu()) {
+                android.view.SubMenu nativeSub = menu.addSubMenu(nonActionItem.getGroupId(), nonActionItem.getItemId(),
+                        nonActionItem.getOrder(), nonActionItem.getTitle());
+
+                SubMenuBuilder subMenu = (SubMenuBuilder)nonActionItem.getSubMenu();
+                for (MenuItemImpl subItem : subMenu.getVisibleItems()) {
+                    android.view.MenuItem nativeSubItem = nativeSub.add(subItem.getGroupId(), subItem.getItemId(),
+                            subItem.getOrder(), subItem.getTitle());
+
+                    nativeSubItem.setIcon(subItem.getIcon());
+                    nativeSubItem.setOnMenuItemClickListener(listener);
+                    nativeSubItem.setEnabled(subItem.isEnabled());
+                    nativeSubItem.setIntent(subItem.getIntent());
+                    nativeSubItem.setNumericShortcut(subItem.getNumericShortcut());
+                    nativeSubItem.setAlphabeticShortcut(subItem.getAlphabeticShortcut());
+                    nativeSubItem.setTitleCondensed(subItem.getTitleCondensed());
+                    nativeSubItem.setCheckable(subItem.isCheckable());
+                    nativeSubItem.setChecked(subItem.isChecked());
+
+                    if (subItem.isExclusiveCheckable()) {
+                        nativeSub.setGroupCheckable(subItem.getGroupId(), true, true);
+                    }
+
+                    map.put(nativeSubItem, subItem);
+                }
+
+                nativeItem = nativeSub.getItem();
+            } else {
+                nativeItem = menu.add(nonActionItem.getGroupId(), nonActionItem.getItemId(),
+                        nonActionItem.getOrder(), nonActionItem.getTitle());
+            }
+            nativeItem.setIcon(nonActionItem.getIcon());
+            nativeItem.setOnMenuItemClickListener(listener);
+            nativeItem.setEnabled(nonActionItem.isEnabled());
+            nativeItem.setIntent(nonActionItem.getIntent());
+            nativeItem.setNumericShortcut(nonActionItem.getNumericShortcut());
+            nativeItem.setAlphabeticShortcut(nonActionItem.getAlphabeticShortcut());
+            nativeItem.setTitleCondensed(nonActionItem.getTitleCondensed());
+            nativeItem.setCheckable(nonActionItem.isCheckable());
+            nativeItem.setChecked(nonActionItem.isChecked());
+
+            if (nonActionItem.isExclusiveCheckable()) {
+                menu.setGroupCheckable(nonActionItem.getGroupId(), true, true);
+            }
+
+            map.put(nativeItem, nonActionItem);
+        }
+        return visible;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemImpl.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemImpl.java
new file mode 100644 (file)
index 0000000..f5359fb
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewDebug;
+import android.widget.LinearLayout;
+
+import com.actionbarsherlock.view.ActionProvider;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.SubMenu;
+
+/**
+ * @hide
+ */
+public final class MenuItemImpl implements MenuItem {
+    private static final String TAG = "MenuItemImpl";
+
+    private static final int SHOW_AS_ACTION_MASK = SHOW_AS_ACTION_NEVER |
+            SHOW_AS_ACTION_IF_ROOM |
+            SHOW_AS_ACTION_ALWAYS;
+
+    private final int mId;
+    private final int mGroup;
+    private final int mCategoryOrder;
+    private final int mOrdering;
+    private CharSequence mTitle;
+    private CharSequence mTitleCondensed;
+    private Intent mIntent;
+    private char mShortcutNumericChar;
+    private char mShortcutAlphabeticChar;
+
+    /** The icon's drawable which is only created as needed */
+    private Drawable mIconDrawable;
+    /**
+     * The icon's resource ID which is used to get the Drawable when it is
+     * needed (if the Drawable isn't already obtained--only one of the two is
+     * needed).
+     */
+    private int mIconResId = NO_ICON;
+
+    /** The menu to which this item belongs */
+    private MenuBuilder mMenu;
+    /** If this item should launch a sub menu, this is the sub menu to launch */
+    private SubMenuBuilder mSubMenu;
+
+    private Runnable mItemCallback;
+    private MenuItem.OnMenuItemClickListener mClickListener;
+
+    private int mFlags = ENABLED;
+    private static final int CHECKABLE      = 0x00000001;
+    private static final int CHECKED        = 0x00000002;
+    private static final int EXCLUSIVE      = 0x00000004;
+    private static final int HIDDEN         = 0x00000008;
+    private static final int ENABLED        = 0x00000010;
+    private static final int IS_ACTION      = 0x00000020;
+
+    private int mShowAsAction = SHOW_AS_ACTION_NEVER;
+
+    private View mActionView;
+    private ActionProvider mActionProvider;
+    private OnActionExpandListener mOnActionExpandListener;
+    private boolean mIsActionViewExpanded = false;
+
+    /** Used for the icon resource ID if this item does not have an icon */
+    static final int NO_ICON = 0;
+
+    /**
+     * Current use case is for context menu: Extra information linked to the
+     * View that added this item to the context menu.
+     */
+    private ContextMenuInfo mMenuInfo;
+
+    private static String sPrependShortcutLabel;
+    private static String sEnterShortcutLabel;
+    private static String sDeleteShortcutLabel;
+    private static String sSpaceShortcutLabel;
+
+
+    /**
+     * Instantiates this menu item.
+     *
+     * @param menu
+     * @param group Item ordering grouping control. The item will be added after
+     *            all other items whose order is <= this number, and before any
+     *            that are larger than it. This can also be used to define
+     *            groups of items for batch state changes. Normally use 0.
+     * @param id Unique item ID. Use 0 if you do not need a unique ID.
+     * @param categoryOrder The ordering for this item.
+     * @param title The text to display for the item.
+     */
+    MenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
+            CharSequence title, int showAsAction) {
+
+        /* TODO if (sPrependShortcutLabel == null) {
+            // This is instantiated from the UI thread, so no chance of sync issues
+            sPrependShortcutLabel = menu.getContext().getResources().getString(
+                    com.android.internal.R.string.prepend_shortcut_label);
+            sEnterShortcutLabel = menu.getContext().getResources().getString(
+                    com.android.internal.R.string.menu_enter_shortcut_label);
+            sDeleteShortcutLabel = menu.getContext().getResources().getString(
+                    com.android.internal.R.string.menu_delete_shortcut_label);
+            sSpaceShortcutLabel = menu.getContext().getResources().getString(
+                    com.android.internal.R.string.menu_space_shortcut_label);
+        }*/
+
+        mMenu = menu;
+        mId = id;
+        mGroup = group;
+        mCategoryOrder = categoryOrder;
+        mOrdering = ordering;
+        mTitle = title;
+        mShowAsAction = showAsAction;
+    }
+
+    /**
+     * Invokes the item by calling various listeners or callbacks.
+     *
+     * @return true if the invocation was handled, false otherwise
+     */
+    public boolean invoke() {
+        if (mClickListener != null &&
+            mClickListener.onMenuItemClick(this)) {
+            return true;
+        }
+
+        if (mMenu.dispatchMenuItemSelected(mMenu.getRootMenu(), this)) {
+            return true;
+        }
+
+        if (mItemCallback != null) {
+            mItemCallback.run();
+            return true;
+        }
+
+        if (mIntent != null) {
+            try {
+                mMenu.getContext().startActivity(mIntent);
+                return true;
+            } catch (ActivityNotFoundException e) {
+                Log.e(TAG, "Can't find activity to handle intent; ignoring", e);
+            }
+        }
+
+        if (mActionProvider != null && mActionProvider.onPerformDefaultAction()) {
+            return true;
+        }
+
+        return false;
+    }
+
+    public boolean isEnabled() {
+        return (mFlags & ENABLED) != 0;
+    }
+
+    public MenuItem setEnabled(boolean enabled) {
+        if (enabled) {
+            mFlags |= ENABLED;
+        } else {
+            mFlags &= ~ENABLED;
+        }
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    public int getGroupId() {
+        return mGroup;
+    }
+
+    @ViewDebug.CapturedViewProperty
+    public int getItemId() {
+        return mId;
+    }
+
+    public int getOrder() {
+        return mCategoryOrder;
+    }
+
+    public int getOrdering() {
+        return mOrdering;
+    }
+
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    public MenuItem setIntent(Intent intent) {
+        mIntent = intent;
+        return this;
+    }
+
+    Runnable getCallback() {
+        return mItemCallback;
+    }
+
+    public MenuItem setCallback(Runnable callback) {
+        mItemCallback = callback;
+        return this;
+    }
+
+    public char getAlphabeticShortcut() {
+        return mShortcutAlphabeticChar;
+    }
+
+    public MenuItem setAlphabeticShortcut(char alphaChar) {
+        if (mShortcutAlphabeticChar == alphaChar) return this;
+
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    public char getNumericShortcut() {
+        return mShortcutNumericChar;
+    }
+
+    public MenuItem setNumericShortcut(char numericChar) {
+        if (mShortcutNumericChar == numericChar) return this;
+
+        mShortcutNumericChar = numericChar;
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    public MenuItem setShortcut(char numericChar, char alphaChar) {
+        mShortcutNumericChar = numericChar;
+        mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    /**
+     * @return The active shortcut (based on QWERTY-mode of the menu).
+     */
+    char getShortcut() {
+        return (mMenu.isQwertyMode() ? mShortcutAlphabeticChar : mShortcutNumericChar);
+    }
+
+    /**
+     * @return The label to show for the shortcut. This includes the chording
+     *         key (for example 'Menu+a'). Also, any non-human readable
+     *         characters should be human readable (for example 'Menu+enter').
+     */
+    String getShortcutLabel() {
+
+        char shortcut = getShortcut();
+        if (shortcut == 0) {
+            return "";
+        }
+
+        StringBuilder sb = new StringBuilder(sPrependShortcutLabel);
+        switch (shortcut) {
+
+            case '\n':
+                sb.append(sEnterShortcutLabel);
+                break;
+
+            case '\b':
+                sb.append(sDeleteShortcutLabel);
+                break;
+
+            case ' ':
+                sb.append(sSpaceShortcutLabel);
+                break;
+
+            default:
+                sb.append(shortcut);
+                break;
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * @return Whether this menu item should be showing shortcuts (depends on
+     *         whether the menu should show shortcuts and whether this item has
+     *         a shortcut defined)
+     */
+    boolean shouldShowShortcut() {
+        // Show shortcuts if the menu is supposed to show shortcuts AND this item has a shortcut
+        return mMenu.isShortcutsVisible() && (getShortcut() != 0);
+    }
+
+    public SubMenu getSubMenu() {
+        return mSubMenu;
+    }
+
+    public boolean hasSubMenu() {
+        return mSubMenu != null;
+    }
+
+    void setSubMenu(SubMenuBuilder subMenu) {
+        mSubMenu = subMenu;
+
+        subMenu.setHeaderTitle(getTitle());
+    }
+
+    @ViewDebug.CapturedViewProperty
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Gets the title for a particular {@link ItemView}
+     *
+     * @param itemView The ItemView that is receiving the title
+     * @return Either the title or condensed title based on what the ItemView
+     *         prefers
+     */
+    CharSequence getTitleForItemView(MenuView.ItemView itemView) {
+        return ((itemView != null) && itemView.prefersCondensedTitle())
+                ? getTitleCondensed()
+                : getTitle();
+    }
+
+    public MenuItem setTitle(CharSequence title) {
+        mTitle = title;
+
+        mMenu.onItemsChanged(false);
+
+        if (mSubMenu != null) {
+            mSubMenu.setHeaderTitle(title);
+        }
+
+        return this;
+    }
+
+    public MenuItem setTitle(int title) {
+        return setTitle(mMenu.getContext().getString(title));
+    }
+
+    public CharSequence getTitleCondensed() {
+        return mTitleCondensed != null ? mTitleCondensed : mTitle;
+    }
+
+    public MenuItem setTitleCondensed(CharSequence title) {
+        mTitleCondensed = title;
+
+        // Could use getTitle() in the loop below, but just cache what it would do here
+        if (title == null) {
+            title = mTitle;
+        }
+
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    public Drawable getIcon() {
+        if (mIconDrawable != null) {
+            return mIconDrawable;
+        }
+
+        if (mIconResId != NO_ICON) {
+            return mMenu.getResources().getDrawable(mIconResId);
+        }
+
+        return null;
+    }
+
+    public MenuItem setIcon(Drawable icon) {
+        mIconResId = NO_ICON;
+        mIconDrawable = icon;
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    public MenuItem setIcon(int iconResId) {
+        mIconDrawable = null;
+        mIconResId = iconResId;
+
+        // If we have a view, we need to push the Drawable to them
+        mMenu.onItemsChanged(false);
+
+        return this;
+    }
+
+    public boolean isCheckable() {
+        return (mFlags & CHECKABLE) == CHECKABLE;
+    }
+
+    public MenuItem setCheckable(boolean checkable) {
+        final int oldFlags = mFlags;
+        mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
+        if (oldFlags != mFlags) {
+            mMenu.onItemsChanged(false);
+        }
+
+        return this;
+    }
+
+    public void setExclusiveCheckable(boolean exclusive) {
+        mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
+    }
+
+    public boolean isExclusiveCheckable() {
+        return (mFlags & EXCLUSIVE) != 0;
+    }
+
+    public boolean isChecked() {
+        return (mFlags & CHECKED) == CHECKED;
+    }
+
+    public MenuItem setChecked(boolean checked) {
+        if ((mFlags & EXCLUSIVE) != 0) {
+            // Call the method on the Menu since it knows about the others in this
+            // exclusive checkable group
+            mMenu.setExclusiveItemChecked(this);
+        } else {
+            setCheckedInt(checked);
+        }
+
+        return this;
+    }
+
+    void setCheckedInt(boolean checked) {
+        final int oldFlags = mFlags;
+        mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
+        if (oldFlags != mFlags) {
+            mMenu.onItemsChanged(false);
+        }
+    }
+
+    public boolean isVisible() {
+        return (mFlags & HIDDEN) == 0;
+    }
+
+    /**
+     * Changes the visibility of the item. This method DOES NOT notify the
+     * parent menu of a change in this item, so this should only be called from
+     * methods that will eventually trigger this change.  If unsure, use {@link #setVisible(boolean)}
+     * instead.
+     *
+     * @param shown Whether to show (true) or hide (false).
+     * @return Whether the item's shown state was changed
+     */
+    boolean setVisibleInt(boolean shown) {
+        final int oldFlags = mFlags;
+        mFlags = (mFlags & ~HIDDEN) | (shown ? 0 : HIDDEN);
+        return oldFlags != mFlags;
+    }
+
+    public MenuItem setVisible(boolean shown) {
+        // Try to set the shown state to the given state. If the shown state was changed
+        // (i.e. the previous state isn't the same as given state), notify the parent menu that
+        // the shown state has changed for this item
+        if (setVisibleInt(shown)) mMenu.onItemVisibleChanged(this);
+
+        return this;
+    }
+
+   public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener clickListener) {
+        mClickListener = clickListener;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return mTitle.toString();
+    }
+
+    void setMenuInfo(ContextMenuInfo menuInfo) {
+        mMenuInfo = menuInfo;
+    }
+
+    public ContextMenuInfo getMenuInfo() {
+        return mMenuInfo;
+    }
+
+    public void actionFormatChanged() {
+        mMenu.onItemActionRequestChanged(this);
+    }
+
+    /**
+     * @return Whether the menu should show icons for menu items.
+     */
+    public boolean shouldShowIcon() {
+        return mMenu.getOptionalIconsVisible();
+    }
+
+    public boolean isActionButton() {
+        return (mFlags & IS_ACTION) == IS_ACTION;
+    }
+
+    public boolean requestsActionButton() {
+        return (mShowAsAction & SHOW_AS_ACTION_IF_ROOM) == SHOW_AS_ACTION_IF_ROOM;
+    }
+
+    public boolean requiresActionButton() {
+        return (mShowAsAction & SHOW_AS_ACTION_ALWAYS) == SHOW_AS_ACTION_ALWAYS;
+    }
+
+    public void setIsActionButton(boolean isActionButton) {
+        if (isActionButton) {
+            mFlags |= IS_ACTION;
+        } else {
+            mFlags &= ~IS_ACTION;
+        }
+    }
+
+    public boolean showsTextAsAction() {
+        return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT;
+    }
+
+    public void setShowAsAction(int actionEnum) {
+        switch (actionEnum & SHOW_AS_ACTION_MASK) {
+            case SHOW_AS_ACTION_ALWAYS:
+            case SHOW_AS_ACTION_IF_ROOM:
+            case SHOW_AS_ACTION_NEVER:
+                // Looks good!
+                break;
+
+            default:
+                // Mutually exclusive options selected!
+                throw new IllegalArgumentException("SHOW_AS_ACTION_ALWAYS, SHOW_AS_ACTION_IF_ROOM,"
+                        + " and SHOW_AS_ACTION_NEVER are mutually exclusive.");
+        }
+        mShowAsAction = actionEnum;
+        mMenu.onItemActionRequestChanged(this);
+    }
+
+    public MenuItem setActionView(View view) {
+        mActionView = view;
+        mActionProvider = null;
+        if (view != null && view.getId() == View.NO_ID && mId > 0) {
+            view.setId(mId);
+        }
+        mMenu.onItemActionRequestChanged(this);
+        return this;
+    }
+
+    public MenuItem setActionView(int resId) {
+        final Context context = mMenu.getContext();
+        final LayoutInflater inflater = LayoutInflater.from(context);
+        setActionView(inflater.inflate(resId, new LinearLayout(context), false));
+        return this;
+    }
+
+    public View getActionView() {
+        if (mActionView != null) {
+            return mActionView;
+        } else if (mActionProvider != null) {
+            mActionView = mActionProvider.onCreateActionView();
+            return mActionView;
+        } else {
+            return null;
+        }
+    }
+
+    public ActionProvider getActionProvider() {
+        return mActionProvider;
+    }
+
+    public MenuItem setActionProvider(ActionProvider actionProvider) {
+        mActionView = null;
+        mActionProvider = actionProvider;
+        mMenu.onItemsChanged(true); // Measurement can be changed
+        return this;
+    }
+
+    @Override
+    public MenuItem setShowAsActionFlags(int actionEnum) {
+        setShowAsAction(actionEnum);
+        return this;
+    }
+
+    @Override
+    public boolean expandActionView() {
+        if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0 || mActionView == null) {
+            return false;
+        }
+
+        if (mOnActionExpandListener == null ||
+                mOnActionExpandListener.onMenuItemActionExpand(this)) {
+            return mMenu.expandItemActionView(this);
+        }
+
+        return false;
+    }
+
+    @Override
+    public boolean collapseActionView() {
+        if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0) {
+            return false;
+        }
+        if (mActionView == null) {
+            // We're already collapsed if we have no action view.
+            return true;
+        }
+
+        if (mOnActionExpandListener == null ||
+                mOnActionExpandListener.onMenuItemActionCollapse(this)) {
+            return mMenu.collapseItemActionView(this);
+        }
+
+        return false;
+    }
+
+    @Override
+    public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
+        mOnActionExpandListener = listener;
+        return this;
+    }
+
+    public boolean hasCollapsibleActionView() {
+        return (mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) != 0 && mActionView != null;
+    }
+
+    public void setActionViewExpanded(boolean isExpanded) {
+        mIsActionViewExpanded = isExpanded;
+        mMenu.onItemsChanged(false);
+    }
+
+    public boolean isActionViewExpanded() {
+        return mIsActionViewExpanded;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuItemWrapper.java
new file mode 100644 (file)
index 0000000..907a7aa
--- /dev/null
@@ -0,0 +1,292 @@
+package com.actionbarsherlock.internal.view.menu;
+
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.view.ContextMenu.ContextMenuInfo;
+import com.actionbarsherlock.internal.view.ActionProviderWrapper;
+import com.actionbarsherlock.view.ActionProvider;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.SubMenu;
+
+public class MenuItemWrapper implements MenuItem, android.view.MenuItem.OnMenuItemClickListener {
+    private final android.view.MenuItem mNativeItem;
+    private SubMenu mSubMenu = null;
+    private OnMenuItemClickListener mMenuItemClickListener = null;
+    private OnActionExpandListener mActionExpandListener = null;
+    private android.view.MenuItem.OnActionExpandListener mNativeActionExpandListener = null;
+
+
+    public MenuItemWrapper(android.view.MenuItem nativeItem) {
+        if (nativeItem == null) {
+            throw new IllegalStateException("Wrapped menu item cannot be null.");
+        }
+        mNativeItem = nativeItem;
+    }
+
+
+    @Override
+    public int getItemId() {
+        return mNativeItem.getItemId();
+    }
+
+    @Override
+    public int getGroupId() {
+        return mNativeItem.getGroupId();
+    }
+
+    @Override
+    public int getOrder() {
+        return mNativeItem.getOrder();
+    }
+
+    @Override
+    public MenuItem setTitle(CharSequence title) {
+        mNativeItem.setTitle(title);
+        return this;
+    }
+
+    @Override
+    public MenuItem setTitle(int title) {
+        mNativeItem.setTitle(title);
+        return this;
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mNativeItem.getTitle();
+    }
+
+    @Override
+    public MenuItem setTitleCondensed(CharSequence title) {
+        mNativeItem.setTitleCondensed(title);
+        return this;
+    }
+
+    @Override
+    public CharSequence getTitleCondensed() {
+        return mNativeItem.getTitleCondensed();
+    }
+
+    @Override
+    public MenuItem setIcon(Drawable icon) {
+        mNativeItem.setIcon(icon);
+        return this;
+    }
+
+    @Override
+    public MenuItem setIcon(int iconRes) {
+        mNativeItem.setIcon(iconRes);
+        return this;
+    }
+
+    @Override
+    public Drawable getIcon() {
+        return mNativeItem.getIcon();
+    }
+
+    @Override
+    public MenuItem setIntent(Intent intent) {
+        mNativeItem.setIntent(intent);
+        return this;
+    }
+
+    @Override
+    public Intent getIntent() {
+        return mNativeItem.getIntent();
+    }
+
+    @Override
+    public MenuItem setShortcut(char numericChar, char alphaChar) {
+        mNativeItem.setShortcut(numericChar, alphaChar);
+        return this;
+    }
+
+    @Override
+    public MenuItem setNumericShortcut(char numericChar) {
+        mNativeItem.setNumericShortcut(numericChar);
+        return this;
+    }
+
+    @Override
+    public char getNumericShortcut() {
+        return mNativeItem.getNumericShortcut();
+    }
+
+    @Override
+    public MenuItem setAlphabeticShortcut(char alphaChar) {
+        mNativeItem.setAlphabeticShortcut(alphaChar);
+        return this;
+    }
+
+    @Override
+    public char getAlphabeticShortcut() {
+        return mNativeItem.getAlphabeticShortcut();
+    }
+
+    @Override
+    public MenuItem setCheckable(boolean checkable) {
+        mNativeItem.setCheckable(checkable);
+        return this;
+    }
+
+    @Override
+    public boolean isCheckable() {
+        return mNativeItem.isCheckable();
+    }
+
+    @Override
+    public MenuItem setChecked(boolean checked) {
+        mNativeItem.setChecked(checked);
+        return this;
+    }
+
+    @Override
+    public boolean isChecked() {
+        return mNativeItem.isChecked();
+    }
+
+    @Override
+    public MenuItem setVisible(boolean visible) {
+        mNativeItem.setVisible(visible);
+        return this;
+    }
+
+    @Override
+    public boolean isVisible() {
+        return mNativeItem.isVisible();
+    }
+
+    @Override
+    public MenuItem setEnabled(boolean enabled) {
+        mNativeItem.setEnabled(enabled);
+        return this;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return mNativeItem.isEnabled();
+    }
+
+    @Override
+    public boolean hasSubMenu() {
+        return mNativeItem.hasSubMenu();
+    }
+
+    @Override
+    public SubMenu getSubMenu() {
+        if (hasSubMenu() && (mSubMenu == null)) {
+            mSubMenu = new SubMenuWrapper(mNativeItem.getSubMenu());
+        }
+        return mSubMenu;
+    }
+
+    @Override
+    public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
+        mMenuItemClickListener = menuItemClickListener;
+        //Register ourselves as the listener to proxy
+        mNativeItem.setOnMenuItemClickListener(this);
+        return this;
+    }
+
+    @Override
+    public boolean onMenuItemClick(android.view.MenuItem item) {
+        if (mMenuItemClickListener != null) {
+            return mMenuItemClickListener.onMenuItemClick(this);
+        }
+        return false;
+    }
+
+    @Override
+    public ContextMenuInfo getMenuInfo() {
+        return mNativeItem.getMenuInfo();
+    }
+
+    @Override
+    public void setShowAsAction(int actionEnum) {
+        mNativeItem.setShowAsAction(actionEnum);
+    }
+
+    @Override
+    public MenuItem setShowAsActionFlags(int actionEnum) {
+        mNativeItem.setShowAsActionFlags(actionEnum);
+        return this;
+    }
+
+    @Override
+    public MenuItem setActionView(View view) {
+        mNativeItem.setActionView(view);
+        return this;
+    }
+
+    @Override
+    public MenuItem setActionView(int resId) {
+        mNativeItem.setActionView(resId);
+        return this;
+    }
+
+    @Override
+    public View getActionView() {
+        return mNativeItem.getActionView();
+    }
+
+    @Override
+    public MenuItem setActionProvider(ActionProvider actionProvider) {
+        mNativeItem.setActionProvider(new ActionProviderWrapper(actionProvider));
+        return this;
+    }
+
+    @Override
+    public ActionProvider getActionProvider() {
+        android.view.ActionProvider nativeProvider = mNativeItem.getActionProvider();
+        if (nativeProvider != null && nativeProvider instanceof ActionProviderWrapper) {
+            return ((ActionProviderWrapper)nativeProvider).unwrap();
+        }
+        return null;
+    }
+
+    @Override
+    public boolean expandActionView() {
+        return mNativeItem.expandActionView();
+    }
+
+    @Override
+    public boolean collapseActionView() {
+        return mNativeItem.collapseActionView();
+    }
+
+    @Override
+    public boolean isActionViewExpanded() {
+        return mNativeItem.isActionViewExpanded();
+    }
+
+    @Override
+    public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
+        mActionExpandListener = listener;
+
+        if (mNativeActionExpandListener == null) {
+            mNativeActionExpandListener = new android.view.MenuItem.OnActionExpandListener() {
+                @Override
+                public boolean onMenuItemActionExpand(android.view.MenuItem menuItem) {
+                    if (mActionExpandListener != null) {
+                        return mActionExpandListener.onMenuItemActionExpand(MenuItemWrapper.this);
+                    }
+                    return false;
+                }
+
+                @Override
+                public boolean onMenuItemActionCollapse(android.view.MenuItem menuItem) {
+                    if (mActionExpandListener != null) {
+                        return mActionExpandListener.onMenuItemActionCollapse(MenuItemWrapper.this);
+                    }
+                    return false;
+                }
+            };
+
+            //Register our inner-class as the listener to proxy method calls
+            mNativeItem.setOnActionExpandListener(mNativeActionExpandListener);
+        }
+
+        return this;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuPopupHelper.java
new file mode 100644 (file)
index 0000000..f030de3
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import java.util.ArrayList;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.DataSetObserver;
+import android.os.Parcelable;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ListAdapter;
+import android.widget.PopupWindow;
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
+import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
+import com.actionbarsherlock.internal.widget.IcsListPopupWindow;
+import com.actionbarsherlock.view.MenuItem;
+
+/**
+ * Presents a menu as a small, simple popup anchored to another view.
+ * @hide
+ */
+public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
+        ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
+        View_OnAttachStateChangeListener, MenuPresenter {
+    //UNUSED private static final String TAG = "MenuPopupHelper";
+
+    static final int ITEM_LAYOUT = R.layout.abs__popup_menu_item_layout;
+
+    private Context mContext;
+    private LayoutInflater mInflater;
+    private IcsListPopupWindow mPopup;
+    private MenuBuilder mMenu;
+    private int mPopupMaxWidth;
+    private View mAnchorView;
+    private boolean mOverflowOnly;
+    private ViewTreeObserver mTreeObserver;
+
+    private MenuAdapter mAdapter;
+
+    private Callback mPresenterCallback;
+
+    boolean mForceShowIcon;
+
+    private ViewGroup mMeasureParent;
+
+    public MenuPopupHelper(Context context, MenuBuilder menu) {
+        this(context, menu, null, false);
+    }
+
+    public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
+        this(context, menu, anchorView, false);
+    }
+
+    public MenuPopupHelper(Context context, MenuBuilder menu,
+            View anchorView, boolean overflowOnly) {
+        mContext = context;
+        mInflater = LayoutInflater.from(context);
+        mMenu = menu;
+        mOverflowOnly = overflowOnly;
+
+        final Resources res = context.getResources();
+        mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
+                res.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth));
+
+        mAnchorView = anchorView;
+
+        menu.addMenuPresenter(this);
+    }
+
+    public void setAnchorView(View anchor) {
+        mAnchorView = anchor;
+    }
+
+    public void setForceShowIcon(boolean forceShow) {
+        mForceShowIcon = forceShow;
+    }
+
+    public void show() {
+        if (!tryShow()) {
+            throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
+        }
+    }
+
+    public boolean tryShow() {
+        mPopup = new IcsListPopupWindow(mContext, null, R.attr.popupMenuStyle);
+        mPopup.setOnDismissListener(this);
+        mPopup.setOnItemClickListener(this);
+
+        mAdapter = new MenuAdapter(mMenu);
+        mPopup.setAdapter(mAdapter);
+        mPopup.setModal(true);
+
+        View anchor = mAnchorView;
+        if (anchor != null) {
+            final boolean addGlobalListener = mTreeObserver == null;
+            mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
+            if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
+            ((View_HasStateListenerSupport)anchor).addOnAttachStateChangeListener(this);
+            mPopup.setAnchorView(anchor);
+        } else {
+            return false;
+        }
+
+        mPopup.setContentWidth(Math.min(measureContentWidth(mAdapter), mPopupMaxWidth));
+        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+        mPopup.show();
+        mPopup.getListView().setOnKeyListener(this);
+        return true;
+    }
+
+    public void dismiss() {
+        if (isShowing()) {
+            mPopup.dismiss();
+        }
+    }
+
+    public void onDismiss() {
+        mPopup = null;
+        mMenu.close();
+        if (mTreeObserver != null) {
+            if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
+            mTreeObserver.removeGlobalOnLayoutListener(this);
+            mTreeObserver = null;
+        }
+        ((View_HasStateListenerSupport)mAnchorView).removeOnAttachStateChangeListener(this);
+    }
+
+    public boolean isShowing() {
+        return mPopup != null && mPopup.isShowing();
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        MenuAdapter adapter = mAdapter;
+        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
+    }
+
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
+            dismiss();
+            return true;
+        }
+        return false;
+    }
+
+    private int measureContentWidth(ListAdapter adapter) {
+        // Menus don't tend to be long, so this is more sane than it looks.
+        int width = 0;
+        View itemView = null;
+        int itemType = 0;
+        final int widthMeasureSpec =
+            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec =
+            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int count = adapter.getCount();
+        for (int i = 0; i < count; i++) {
+            final int positionType = adapter.getItemViewType(i);
+            if (positionType != itemType) {
+                itemType = positionType;
+                itemView = null;
+            }
+            if (mMeasureParent == null) {
+                mMeasureParent = new FrameLayout(mContext);
+            }
+            itemView = adapter.getView(i, itemView, mMeasureParent);
+            itemView.measure(widthMeasureSpec, heightMeasureSpec);
+            width = Math.max(width, itemView.getMeasuredWidth());
+        }
+        return width;
+    }
+
+    @Override
+    public void onGlobalLayout() {
+        if (isShowing()) {
+            final View anchor = mAnchorView;
+            if (anchor == null || !anchor.isShown()) {
+                dismiss();
+            } else if (isShowing()) {
+                // Recompute window size and position
+                mPopup.show();
+            }
+        }
+    }
+
+    @Override
+    public void onViewAttachedToWindow(View v) {
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View v) {
+        if (mTreeObserver != null) {
+            if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
+            mTreeObserver.removeGlobalOnLayoutListener(this);
+        }
+        ((View_HasStateListenerSupport)v).removeOnAttachStateChangeListener(this);
+    }
+
+    @Override
+    public void initForMenu(Context context, MenuBuilder menu) {
+        // Don't need to do anything; we added as a presenter in the constructor.
+    }
+
+    @Override
+    public MenuView getMenuView(ViewGroup root) {
+        throw new UnsupportedOperationException("MenuPopupHelpers manage their own views");
+    }
+
+    @Override
+    public void updateMenuView(boolean cleared) {
+        if (mAdapter != null) mAdapter.notifyDataSetChanged();
+    }
+
+    @Override
+    public void setCallback(Callback cb) {
+        mPresenterCallback = cb;
+    }
+
+    @Override
+    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+        if (subMenu.hasVisibleItems()) {
+            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
+            subPopup.setCallback(mPresenterCallback);
+
+            boolean preserveIconSpacing = false;
+            final int count = subMenu.size();
+            for (int i = 0; i < count; i++) {
+                MenuItem childItem = subMenu.getItem(i);
+                if (childItem.isVisible() && childItem.getIcon() != null) {
+                    preserveIconSpacing = true;
+                    break;
+                }
+            }
+            subPopup.setForceShowIcon(preserveIconSpacing);
+
+            if (subPopup.tryShow()) {
+                if (mPresenterCallback != null) {
+                    mPresenterCallback.onOpenSubMenu(subMenu);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        // Only care about the (sub)menu we're presenting.
+        if (menu != mMenu) return;
+
+        dismiss();
+        if (mPresenterCallback != null) {
+            mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
+        }
+    }
+
+    @Override
+    public boolean flagActionItems() {
+        return false;
+    }
+
+    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    @Override
+    public int getId() {
+        return 0;
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        return null;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+    }
+
+    private class MenuAdapter extends BaseAdapter {
+        private MenuBuilder mAdapterMenu;
+        private int mExpandedIndex = -1;
+
+        public MenuAdapter(MenuBuilder menu) {
+            mAdapterMenu = menu;
+            registerDataSetObserver(new ExpandedIndexObserver());
+            findExpandedIndex();
+        }
+
+        public int getCount() {
+            ArrayList<MenuItemImpl> items = mOverflowOnly ?
+                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
+            if (mExpandedIndex < 0) {
+                return items.size();
+            }
+            return items.size() - 1;
+        }
+
+        public MenuItemImpl getItem(int position) {
+            ArrayList<MenuItemImpl> items = mOverflowOnly ?
+                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
+            if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
+                position++;
+            }
+            return items.get(position);
+        }
+
+        public long getItemId(int position) {
+            // Since a menu item's ID is optional, we'll use the position as an
+            // ID for the item in the AdapterView
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
+            }
+
+            MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+            if (mForceShowIcon) {
+                ((ListMenuItemView) convertView).setForceShowIcon(true);
+            }
+            itemView.initialize(getItem(position), 0);
+            return convertView;
+        }
+
+        void findExpandedIndex() {
+            final MenuItemImpl expandedItem = mMenu.getExpandedItem();
+            if (expandedItem != null) {
+                final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
+                final int count = items.size();
+                for (int i = 0; i < count; i++) {
+                    final MenuItemImpl item = items.get(i);
+                    if (item == expandedItem) {
+                        mExpandedIndex = i;
+                        return;
+                    }
+                }
+            }
+            mExpandedIndex = -1;
+        }
+    }
+
+    private class ExpandedIndexObserver extends DataSetObserver {
+        @Override
+        public void onChanged() {
+            mAdapter.findExpandedIndex();
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuPresenter.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuPresenter.java
new file mode 100644 (file)
index 0000000..c3f3547
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import android.content.Context;
+import android.os.Parcelable;
+import android.view.ViewGroup;
+
+/**
+ * A MenuPresenter is responsible for building views for a Menu object.
+ * It takes over some responsibility from the old style monolithic MenuBuilder class.
+ */
+public interface MenuPresenter {
+    /**
+     * Called by menu implementation to notify another component of open/close events.
+     */
+    public interface Callback {
+        /**
+         * Called when a menu is closing.
+         * @param menu
+         * @param allMenusAreClosing
+         */
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing);
+
+        /**
+         * Called when a submenu opens. Useful for notifying the application
+         * of menu state so that it does not attempt to hide the action bar
+         * while a submenu is open or similar.
+         *
+         * @param subMenu Submenu currently being opened
+         * @return true if the Callback will handle presenting the submenu, false if
+         *         the presenter should attempt to do so.
+         */
+        public boolean onOpenSubMenu(MenuBuilder subMenu);
+    }
+
+    /**
+     * Initialize this presenter for the given context and menu.
+     * This method is called by MenuBuilder when a presenter is
+     * added. See {@link MenuBuilder#addMenuPresenter(MenuPresenter)}
+     *
+     * @param context Context for this presenter; used for view creation and resource management
+     * @param menu Menu to host
+     */
+    public void initForMenu(Context context, MenuBuilder menu);
+
+    /**
+     * Retrieve a MenuView to display the menu specified in
+     * {@link #initForMenu(Context, Menu)}.
+     *
+     * @param root Intended parent of the MenuView.
+     * @return A freshly created MenuView.
+     */
+    public MenuView getMenuView(ViewGroup root);
+
+    /**
+     * Update the menu UI in response to a change. Called by
+     * MenuBuilder during the normal course of operation.
+     *
+     * @param cleared true if the menu was entirely cleared
+     */
+    public void updateMenuView(boolean cleared);
+
+    /**
+     * Set a callback object that will be notified of menu events
+     * related to this specific presentation.
+     * @param cb Callback that will be notified of future events
+     */
+    public void setCallback(Callback cb);
+
+    /**
+     * Called by Menu implementations to indicate that a submenu item
+     * has been selected. An active Callback should be notified, and
+     * if applicable the presenter should present the submenu.
+     *
+     * @param subMenu SubMenu being opened
+     * @return true if the the event was handled, false otherwise.
+     */
+    public boolean onSubMenuSelected(SubMenuBuilder subMenu);
+
+    /**
+     * Called by Menu implementations to indicate that a menu or submenu is
+     * closing. Presenter implementations should close the representation
+     * of the menu indicated as necessary and notify a registered callback.
+     *
+     * @param menu Menu or submenu that is closing.
+     * @param allMenusAreClosing True if all associated menus are closing.
+     */
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing);
+
+    /**
+     * Called by Menu implementations to flag items that will be shown as actions.
+     * @return true if this presenter changed the action status of any items.
+     */
+    public boolean flagActionItems();
+
+    /**
+     * Called when a menu item with a collapsable action view should expand its action view.
+     *
+     * @param menu Menu containing the item to be expanded
+     * @param item Item to be expanded
+     * @return true if this presenter expanded the action view, false otherwise.
+     */
+    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item);
+
+    /**
+     * Called when a menu item with a collapsable action view should collapse its action view.
+     *
+     * @param menu Menu containing the item to be collapsed
+     * @param item Item to be collapsed
+     * @return true if this presenter collapsed the action view, false otherwise.
+     */
+    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item);
+
+    /**
+     * Returns an ID for determining how to save/restore instance state.
+     * @return a valid ID value.
+     */
+    public int getId();
+
+    /**
+     * Returns a Parcelable describing the current state of the presenter.
+     * It will be passed to the {@link #onRestoreInstanceState(Parcelable)}
+     * method of the presenter sharing the same ID later.
+     * @return The saved instance state
+     */
+    public Parcelable onSaveInstanceState();
+
+    /**
+     * Supplies the previously saved instance state to be restored.
+     * @param state The previously saved instance state
+     */
+    public void onRestoreInstanceState(Parcelable state);
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuView.java
new file mode 100644 (file)
index 0000000..323ba2d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import android.graphics.drawable.Drawable;
+
+/**
+ * Minimal interface for a menu view.  {@link #initialize(MenuBuilder)} must be called for the
+ * menu to be functional.
+ *
+ * @hide
+ */
+public interface MenuView {
+    /**
+     * Initializes the menu to the given menu. This should be called after the
+     * view is inflated.
+     *
+     * @param menu The menu that this MenuView should display.
+     */
+    public void initialize(MenuBuilder menu);
+
+    /**
+     * Returns the default animations to be used for this menu when entering/exiting.
+     * @return A resource ID for the default animations to be used for this menu.
+     */
+    public int getWindowAnimations();
+
+    /**
+     * Minimal interface for a menu item view.  {@link #initialize(MenuItemImpl, int)} must be called
+     * for the item to be functional.
+     */
+    public interface ItemView {
+        /**
+         * Initializes with the provided MenuItemData.  This should be called after the view is
+         * inflated.
+         * @param itemData The item that this ItemView should display.
+         * @param menuType The type of this menu, one of
+         *            {@link MenuBuilder#TYPE_ICON}, {@link MenuBuilder#TYPE_EXPANDED},
+         *            {@link MenuBuilder#TYPE_DIALOG}).
+         */
+        public void initialize(MenuItemImpl itemData, int menuType);
+
+        /**
+         * Gets the item data that this view is displaying.
+         * @return the item data, or null if there is not one
+         */
+        public MenuItemImpl getItemData();
+
+        /**
+         * Sets the title of the item view.
+         * @param title The title to set.
+         */
+        public void setTitle(CharSequence title);
+
+        /**
+         * Sets the enabled state of the item view.
+         * @param enabled Whether the item view should be enabled.
+         */
+        public void setEnabled(boolean enabled);
+
+        /**
+         * Displays the checkbox for the item view.  This does not ensure the item view will be
+         * checked, for that use {@link #setChecked}.
+         * @param checkable Whether to display the checkbox or to hide it
+         */
+        public void setCheckable(boolean checkable);
+
+        /**
+         * Checks the checkbox for the item view.  If the checkbox is hidden, it will NOT be
+         * made visible, call {@link #setCheckable(boolean)} for that.
+         * @param checked Whether the checkbox should be checked
+         */
+        public void setChecked(boolean checked);
+
+        /**
+         * Sets the shortcut for the item.
+         * @param showShortcut Whether a shortcut should be shown(if false, the value of
+         * shortcutKey should be ignored).
+         * @param shortcutKey The shortcut key that should be shown on the ItemView.
+         */
+        public void setShortcut(boolean showShortcut, char shortcutKey);
+
+        /**
+         * Set the icon of this item view.
+         * @param icon The icon of this item. null to hide the icon.
+         */
+        public void setIcon(Drawable icon);
+
+        /**
+         * Whether this item view prefers displaying the condensed title rather
+         * than the normal title. If a condensed title is not available, the
+         * normal title will be used.
+         *
+         * @return Whether this item view prefers displaying the condensed
+         *         title.
+         */
+        public boolean prefersCondensedTitle();
+
+        /**
+         * Whether this item view shows an icon.
+         *
+         * @return Whether this item view shows an icon.
+         */
+        public boolean showsIcon();
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuWrapper.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/MenuWrapper.java
new file mode 100644 (file)
index 0000000..64fc4ae
--- /dev/null
@@ -0,0 +1,180 @@
+package com.actionbarsherlock.internal.view.menu;
+
+import java.util.WeakHashMap;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.view.KeyEvent;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.SubMenu;
+
+public class MenuWrapper implements Menu {
+    private final android.view.Menu mNativeMenu;
+
+    private final WeakHashMap<android.view.MenuItem, MenuItem> mNativeMap =
+            new WeakHashMap<android.view.MenuItem, MenuItem>();
+
+
+    public MenuWrapper(android.view.Menu nativeMenu) {
+        mNativeMenu = nativeMenu;
+    }
+
+    public android.view.Menu unwrap() {
+        return mNativeMenu;
+    }
+
+    private MenuItem addInternal(android.view.MenuItem nativeItem) {
+        MenuItem item = new MenuItemWrapper(nativeItem);
+        mNativeMap.put(nativeItem, item);
+        return item;
+    }
+
+    @Override
+    public MenuItem add(CharSequence title) {
+        return addInternal(mNativeMenu.add(title));
+    }
+
+    @Override
+    public MenuItem add(int titleRes) {
+        return addInternal(mNativeMenu.add(titleRes));
+    }
+
+    @Override
+    public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
+        return addInternal(mNativeMenu.add(groupId, itemId, order, title));
+    }
+
+    @Override
+    public MenuItem add(int groupId, int itemId, int order, int titleRes) {
+        return addInternal(mNativeMenu.add(groupId, itemId, order, titleRes));
+    }
+
+    private SubMenu addInternal(android.view.SubMenu nativeSubMenu) {
+        SubMenu subMenu = new SubMenuWrapper(nativeSubMenu);
+        android.view.MenuItem nativeItem = nativeSubMenu.getItem();
+        MenuItem item = subMenu.getItem();
+        mNativeMap.put(nativeItem, item);
+        return subMenu;
+    }
+
+    @Override
+    public SubMenu addSubMenu(CharSequence title) {
+        return addInternal(mNativeMenu.addSubMenu(title));
+    }
+
+    @Override
+    public SubMenu addSubMenu(int titleRes) {
+        return addInternal(mNativeMenu.addSubMenu(titleRes));
+    }
+
+    @Override
+    public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
+        return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, title));
+    }
+
+    @Override
+    public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
+        return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, titleRes));
+    }
+
+    @Override
+    public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
+        android.view.MenuItem[] nativeOutItems = new android.view.MenuItem[outSpecificItems.length];
+        int result = mNativeMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, nativeOutItems);
+        for (int i = 0, length = outSpecificItems.length; i < length; i++) {
+            outSpecificItems[i] = new MenuItemWrapper(nativeOutItems[i]);
+        }
+        return result;
+    }
+
+    @Override
+    public void removeItem(int id) {
+        mNativeMenu.removeItem(id);
+    }
+
+    @Override
+    public void removeGroup(int groupId) {
+        mNativeMenu.removeGroup(groupId);
+    }
+
+    @Override
+    public void clear() {
+        mNativeMap.clear();
+        mNativeMenu.clear();
+    }
+
+    @Override
+    public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
+        mNativeMenu.setGroupCheckable(group, checkable, exclusive);
+    }
+
+    @Override
+    public void setGroupVisible(int group, boolean visible) {
+        mNativeMenu.setGroupVisible(group, visible);
+    }
+
+    @Override
+    public void setGroupEnabled(int group, boolean enabled) {
+        mNativeMenu.setGroupEnabled(group, enabled);
+    }
+
+    @Override
+    public boolean hasVisibleItems() {
+        return mNativeMenu.hasVisibleItems();
+    }
+
+    @Override
+    public MenuItem findItem(int id) {
+        android.view.MenuItem nativeItem = mNativeMenu.findItem(id);
+        return findItem(nativeItem);
+    }
+
+    public MenuItem findItem(android.view.MenuItem nativeItem) {
+        if (nativeItem == null) {
+            return null;
+        }
+
+        MenuItem wrapped = mNativeMap.get(nativeItem);
+        if (wrapped != null) {
+            return wrapped;
+        }
+
+        return addInternal(nativeItem);
+    }
+
+    @Override
+    public int size() {
+        return mNativeMenu.size();
+    }
+
+    @Override
+    public MenuItem getItem(int index) {
+        android.view.MenuItem nativeItem = mNativeMenu.getItem(index);
+        return findItem(nativeItem);
+    }
+
+    @Override
+    public void close() {
+        mNativeMenu.close();
+    }
+
+    @Override
+    public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
+        return mNativeMenu.performShortcut(keyCode, event, flags);
+    }
+
+    @Override
+    public boolean isShortcutKey(int keyCode, KeyEvent event) {
+        return mNativeMenu.isShortcutKey(keyCode, event);
+    }
+
+    @Override
+    public boolean performIdentifierAction(int id, int flags) {
+        return mNativeMenu.performIdentifierAction(id, flags);
+    }
+
+    @Override
+    public void setQwertyMode(boolean isQwerty) {
+        mNativeMenu.setQwertyMode(isQwerty);
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/SubMenuBuilder.java
new file mode 100644 (file)
index 0000000..6679cf3
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.view.menu;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.SubMenu;
+
+/**
+ * The model for a sub menu, which is an extension of the menu.  Most methods are proxied to
+ * the parent menu.
+ */
+public class SubMenuBuilder extends MenuBuilder implements SubMenu {
+    private MenuBuilder mParentMenu;
+    private MenuItemImpl mItem;
+
+    public SubMenuBuilder(Context context, MenuBuilder parentMenu, MenuItemImpl item) {
+        super(context);
+
+        mParentMenu = parentMenu;
+        mItem = item;
+    }
+
+    @Override
+    public void setQwertyMode(boolean isQwerty) {
+        mParentMenu.setQwertyMode(isQwerty);
+    }
+
+    @Override
+    public boolean isQwertyMode() {
+        return mParentMenu.isQwertyMode();
+    }
+
+    @Override
+    public void setShortcutsVisible(boolean shortcutsVisible) {
+        mParentMenu.setShortcutsVisible(shortcutsVisible);
+    }
+
+    @Override
+    public boolean isShortcutsVisible() {
+        return mParentMenu.isShortcutsVisible();
+    }
+
+    public Menu getParentMenu() {
+        return mParentMenu;
+    }
+
+    public MenuItem getItem() {
+        return mItem;
+    }
+
+    @Override
+    public void setCallback(Callback callback) {
+        mParentMenu.setCallback(callback);
+    }
+
+    @Override
+    public MenuBuilder getRootMenu() {
+        return mParentMenu;
+    }
+
+    @Override
+    boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) {
+        return super.dispatchMenuItemSelected(menu, item) ||
+                mParentMenu.dispatchMenuItemSelected(menu, item);
+    }
+
+    public SubMenu setIcon(Drawable icon) {
+        mItem.setIcon(icon);
+        return this;
+    }
+
+    public SubMenu setIcon(int iconRes) {
+        mItem.setIcon(iconRes);
+        return this;
+    }
+
+    public SubMenu setHeaderIcon(Drawable icon) {
+        return (SubMenu) super.setHeaderIconInt(icon);
+    }
+
+    public SubMenu setHeaderIcon(int iconRes) {
+        return (SubMenu) super.setHeaderIconInt(iconRes);
+    }
+
+    public SubMenu setHeaderTitle(CharSequence title) {
+        return (SubMenu) super.setHeaderTitleInt(title);
+    }
+
+    public SubMenu setHeaderTitle(int titleRes) {
+        return (SubMenu) super.setHeaderTitleInt(titleRes);
+    }
+
+    public SubMenu setHeaderView(View view) {
+        return (SubMenu) super.setHeaderViewInt(view);
+    }
+
+    @Override
+    public boolean expandItemActionView(MenuItemImpl item) {
+        return mParentMenu.expandItemActionView(item);
+    }
+
+    @Override
+    public boolean collapseItemActionView(MenuItemImpl item) {
+        return mParentMenu.collapseItemActionView(item);
+    }
+
+    @Override
+    public String getActionViewStatesKey() {
+        final int itemId = mItem != null ? mItem.getItemId() : 0;
+        if (itemId == 0) {
+            return null;
+        }
+        return super.getActionViewStatesKey() + ":" + itemId;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/view/menu/SubMenuWrapper.java
new file mode 100644 (file)
index 0000000..7d307ac
--- /dev/null
@@ -0,0 +1,72 @@
+package com.actionbarsherlock.internal.view.menu;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.SubMenu;
+
+public class SubMenuWrapper extends MenuWrapper implements SubMenu {
+    private final android.view.SubMenu mNativeSubMenu;
+    private MenuItem mItem = null;
+
+    public SubMenuWrapper(android.view.SubMenu nativeSubMenu) {
+        super(nativeSubMenu);
+        mNativeSubMenu = nativeSubMenu;
+    }
+
+
+    @Override
+    public SubMenu setHeaderTitle(int titleRes) {
+        mNativeSubMenu.setHeaderTitle(titleRes);
+        return this;
+    }
+
+    @Override
+    public SubMenu setHeaderTitle(CharSequence title) {
+        mNativeSubMenu.setHeaderTitle(title);
+        return this;
+    }
+
+    @Override
+    public SubMenu setHeaderIcon(int iconRes) {
+        mNativeSubMenu.setHeaderIcon(iconRes);
+        return this;
+    }
+
+    @Override
+    public SubMenu setHeaderIcon(Drawable icon) {
+        mNativeSubMenu.setHeaderIcon(icon);
+        return this;
+    }
+
+    @Override
+    public SubMenu setHeaderView(View view) {
+        mNativeSubMenu.setHeaderView(view);
+        return this;
+    }
+
+    @Override
+    public void clearHeader() {
+        mNativeSubMenu.clearHeader();
+    }
+
+    @Override
+    public SubMenu setIcon(int iconRes) {
+        mNativeSubMenu.setIcon(iconRes);
+        return this;
+    }
+
+    @Override
+    public SubMenu setIcon(Drawable icon) {
+        mNativeSubMenu.setIcon(icon);
+        return this;
+    }
+
+    @Override
+    public MenuItem getItem() {
+        if (mItem == null) {
+            mItem = new MenuItemWrapper(mNativeSubMenu.getItem());
+        }
+        return mItem;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/AbsActionBarView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/AbsActionBarView.java
new file mode 100644 (file)
index 0000000..3a4a446
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
+import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
+import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
+import com.actionbarsherlock.internal.nineoldandroids.view.NineViewGroup;
+import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
+import com.actionbarsherlock.internal.view.menu.ActionMenuView;
+
+import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
+
+public abstract class AbsActionBarView extends NineViewGroup {
+    protected ActionMenuView mMenuView;
+    protected ActionMenuPresenter mActionMenuPresenter;
+    protected ActionBarContainer mSplitView;
+    protected boolean mSplitActionBar;
+    protected boolean mSplitWhenNarrow;
+    protected int mContentHeight;
+
+    final Context mContext;
+
+    protected Animator mVisibilityAnim;
+    protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
+
+    private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator();
+
+    private static final int FADE_DURATION = 200;
+
+    public AbsActionBarView(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    public AbsActionBarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mContext = context;
+    }
+
+    public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mContext = context;
+    }
+
+    /*
+     * Must be public so we can dispatch pre-2.2 via ActionBarImpl.
+     */
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
+            super.onConfigurationChanged(newConfig);
+        } else if (mMenuView != null) {
+            mMenuView.onConfigurationChanged(newConfig);
+        }
+
+        // Action bar can change size on configuration changes.
+        // Reread the desired height from the theme-specified style.
+        TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
+                R.attr.actionBarStyle, 0);
+        setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
+        a.recycle();
+        if (mSplitWhenNarrow) {
+            setSplitActionBar(getResources_getBoolean(getContext(),
+                    R.bool.abs__split_action_bar_is_narrow));
+        }
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.onConfigurationChanged(newConfig);
+        }
+    }
+
+    /**
+     * Sets whether the bar should be split right now, no questions asked.
+     * @param split true if the bar should split
+     */
+    public void setSplitActionBar(boolean split) {
+        mSplitActionBar = split;
+    }
+
+    /**
+     * Sets whether the bar should split if we enter a narrow screen configuration.
+     * @param splitWhenNarrow true if the bar should check to split after a config change
+     */
+    public void setSplitWhenNarrow(boolean splitWhenNarrow) {
+        mSplitWhenNarrow = splitWhenNarrow;
+    }
+
+    public void setContentHeight(int height) {
+        mContentHeight = height;
+        requestLayout();
+    }
+
+    public int getContentHeight() {
+        return mContentHeight;
+    }
+
+    public void setSplitView(ActionBarContainer splitView) {
+        mSplitView = splitView;
+    }
+
+    /**
+     * @return Current visibility or if animating, the visibility being animated to.
+     */
+    public int getAnimatedVisibility() {
+        if (mVisibilityAnim != null) {
+            return mVisAnimListener.mFinalVisibility;
+        }
+        return getVisibility();
+    }
+
+    public void animateToVisibility(int visibility) {
+        if (mVisibilityAnim != null) {
+            mVisibilityAnim.cancel();
+        }
+        if (visibility == VISIBLE) {
+            if (getVisibility() != VISIBLE) {
+                setAlpha(0);
+                if (mSplitView != null && mMenuView != null) {
+                    mMenuView.setAlpha(0);
+                }
+            }
+            ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
+            anim.setDuration(FADE_DURATION);
+            anim.setInterpolator(sAlphaInterpolator);
+            if (mSplitView != null && mMenuView != null) {
+                AnimatorSet set = new AnimatorSet();
+                ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1);
+                splitAnim.setDuration(FADE_DURATION);
+                set.addListener(mVisAnimListener.withFinalVisibility(visibility));
+                set.play(anim).with(splitAnim);
+                set.start();
+            } else {
+                anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+                anim.start();
+            }
+        } else {
+            ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
+            anim.setDuration(FADE_DURATION);
+            anim.setInterpolator(sAlphaInterpolator);
+            if (mSplitView != null && mMenuView != null) {
+                AnimatorSet set = new AnimatorSet();
+                ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0);
+                splitAnim.setDuration(FADE_DURATION);
+                set.addListener(mVisAnimListener.withFinalVisibility(visibility));
+                set.play(anim).with(splitAnim);
+                set.start();
+            } else {
+                anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+                anim.start();
+            }
+        }
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        if (mVisibilityAnim != null) {
+            mVisibilityAnim.end();
+        }
+        super.setVisibility(visibility);
+    }
+
+    public boolean showOverflowMenu() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.showOverflowMenu();
+        }
+        return false;
+    }
+
+    public void postShowOverflowMenu() {
+        post(new Runnable() {
+            public void run() {
+                showOverflowMenu();
+            }
+        });
+    }
+
+    public boolean hideOverflowMenu() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.hideOverflowMenu();
+        }
+        return false;
+    }
+
+    public boolean isOverflowMenuShowing() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.isOverflowMenuShowing();
+        }
+        return false;
+    }
+
+    public boolean isOverflowReserved() {
+        return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
+    }
+
+    public void dismissPopupMenus() {
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.dismissPopupMenus();
+        }
+    }
+
+    protected int measureChildView(View child, int availableWidth, int childSpecHeight,
+            int spacing) {
+        child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+                childSpecHeight);
+
+        availableWidth -= child.getMeasuredWidth();
+        availableWidth -= spacing;
+
+        return Math.max(0, availableWidth);
+    }
+
+    protected int positionChild(View child, int x, int y, int contentHeight) {
+        int childWidth = child.getMeasuredWidth();
+        int childHeight = child.getMeasuredHeight();
+        int childTop = y + (contentHeight - childHeight) / 2;
+
+        child.layout(x, childTop, x + childWidth, childTop + childHeight);
+
+        return childWidth;
+    }
+
+    protected int positionChildInverse(View child, int x, int y, int contentHeight) {
+        int childWidth = child.getMeasuredWidth();
+        int childHeight = child.getMeasuredHeight();
+        int childTop = y + (contentHeight - childHeight) / 2;
+
+        child.layout(x - childWidth, childTop, x, childTop + childHeight);
+
+        return childWidth;
+    }
+
+    protected class VisibilityAnimListener implements Animator.AnimatorListener {
+        private boolean mCanceled = false;
+        int mFinalVisibility;
+
+        public VisibilityAnimListener withFinalVisibility(int visibility) {
+            mFinalVisibility = visibility;
+            return this;
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            setVisibility(VISIBLE);
+            mVisibilityAnim = animation;
+            mCanceled = false;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (mCanceled) return;
+
+            mVisibilityAnim = null;
+            setVisibility(mFinalVisibility);
+            if (mSplitView != null && mMenuView != null) {
+                mMenuView.setVisibility(mFinalVisibility);
+            }
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCanceled = true;
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarContainer.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarContainer.java
new file mode 100644 (file)
index 0000000..5e5aa28
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout;
+
+/**
+ * This class acts as a container for the action bar view and action mode context views.
+ * It applies special styles as needed to help handle animated transitions between them.
+ * @hide
+ */
+public class ActionBarContainer extends NineFrameLayout {
+    private boolean mIsTransitioning;
+    private View mTabContainer;
+    private ActionBarView mActionBarView;
+
+    private Drawable mBackground;
+    private Drawable mStackedBackground;
+    private Drawable mSplitBackground;
+    private boolean mIsSplit;
+    private boolean mIsStacked;
+
+    public ActionBarContainer(Context context) {
+        this(context, null);
+    }
+
+    public ActionBarContainer(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        setBackgroundDrawable(null);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.SherlockActionBar);
+        mBackground = a.getDrawable(R.styleable.SherlockActionBar_background);
+        mStackedBackground = a.getDrawable(
+                R.styleable.SherlockActionBar_backgroundStacked);
+
+        if (getId() == R.id.abs__split_action_bar) {
+            mIsSplit = true;
+            mSplitBackground = a.getDrawable(
+                    R.styleable.SherlockActionBar_backgroundSplit);
+        }
+        a.recycle();
+
+        setWillNotDraw(mIsSplit ? mSplitBackground == null :
+                mBackground == null && mStackedBackground == null);
+    }
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+        mActionBarView = (ActionBarView) findViewById(R.id.abs__action_bar);
+    }
+
+    public void setPrimaryBackground(Drawable bg) {
+        mBackground = bg;
+        invalidate();
+    }
+
+    public void setStackedBackground(Drawable bg) {
+        mStackedBackground = bg;
+        invalidate();
+    }
+
+    public void setSplitBackground(Drawable bg) {
+        mSplitBackground = bg;
+        invalidate();
+    }
+
+    /**
+     * Set the action bar into a "transitioning" state. While transitioning
+     * the bar will block focus and touch from all of its descendants. This
+     * prevents the user from interacting with the bar while it is animating
+     * in or out.
+     *
+     * @param isTransitioning true if the bar is currently transitioning, false otherwise.
+     */
+    public void setTransitioning(boolean isTransitioning) {
+        mIsTransitioning = isTransitioning;
+        setDescendantFocusability(isTransitioning ? FOCUS_BLOCK_DESCENDANTS
+                : FOCUS_AFTER_DESCENDANTS);
+    }
+
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return mIsTransitioning || super.onInterceptTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        super.onTouchEvent(ev);
+
+        // An action bar always eats touch events.
+        return true;
+    }
+
+    @Override
+    public boolean onHoverEvent(MotionEvent ev) {
+        super.onHoverEvent(ev);
+
+        // An action bar always eats hover events.
+        return true;
+    }
+
+    public void setTabContainer(ScrollingTabContainerView tabView) {
+        if (mTabContainer != null) {
+            removeView(mTabContainer);
+        }
+        mTabContainer = tabView;
+        if (tabView != null) {
+            addView(tabView);
+            final ViewGroup.LayoutParams lp = tabView.getLayoutParams();
+            lp.width = LayoutParams.MATCH_PARENT;
+            lp.height = LayoutParams.WRAP_CONTENT;
+            tabView.setAllowCollapse(false);
+        }
+    }
+
+    public View getTabContainer() {
+        return mTabContainer;
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        if (getWidth() == 0 || getHeight() == 0) {
+            return;
+        }
+
+        if (mIsSplit) {
+            if (mSplitBackground != null) mSplitBackground.draw(canvas);
+        } else {
+            if (mBackground != null) {
+                mBackground.draw(canvas);
+            }
+            if (mStackedBackground != null && mIsStacked) {
+                mStackedBackground.draw(canvas);
+            }
+        }
+    }
+
+    //This causes the animation reflection to fail on pre-HC platforms
+    //@Override
+    //public android.view.ActionMode startActionModeForChild(View child, android.view.ActionMode.Callback callback) {
+    //    // No starting an action mode for an action bar child! (Where would it go?)
+    //    return null;
+    //}
+
+    @Override
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        if (mActionBarView == null) return;
+
+        final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
+        final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
+                mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
+
+        if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
+            final int mode = MeasureSpec.getMode(heightMeasureSpec);
+            if (mode == MeasureSpec.AT_MOST) {
+                final int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
+                setMeasuredDimension(getMeasuredWidth(),
+                        Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(),
+                                maxHeight));
+            }
+        }
+    }
+
+    @Override
+    public void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+
+        final boolean hasTabs = mTabContainer != null && mTabContainer.getVisibility() != GONE;
+
+        if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
+            final int containerHeight = getMeasuredHeight();
+            final int tabHeight = mTabContainer.getMeasuredHeight();
+
+            if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) {
+                // Not showing home, put tabs on top.
+                final int count = getChildCount();
+                for (int i = 0; i < count; i++) {
+                    final View child = getChildAt(i);
+
+                    if (child == mTabContainer) continue;
+
+                    if (!mActionBarView.isCollapsed()) {
+                        child.offsetTopAndBottom(tabHeight);
+                    }
+                }
+                mTabContainer.layout(l, 0, r, tabHeight);
+            } else {
+                mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
+            }
+        }
+
+        boolean needsInvalidate = false;
+        if (mIsSplit) {
+            if (mSplitBackground != null) {
+                mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
+                needsInvalidate = true;
+            }
+        } else {
+            if (mBackground != null) {
+                mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
+                        mActionBarView.getRight(), mActionBarView.getBottom());
+                needsInvalidate = true;
+            }
+            if ((mIsStacked = hasTabs && mStackedBackground != null)) {
+                mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(),
+                        mTabContainer.getRight(), mTabContainer.getBottom());
+                needsInvalidate = true;
+            }
+        }
+
+        if (needsInvalidate) {
+            invalidate();
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarContextView.java
new file mode 100644 (file)
index 0000000..9ec250f
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Animator.AnimatorListener;
+import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
+import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
+import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
+import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
+import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
+import com.actionbarsherlock.internal.view.menu.ActionMenuView;
+import com.actionbarsherlock.internal.view.menu.MenuBuilder;
+import com.actionbarsherlock.view.ActionMode;
+
+/**
+ * @hide
+ */
+public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
+    //UNUSED private static final String TAG = "ActionBarContextView";
+
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+
+    private NineLinearLayout mClose;
+    private View mCustomView;
+    private LinearLayout mTitleLayout;
+    private TextView mTitleView;
+    private TextView mSubtitleView;
+    private int mTitleStyleRes;
+    private int mSubtitleStyleRes;
+    private Drawable mSplitBackground;
+
+    private Animator mCurrentAnimation;
+    private boolean mAnimateInOnLayout;
+    private int mAnimationMode;
+
+    private static final int ANIMATE_IDLE = 0;
+    private static final int ANIMATE_IN = 1;
+    private static final int ANIMATE_OUT = 2;
+
+    public ActionBarContextView(Context context) {
+        this(context, null);
+    }
+
+    public ActionBarContextView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.actionModeStyle);
+    }
+
+    public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockActionMode, defStyle, 0);
+        setBackgroundDrawable(a.getDrawable(
+                R.styleable.SherlockActionMode_background));
+        mTitleStyleRes = a.getResourceId(
+                R.styleable.SherlockActionMode_titleTextStyle, 0);
+        mSubtitleStyleRes = a.getResourceId(
+                R.styleable.SherlockActionMode_subtitleTextStyle, 0);
+
+        mContentHeight = a.getLayoutDimension(
+                R.styleable.SherlockActionMode_height, 0);
+
+        mSplitBackground = a.getDrawable(
+                R.styleable.SherlockActionMode_backgroundSplit);
+
+        a.recycle();
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.hideOverflowMenu();
+            mActionMenuPresenter.hideSubMenus();
+        }
+    }
+
+    @Override
+    public void setSplitActionBar(boolean split) {
+        if (mSplitActionBar != split) {
+            if (mActionMenuPresenter != null) {
+                // Mode is already active; move everything over and adjust the menu itself.
+                final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                        LayoutParams.MATCH_PARENT);
+                if (!split) {
+                    mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+                    mMenuView.setBackgroundDrawable(null);
+                    final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
+                    if (oldParent != null) oldParent.removeView(mMenuView);
+                    addView(mMenuView, layoutParams);
+                } else {
+                    // Allow full screen width in split mode.
+                    mActionMenuPresenter.setWidthLimit(
+                            getContext().getResources().getDisplayMetrics().widthPixels, true);
+                    // No limit to the item count; use whatever will fit.
+                    mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+                    // Span the whole width
+                    layoutParams.width = LayoutParams.MATCH_PARENT;
+                    layoutParams.height = mContentHeight;
+                    mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+                    mMenuView.setBackgroundDrawable(mSplitBackground);
+                    final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
+                    if (oldParent != null) oldParent.removeView(mMenuView);
+                    mSplitView.addView(mMenuView, layoutParams);
+                }
+            }
+            super.setSplitActionBar(split);
+        }
+    }
+
+    public void setContentHeight(int height) {
+        mContentHeight = height;
+    }
+
+    public void setCustomView(View view) {
+        if (mCustomView != null) {
+            removeView(mCustomView);
+        }
+        mCustomView = view;
+        if (mTitleLayout != null) {
+            removeView(mTitleLayout);
+            mTitleLayout = null;
+        }
+        if (view != null) {
+            addView(view);
+        }
+        requestLayout();
+    }
+
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+        initTitle();
+    }
+
+    public void setSubtitle(CharSequence subtitle) {
+        mSubtitle = subtitle;
+        initTitle();
+    }
+
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    public CharSequence getSubtitle() {
+        return mSubtitle;
+    }
+
+    private void initTitle() {
+        if (mTitleLayout == null) {
+            LayoutInflater inflater = LayoutInflater.from(getContext());
+            inflater.inflate(R.layout.abs__action_bar_title_item, this);
+            mTitleLayout = (LinearLayout) getChildAt(getChildCount() - 1);
+            mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title);
+            mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle);
+            if (mTitleStyleRes != 0) {
+                mTitleView.setTextAppearance(mContext, mTitleStyleRes);
+            }
+            if (mSubtitleStyleRes != 0) {
+                mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
+            }
+        }
+
+        mTitleView.setText(mTitle);
+        mSubtitleView.setText(mSubtitle);
+
+        final boolean hasTitle = !TextUtils.isEmpty(mTitle);
+        final boolean hasSubtitle = !TextUtils.isEmpty(mSubtitle);
+        mSubtitleView.setVisibility(hasSubtitle ? VISIBLE : GONE);
+        mTitleLayout.setVisibility(hasTitle || hasSubtitle ? VISIBLE : GONE);
+        if (mTitleLayout.getParent() == null) {
+            addView(mTitleLayout);
+        }
+    }
+
+    public void initForMode(final ActionMode mode) {
+        if (mClose == null) {
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            mClose = (NineLinearLayout)inflater.inflate(R.layout.abs__action_mode_close_item, this, false);
+            addView(mClose);
+        } else if (mClose.getParent() == null) {
+            addView(mClose);
+        }
+
+        View closeButton = mClose.findViewById(R.id.abs__action_mode_close_button);
+        closeButton.setOnClickListener(new OnClickListener() {
+            public void onClick(View v) {
+                mode.finish();
+            }
+        });
+
+        final MenuBuilder menu = (MenuBuilder) mode.getMenu();
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.dismissPopupMenus();
+        }
+        mActionMenuPresenter = new ActionMenuPresenter(mContext);
+        mActionMenuPresenter.setReserveOverflow(true);
+
+        final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT);
+        if (!mSplitActionBar) {
+            menu.addMenuPresenter(mActionMenuPresenter);
+            mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+            mMenuView.setBackgroundDrawable(null);
+            addView(mMenuView, layoutParams);
+        } else {
+            // Allow full screen width in split mode.
+            mActionMenuPresenter.setWidthLimit(
+                    getContext().getResources().getDisplayMetrics().widthPixels, true);
+            // No limit to the item count; use whatever will fit.
+            mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+            // Span the whole width
+            layoutParams.width = LayoutParams.MATCH_PARENT;
+            layoutParams.height = mContentHeight;
+            menu.addMenuPresenter(mActionMenuPresenter);
+            mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+            mMenuView.setBackgroundDrawable(mSplitBackground);
+            mSplitView.addView(mMenuView, layoutParams);
+        }
+
+        mAnimateInOnLayout = true;
+    }
+
+    public void closeMode() {
+        if (mAnimationMode == ANIMATE_OUT) {
+            // Called again during close; just finish what we were doing.
+            return;
+        }
+        if (mClose == null) {
+            killMode();
+            return;
+        }
+
+        finishAnimation();
+        mAnimationMode = ANIMATE_OUT;
+        mCurrentAnimation = makeOutAnimation();
+        mCurrentAnimation.start();
+    }
+
+    private void finishAnimation() {
+        final Animator a = mCurrentAnimation;
+        if (a != null) {
+            mCurrentAnimation = null;
+            a.end();
+        }
+    }
+
+    public void killMode() {
+        finishAnimation();
+        removeAllViews();
+        if (mSplitView != null) {
+            mSplitView.removeView(mMenuView);
+        }
+        mCustomView = null;
+        mMenuView = null;
+        mAnimateInOnLayout = false;
+    }
+
+    @Override
+    public boolean showOverflowMenu() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.showOverflowMenu();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean hideOverflowMenu() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.hideOverflowMenu();
+        }
+        return false;
+    }
+
+    @Override
+    public boolean isOverflowMenuShowing() {
+        if (mActionMenuPresenter != null) {
+            return mActionMenuPresenter.isOverflowMenuShowing();
+        }
+        return false;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        // Used by custom views if they don't supply layout params. Everything else
+        // added to an ActionBarContextView should have them already.
+        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new MarginLayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        if (widthMode != MeasureSpec.EXACTLY) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with android:layout_width=\"match_parent\" (or fill_parent)");
+        }
+
+        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        if (heightMode == MeasureSpec.UNSPECIFIED) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with android:layout_height=\"wrap_content\"");
+        }
+
+        final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
+
+        int maxHeight = mContentHeight > 0 ?
+                mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
+
+        final int verticalPadding = getPaddingTop() + getPaddingBottom();
+        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
+        final int height = maxHeight - verticalPadding;
+        final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+
+        if (mClose != null) {
+            availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
+            MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
+            availableWidth -= lp.leftMargin + lp.rightMargin;
+        }
+
+        if (mMenuView != null && mMenuView.getParent() == this) {
+            availableWidth = measureChildView(mMenuView, availableWidth,
+                    childSpecHeight, 0);
+        }
+
+        if (mTitleLayout != null && mCustomView == null) {
+            availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
+        }
+
+        if (mCustomView != null) {
+            ViewGroup.LayoutParams lp = mCustomView.getLayoutParams();
+            final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
+                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            final int customWidth = lp.width >= 0 ?
+                    Math.min(lp.width, availableWidth) : availableWidth;
+            final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
+                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            final int customHeight = lp.height >= 0 ?
+                    Math.min(lp.height, height) : height;
+            mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
+                    MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
+        }
+
+        if (mContentHeight <= 0) {
+            int measuredHeight = 0;
+            final int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                View v = getChildAt(i);
+                int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
+                if (paddedViewHeight > measuredHeight) {
+                    measuredHeight = paddedViewHeight;
+                }
+            }
+            setMeasuredDimension(contentWidth, measuredHeight);
+        } else {
+            setMeasuredDimension(contentWidth, maxHeight);
+        }
+    }
+
+    private Animator makeInAnimation() {
+        mClose.setTranslationX(-mClose.getWidth() -
+                ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
+        ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0);
+        buttonAnimator.setDuration(200);
+        buttonAnimator.addListener(this);
+        buttonAnimator.setInterpolator(new DecelerateInterpolator());
+
+        AnimatorSet set = new AnimatorSet();
+        AnimatorSet.Builder b = set.play(buttonAnimator);
+
+        if (mMenuView != null) {
+            final int count = mMenuView.getChildCount();
+            if (count > 0) {
+                for (int i = count - 1, j = 0; i >= 0; i--, j++) {
+                    AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i));
+                    child.setScaleY(0);
+                    ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1);
+                    a.setDuration(100);
+                    a.setStartDelay(j * 70);
+                    b.with(a);
+                }
+            }
+        }
+
+        return set;
+    }
+
+    private Animator makeOutAnimation() {
+        ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
+                -mClose.getWidth() - ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
+        buttonAnimator.setDuration(200);
+        buttonAnimator.addListener(this);
+        buttonAnimator.setInterpolator(new DecelerateInterpolator());
+
+        AnimatorSet set = new AnimatorSet();
+        AnimatorSet.Builder b = set.play(buttonAnimator);
+
+        if (mMenuView != null) {
+            final int count = mMenuView.getChildCount();
+            if (count > 0) {
+                for (int i = 0; i < 0; i++) {
+                    AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i));
+                    child.setScaleY(0);
+                    ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
+                    a.setDuration(100);
+                    a.setStartDelay(i * 70);
+                    b.with(a);
+                }
+            }
+        }
+
+        return set;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int x = getPaddingLeft();
+        final int y = getPaddingTop();
+        final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
+
+        if (mClose != null && mClose.getVisibility() != GONE) {
+            MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
+            x += lp.leftMargin;
+            x += positionChild(mClose, x, y, contentHeight);
+            x += lp.rightMargin;
+
+            if (mAnimateInOnLayout) {
+                mAnimationMode = ANIMATE_IN;
+                mCurrentAnimation = makeInAnimation();
+                mCurrentAnimation.start();
+                mAnimateInOnLayout = false;
+            }
+        }
+
+        if (mTitleLayout != null && mCustomView == null) {
+            x += positionChild(mTitleLayout, x, y, contentHeight);
+        }
+
+        if (mCustomView != null) {
+            x += positionChild(mCustomView, x, y, contentHeight);
+        }
+
+        x = r - l - getPaddingRight();
+
+        if (mMenuView != null) {
+            x -= positionChildInverse(mMenuView, x, y, contentHeight);
+        }
+    }
+
+    @Override
+    public void onAnimationStart(Animator animation) {
+    }
+
+    @Override
+    public void onAnimationEnd(Animator animation) {
+        if (mAnimationMode == ANIMATE_OUT) {
+            killMode();
+        }
+        mAnimationMode = ANIMATE_IDLE;
+    }
+
+    @Override
+    public void onAnimationCancel(Animator animation) {
+    }
+
+    @Override
+    public void onAnimationRepeat(Animator animation) {
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+            // Action mode started
+            //TODO event.setSource(this);
+            event.setClassName(getClass().getName());
+            event.setPackageName(getContext().getPackageName());
+            event.setContentDescription(mTitle);
+        } else {
+            //TODO super.onInitializeAccessibilityEvent(event);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ActionBarView.java
new file mode 100644 (file)
index 0000000..4636de1
--- /dev/null
@@ -0,0 +1,1548 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.widget;
+
+import org.xmlpull.v1.XmlPullParser;
+import android.app.Activity;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.SpinnerAdapter;
+import android.widget.TextView;
+
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.app.ActionBar.OnNavigationListener;
+import com.actionbarsherlock.internal.ActionBarSherlockCompat;
+import com.actionbarsherlock.internal.view.menu.ActionMenuItem;
+import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
+import com.actionbarsherlock.internal.view.menu.ActionMenuView;
+import com.actionbarsherlock.internal.view.menu.MenuBuilder;
+import com.actionbarsherlock.internal.view.menu.MenuItemImpl;
+import com.actionbarsherlock.internal.view.menu.MenuPresenter;
+import com.actionbarsherlock.internal.view.menu.MenuView;
+import com.actionbarsherlock.internal.view.menu.SubMenuBuilder;
+import com.actionbarsherlock.view.CollapsibleActionView;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.Window;
+
+import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
+
+/**
+ * @hide
+ */
+public class ActionBarView extends AbsActionBarView {
+    private static final String TAG = "ActionBarView";
+    private static final boolean DEBUG = false;
+
+    /**
+     * Display options applied by default
+     */
+    public static final int DISPLAY_DEFAULT = 0;
+
+    /**
+     * Display options that require re-layout as opposed to a simple invalidate
+     */
+    private static final int DISPLAY_RELAYOUT_MASK =
+            ActionBar.DISPLAY_SHOW_HOME |
+            ActionBar.DISPLAY_USE_LOGO |
+            ActionBar.DISPLAY_HOME_AS_UP |
+            ActionBar.DISPLAY_SHOW_CUSTOM |
+            ActionBar.DISPLAY_SHOW_TITLE;
+
+    private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | Gravity.CENTER_VERTICAL;
+
+    private int mNavigationMode;
+    private int mDisplayOptions = -1;
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+    private Drawable mIcon;
+    private Drawable mLogo;
+
+    private HomeView mHomeLayout;
+    private HomeView mExpandedHomeLayout;
+    private LinearLayout mTitleLayout;
+    private TextView mTitleView;
+    private TextView mSubtitleView;
+    private View mTitleUpView;
+
+    private IcsSpinner mSpinner;
+    private IcsLinearLayout mListNavLayout;
+    private ScrollingTabContainerView mTabScrollView;
+    private View mCustomNavView;
+    private IcsProgressBar mProgressView;
+    private IcsProgressBar mIndeterminateProgressView;
+
+    private int mProgressBarPadding;
+    private int mItemPadding;
+
+    private int mTitleStyleRes;
+    private int mSubtitleStyleRes;
+    private int mProgressStyle;
+    private int mIndeterminateProgressStyle;
+
+    private boolean mUserTitle;
+    private boolean mIncludeTabs;
+    private boolean mIsCollapsable;
+    private boolean mIsCollapsed;
+
+    private MenuBuilder mOptionsMenu;
+
+    private ActionBarContextView mContextView;
+
+    private ActionMenuItem mLogoNavItem;
+
+    private SpinnerAdapter mSpinnerAdapter;
+    private OnNavigationListener mCallback;
+
+    //UNUSED private Runnable mTabSelector;
+
+    private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
+    View mExpandedActionView;
+
+    Window.Callback mWindowCallback;
+
+    @SuppressWarnings("rawtypes")
+    private final IcsAdapterView.OnItemSelectedListener mNavItemSelectedListener =
+            new IcsAdapterView.OnItemSelectedListener() {
+        public void onItemSelected(IcsAdapterView parent, View view, int position, long id) {
+            if (mCallback != null) {
+                mCallback.onNavigationItemSelected(position, id);
+            }
+        }
+        public void onNothingSelected(IcsAdapterView parent) {
+            // Do nothing
+        }
+    };
+
+    private final OnClickListener mExpandedActionViewUpListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            final MenuItemImpl item = mExpandedMenuPresenter.mCurrentExpandedItem;
+            if (item != null) {
+                item.collapseActionView();
+            }
+        }
+    };
+
+    private final OnClickListener mUpClickListener = new OnClickListener() {
+        public void onClick(View v) {
+            mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mLogoNavItem);
+        }
+    };
+
+    public ActionBarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        // Background is always provided by the container.
+        setBackgroundResource(0);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockActionBar,
+                R.attr.actionBarStyle, 0);
+
+        ApplicationInfo appInfo = context.getApplicationInfo();
+        PackageManager pm = context.getPackageManager();
+        mNavigationMode = a.getInt(R.styleable.SherlockActionBar_navigationMode,
+                ActionBar.NAVIGATION_MODE_STANDARD);
+        mTitle = a.getText(R.styleable.SherlockActionBar_title);
+        mSubtitle = a.getText(R.styleable.SherlockActionBar_subtitle);
+
+        mLogo = a.getDrawable(R.styleable.SherlockActionBar_logo);
+        if (mLogo == null) {
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+                if (context instanceof Activity) {
+                    //Even though native methods existed in API 9 and 10 they don't work
+                    //so just parse the manifest to look for the logo pre-Honeycomb
+                    final int resId = loadLogoFromManifest((Activity) context);
+                    if (resId != 0) {
+                        mLogo = context.getResources().getDrawable(resId);
+                    }
+                }
+            } else {
+                if (context instanceof Activity) {
+                    try {
+                        mLogo = pm.getActivityLogo(((Activity) context).getComponentName());
+                    } catch (NameNotFoundException e) {
+                        Log.e(TAG, "Activity component name not found!", e);
+                    }
+                }
+                if (mLogo == null) {
+                    mLogo = appInfo.loadLogo(pm);
+                }
+            }
+        }
+
+        mIcon = a.getDrawable(R.styleable.SherlockActionBar_icon);
+        if (mIcon == null) {
+            if (context instanceof Activity) {
+                try {
+                    mIcon = pm.getActivityIcon(((Activity) context).getComponentName());
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Activity component name not found!", e);
+                }
+            }
+            if (mIcon == null) {
+                mIcon = appInfo.loadIcon(pm);
+            }
+        }
+
+        final LayoutInflater inflater = LayoutInflater.from(context);
+
+        final int homeResId = a.getResourceId(
+                R.styleable.SherlockActionBar_homeLayout,
+                R.layout.abs__action_bar_home);
+
+        mHomeLayout = (HomeView) inflater.inflate(homeResId, this, false);
+
+        mExpandedHomeLayout = (HomeView) inflater.inflate(homeResId, this, false);
+        mExpandedHomeLayout.setUp(true);
+        mExpandedHomeLayout.setOnClickListener(mExpandedActionViewUpListener);
+        mExpandedHomeLayout.setContentDescription(getResources().getText(
+                R.string.abs__action_bar_up_description));
+
+        mTitleStyleRes = a.getResourceId(R.styleable.SherlockActionBar_titleTextStyle, 0);
+        mSubtitleStyleRes = a.getResourceId(R.styleable.SherlockActionBar_subtitleTextStyle, 0);
+        mProgressStyle = a.getResourceId(R.styleable.SherlockActionBar_progressBarStyle, 0);
+        mIndeterminateProgressStyle = a.getResourceId(
+                R.styleable.SherlockActionBar_indeterminateProgressStyle, 0);
+
+        mProgressBarPadding = a.getDimensionPixelOffset(R.styleable.SherlockActionBar_progressBarPadding, 0);
+        mItemPadding = a.getDimensionPixelOffset(R.styleable.SherlockActionBar_itemPadding, 0);
+
+        setDisplayOptions(a.getInt(R.styleable.SherlockActionBar_displayOptions, DISPLAY_DEFAULT));
+
+        final int customNavId = a.getResourceId(R.styleable.SherlockActionBar_customNavigationLayout, 0);
+        if (customNavId != 0) {
+            mCustomNavView = inflater.inflate(customNavId, this, false);
+            mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD;
+            setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM);
+        }
+
+        mContentHeight = a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0);
+
+        a.recycle();
+
+        mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
+        mHomeLayout.setOnClickListener(mUpClickListener);
+        mHomeLayout.setClickable(true);
+        mHomeLayout.setFocusable(true);
+    }
+
+    /**
+     * Attempt to programmatically load the logo from the manifest file of an
+     * activity by using an XML pull parser. This should allow us to read the
+     * logo attribute regardless of the platform it is being run on.
+     *
+     * @param activity Activity instance.
+     * @return Logo resource ID.
+     */
+    private static int loadLogoFromManifest(Activity activity) {
+        int logo = 0;
+        try {
+            final String thisPackage = activity.getClass().getName();
+            if (DEBUG) Log.i(TAG, "Parsing AndroidManifest.xml for " + thisPackage);
+
+            final String packageName = activity.getApplicationInfo().packageName;
+            final AssetManager am = activity.createPackageContext(packageName, 0).getAssets();
+            final XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml");
+
+            int eventType = xml.getEventType();
+            while (eventType != XmlPullParser.END_DOCUMENT) {
+                if (eventType == XmlPullParser.START_TAG) {
+                    String name = xml.getName();
+
+                    if ("application".equals(name)) {
+                        //Check if the <application> has the attribute
+                        if (DEBUG) Log.d(TAG, "Got <application>");
+
+                        for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
+                            if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
+
+                            if ("logo".equals(xml.getAttributeName(i))) {
+                                logo = xml.getAttributeResourceValue(i, 0);
+                                break; //out of for loop
+                            }
+                        }
+                    } else if ("activity".equals(name)) {
+                        //Check if the <activity> is us and has the attribute
+                        if (DEBUG) Log.d(TAG, "Got <activity>");
+                        Integer activityLogo = null;
+                        String activityPackage = null;
+                        boolean isOurActivity = false;
+
+                        for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
+                            if (DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
+
+                            //We need both uiOptions and name attributes
+                            String attrName = xml.getAttributeName(i);
+                            if ("logo".equals(attrName)) {
+                                activityLogo = xml.getAttributeResourceValue(i, 0);
+                            } else if ("name".equals(attrName)) {
+                                activityPackage = ActionBarSherlockCompat.cleanActivityName(packageName, xml.getAttributeValue(i));
+                                if (!thisPackage.equals(activityPackage)) {
+                                    break; //on to the next
+                                }
+                                isOurActivity = true;
+                            }
+
+                            //Make sure we have both attributes before processing
+                            if ((activityLogo != null) && (activityPackage != null)) {
+                                //Our activity, logo specified, override with our value
+                                logo = activityLogo.intValue();
+                            }
+                        }
+                        if (isOurActivity) {
+                            //If we matched our activity but it had no logo don't
+                            //do any more processing of the manifest
+                            break;
+                        }
+                    }
+                }
+                eventType = xml.nextToken();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        if (DEBUG) Log.i(TAG, "Returning " + Integer.toHexString(logo));
+        return logo;
+    }
+
+    /*
+     * Must be public so we can dispatch pre-2.2 via ActionBarImpl.
+     */
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        mTitleView = null;
+        mSubtitleView = null;
+        mTitleUpView = null;
+        if (mTitleLayout != null && mTitleLayout.getParent() == this) {
+            removeView(mTitleLayout);
+        }
+        mTitleLayout = null;
+        if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            initTitle();
+        }
+
+        if (mTabScrollView != null && mIncludeTabs) {
+            ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
+            if (lp != null) {
+                lp.width = LayoutParams.WRAP_CONTENT;
+                lp.height = LayoutParams.MATCH_PARENT;
+            }
+            mTabScrollView.setAllowCollapse(true);
+        }
+    }
+
+    /**
+     * Set the window callback used to invoke menu items; used for dispatching home button presses.
+     * @param cb Window callback to dispatch to
+     */
+    public void setWindowCallback(Window.Callback cb) {
+        mWindowCallback = cb;
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        //UNUSED removeCallbacks(mTabSelector);
+        if (mActionMenuPresenter != null) {
+            mActionMenuPresenter.hideOverflowMenu();
+            mActionMenuPresenter.hideSubMenus();
+        }
+    }
+
+    @Override
+    public boolean shouldDelayChildPressedState() {
+        return false;
+    }
+
+    public void initProgress() {
+        mProgressView = new IcsProgressBar(mContext, null, 0, mProgressStyle);
+        mProgressView.setId(R.id.abs__progress_horizontal);
+        mProgressView.setMax(10000);
+        addView(mProgressView);
+    }
+
+    public void initIndeterminateProgress() {
+        mIndeterminateProgressView = new IcsProgressBar(mContext, null, 0, mIndeterminateProgressStyle);
+        mIndeterminateProgressView.setId(R.id.abs__progress_circular);
+        addView(mIndeterminateProgressView);
+    }
+
+    @Override
+    public void setSplitActionBar(boolean splitActionBar) {
+        if (mSplitActionBar != splitActionBar) {
+            if (mMenuView != null) {
+                final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
+                if (oldParent != null) {
+                    oldParent.removeView(mMenuView);
+                }
+                if (splitActionBar) {
+                    if (mSplitView != null) {
+                        mSplitView.addView(mMenuView);
+                    }
+                } else {
+                    addView(mMenuView);
+                }
+            }
+            if (mSplitView != null) {
+                mSplitView.setVisibility(splitActionBar ? VISIBLE : GONE);
+            }
+            super.setSplitActionBar(splitActionBar);
+        }
+    }
+
+    public boolean isSplitActionBar() {
+        return mSplitActionBar;
+    }
+
+    public boolean hasEmbeddedTabs() {
+        return mIncludeTabs;
+    }
+
+    public void setEmbeddedTabView(ScrollingTabContainerView tabs) {
+        if (mTabScrollView != null) {
+            removeView(mTabScrollView);
+        }
+        mTabScrollView = tabs;
+        mIncludeTabs = tabs != null;
+        if (mIncludeTabs && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) {
+            addView(mTabScrollView);
+            ViewGroup.LayoutParams lp = mTabScrollView.getLayoutParams();
+            lp.width = LayoutParams.WRAP_CONTENT;
+            lp.height = LayoutParams.MATCH_PARENT;
+            tabs.setAllowCollapse(true);
+        }
+    }
+
+    public void setCallback(OnNavigationListener callback) {
+        mCallback = callback;
+    }
+
+    public void setMenu(Menu menu, MenuPresenter.Callback cb) {
+        if (menu == mOptionsMenu) return;
+
+        if (mOptionsMenu != null) {
+            mOptionsMenu.removeMenuPresenter(mActionMenuPresenter);
+            mOptionsMenu.removeMenuPresenter(mExpandedMenuPresenter);
+        }
+
+        MenuBuilder builder = (MenuBuilder) menu;
+        mOptionsMenu = builder;
+        if (mMenuView != null) {
+            final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
+            if (oldParent != null) {
+                oldParent.removeView(mMenuView);
+            }
+        }
+        if (mActionMenuPresenter == null) {
+            mActionMenuPresenter = new ActionMenuPresenter(mContext);
+            mActionMenuPresenter.setCallback(cb);
+            mActionMenuPresenter.setId(R.id.abs__action_menu_presenter);
+            mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
+        }
+
+        ActionMenuView menuView;
+        final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT);
+        if (!mSplitActionBar) {
+            mActionMenuPresenter.setExpandedActionViewsExclusive(
+                    getResources_getBoolean(getContext(),
+                    R.bool.abs__action_bar_expanded_action_views_exclusive));
+            configPresenters(builder);
+            menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+            final ViewGroup oldParent = (ViewGroup) menuView.getParent();
+            if (oldParent != null && oldParent != this) {
+                oldParent.removeView(menuView);
+            }
+            addView(menuView, layoutParams);
+        } else {
+            mActionMenuPresenter.setExpandedActionViewsExclusive(false);
+            // Allow full screen width in split mode.
+            mActionMenuPresenter.setWidthLimit(
+                    getContext().getResources().getDisplayMetrics().widthPixels, true);
+            // No limit to the item count; use whatever will fit.
+            mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
+            // Span the whole width
+            layoutParams.width = LayoutParams.MATCH_PARENT;
+            configPresenters(builder);
+            menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
+            if (mSplitView != null) {
+                final ViewGroup oldParent = (ViewGroup) menuView.getParent();
+                if (oldParent != null && oldParent != mSplitView) {
+                    oldParent.removeView(menuView);
+                }
+                menuView.setVisibility(getAnimatedVisibility());
+                mSplitView.addView(menuView, layoutParams);
+            } else {
+                // We'll add this later if we missed it this time.
+                menuView.setLayoutParams(layoutParams);
+            }
+        }
+        mMenuView = menuView;
+    }
+
+    private void configPresenters(MenuBuilder builder) {
+        if (builder != null) {
+            builder.addMenuPresenter(mActionMenuPresenter);
+            builder.addMenuPresenter(mExpandedMenuPresenter);
+        } else {
+            mActionMenuPresenter.initForMenu(mContext, null);
+            mExpandedMenuPresenter.initForMenu(mContext, null);
+            mActionMenuPresenter.updateMenuView(true);
+            mExpandedMenuPresenter.updateMenuView(true);
+        }
+    }
+
+    public boolean hasExpandedActionView() {
+        return mExpandedMenuPresenter != null &&
+                mExpandedMenuPresenter.mCurrentExpandedItem != null;
+    }
+
+    public void collapseActionView() {
+        final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
+                mExpandedMenuPresenter.mCurrentExpandedItem;
+        if (item != null) {
+            item.collapseActionView();
+        }
+    }
+
+    public void setCustomNavigationView(View view) {
+        final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
+        if (mCustomNavView != null && showCustom) {
+            removeView(mCustomNavView);
+        }
+        mCustomNavView = view;
+        if (mCustomNavView != null && showCustom) {
+            addView(mCustomNavView);
+        }
+    }
+
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Set the action bar title. This will always replace or override window titles.
+     * @param title Title to set
+     *
+     * @see #setWindowTitle(CharSequence)
+     */
+    public void setTitle(CharSequence title) {
+        mUserTitle = true;
+        setTitleImpl(title);
+    }
+
+    /**
+     * Set the window title. A window title will always be replaced or overridden by a user title.
+     * @param title Title to set
+     *
+     * @see #setTitle(CharSequence)
+     */
+    public void setWindowTitle(CharSequence title) {
+        if (!mUserTitle) {
+            setTitleImpl(title);
+        }
+    }
+
+    private void setTitleImpl(CharSequence title) {
+        mTitle = title;
+        if (mTitleView != null) {
+            mTitleView.setText(title);
+            final boolean visible = mExpandedActionView == null &&
+                    (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0 &&
+                    (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle));
+            mTitleLayout.setVisibility(visible ? VISIBLE : GONE);
+        }
+        if (mLogoNavItem != null) {
+            mLogoNavItem.setTitle(title);
+        }
+    }
+
+    public CharSequence getSubtitle() {
+        return mSubtitle;
+    }
+
+    public void setSubtitle(CharSequence subtitle) {
+        mSubtitle = subtitle;
+        if (mSubtitleView != null) {
+            mSubtitleView.setText(subtitle);
+            mSubtitleView.setVisibility(subtitle != null ? VISIBLE : GONE);
+            final boolean visible = mExpandedActionView == null &&
+                    (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0 &&
+                    (!TextUtils.isEmpty(mTitle) || !TextUtils.isEmpty(mSubtitle));
+            mTitleLayout.setVisibility(visible ? VISIBLE : GONE);
+        }
+    }
+
+    public void setHomeButtonEnabled(boolean enable) {
+        mHomeLayout.setEnabled(enable);
+        mHomeLayout.setFocusable(enable);
+        // Make sure the home button has an accurate content description for accessibility.
+        if (!enable) {
+            mHomeLayout.setContentDescription(null);
+        } else if ((mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+            mHomeLayout.setContentDescription(mContext.getResources().getText(
+                    R.string.abs__action_bar_up_description));
+        } else {
+            mHomeLayout.setContentDescription(mContext.getResources().getText(
+                    R.string.abs__action_bar_home_description));
+        }
+    }
+
+    public void setDisplayOptions(int options) {
+        final int flagsChanged = mDisplayOptions == -1 ? -1 : options ^ mDisplayOptions;
+        mDisplayOptions = options;
+
+        if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
+            final boolean showHome = (options & ActionBar.DISPLAY_SHOW_HOME) != 0;
+            final int vis = showHome && mExpandedActionView == null ? VISIBLE : GONE;
+            mHomeLayout.setVisibility(vis);
+
+            if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+                final boolean setUp = (options & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+                mHomeLayout.setUp(setUp);
+
+                // Showing home as up implicitly enables interaction with it.
+                // In honeycomb it was always enabled, so make this transition
+                // a bit easier for developers in the common case.
+                // (It would be silly to show it as up without responding to it.)
+                if (setUp) {
+                    setHomeButtonEnabled(true);
+                }
+            }
+
+            if ((flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
+                final boolean logoVis = mLogo != null && (options & ActionBar.DISPLAY_USE_LOGO) != 0;
+                mHomeLayout.setIcon(logoVis ? mLogo : mIcon);
+            }
+
+            if ((flagsChanged & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                if ((options & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                    initTitle();
+                } else {
+                    removeView(mTitleLayout);
+                }
+            }
+
+            if (mTitleLayout != null && (flagsChanged &
+                    (ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME)) != 0) {
+                final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+                mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
+                mTitleLayout.setEnabled(!showHome && homeAsUp);
+            }
+
+            if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
+                if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+                    addView(mCustomNavView);
+                } else {
+                    removeView(mCustomNavView);
+                }
+            }
+
+            requestLayout();
+        } else {
+            invalidate();
+        }
+
+        // Make sure the home button has an accurate content description for accessibility.
+        if (!mHomeLayout.isEnabled()) {
+            mHomeLayout.setContentDescription(null);
+        } else if ((options & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+            mHomeLayout.setContentDescription(mContext.getResources().getText(
+                    R.string.abs__action_bar_up_description));
+        } else {
+            mHomeLayout.setContentDescription(mContext.getResources().getText(
+                    R.string.abs__action_bar_home_description));
+        }
+    }
+
+    public void setIcon(Drawable icon) {
+        mIcon = icon;
+        if (icon != null &&
+                ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null)) {
+            mHomeLayout.setIcon(icon);
+        }
+    }
+
+    public void setIcon(int resId) {
+        setIcon(mContext.getResources().getDrawable(resId));
+    }
+
+    public void setLogo(Drawable logo) {
+        mLogo = logo;
+        if (logo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
+            mHomeLayout.setIcon(logo);
+        }
+    }
+
+    public void setLogo(int resId) {
+        setLogo(mContext.getResources().getDrawable(resId));
+    }
+
+    public void setNavigationMode(int mode) {
+        final int oldMode = mNavigationMode;
+        if (mode != oldMode) {
+            switch (oldMode) {
+            case ActionBar.NAVIGATION_MODE_LIST:
+                if (mListNavLayout != null) {
+                    removeView(mListNavLayout);
+                }
+                break;
+            case ActionBar.NAVIGATION_MODE_TABS:
+                if (mTabScrollView != null && mIncludeTabs) {
+                    removeView(mTabScrollView);
+                }
+            }
+
+            switch (mode) {
+            case ActionBar.NAVIGATION_MODE_LIST:
+                if (mSpinner == null) {
+                    mSpinner = new IcsSpinner(mContext, null,
+                            R.attr.actionDropDownStyle);
+                    mListNavLayout = (IcsLinearLayout) LayoutInflater.from(mContext)
+                            .inflate(R.layout.abs__action_bar_tab_bar_view, null);
+                    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                            LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+                    params.gravity = Gravity.CENTER;
+                    mListNavLayout.addView(mSpinner, params);
+                }
+                if (mSpinner.getAdapter() != mSpinnerAdapter) {
+                    mSpinner.setAdapter(mSpinnerAdapter);
+                }
+                mSpinner.setOnItemSelectedListener(mNavItemSelectedListener);
+                addView(mListNavLayout);
+                break;
+            case ActionBar.NAVIGATION_MODE_TABS:
+                if (mTabScrollView != null && mIncludeTabs) {
+                    addView(mTabScrollView);
+                }
+                break;
+            }
+            mNavigationMode = mode;
+            requestLayout();
+        }
+    }
+
+    public void setDropdownAdapter(SpinnerAdapter adapter) {
+        mSpinnerAdapter = adapter;
+        if (mSpinner != null) {
+            mSpinner.setAdapter(adapter);
+        }
+    }
+
+    public SpinnerAdapter getDropdownAdapter() {
+        return mSpinnerAdapter;
+    }
+
+    public void setDropdownSelectedPosition(int position) {
+        mSpinner.setSelection(position);
+    }
+
+    public int getDropdownSelectedPosition() {
+        return mSpinner.getSelectedItemPosition();
+    }
+
+    public View getCustomNavigationView() {
+        return mCustomNavView;
+    }
+
+    public int getNavigationMode() {
+        return mNavigationMode;
+    }
+
+    public int getDisplayOptions() {
+        return mDisplayOptions;
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        // Used by custom nav views if they don't supply layout params. Everything else
+        // added to an ActionBarView should have them already.
+        return new ActionBar.LayoutParams(DEFAULT_CUSTOM_GRAVITY);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        addView(mHomeLayout);
+
+        if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            final ViewParent parent = mCustomNavView.getParent();
+            if (parent != this) {
+                if (parent instanceof ViewGroup) {
+                    ((ViewGroup) parent).removeView(mCustomNavView);
+                }
+                addView(mCustomNavView);
+            }
+        }
+    }
+
+    private void initTitle() {
+        if (mTitleLayout == null) {
+            LayoutInflater inflater = LayoutInflater.from(getContext());
+            mTitleLayout = (LinearLayout) inflater.inflate(R.layout.abs__action_bar_title_item,
+                    this, false);
+            mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title);
+            mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle);
+            mTitleUpView = mTitleLayout.findViewById(R.id.abs__up);
+
+            mTitleLayout.setOnClickListener(mUpClickListener);
+
+            if (mTitleStyleRes != 0) {
+                mTitleView.setTextAppearance(mContext, mTitleStyleRes);
+            }
+            if (mTitle != null) {
+                mTitleView.setText(mTitle);
+            }
+
+            if (mSubtitleStyleRes != 0) {
+                mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
+            }
+            if (mSubtitle != null) {
+                mSubtitleView.setText(mSubtitle);
+                mSubtitleView.setVisibility(VISIBLE);
+            }
+
+            final boolean homeAsUp = (mDisplayOptions & ActionBar.DISPLAY_HOME_AS_UP) != 0;
+            final boolean showHome = (mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0;
+            mTitleUpView.setVisibility(!showHome ? (homeAsUp ? VISIBLE : INVISIBLE) : GONE);
+            mTitleLayout.setEnabled(homeAsUp && !showHome);
+        }
+
+        addView(mTitleLayout);
+        if (mExpandedActionView != null ||
+                (TextUtils.isEmpty(mTitle) && TextUtils.isEmpty(mSubtitle))) {
+            // Don't show while in expanded mode or with empty text
+            mTitleLayout.setVisibility(GONE);
+        }
+    }
+
+    public void setContextView(ActionBarContextView view) {
+        mContextView = view;
+    }
+
+    public void setCollapsable(boolean collapsable) {
+        mIsCollapsable = collapsable;
+    }
+
+    public boolean isCollapsed() {
+        return mIsCollapsed;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int childCount = getChildCount();
+        if (mIsCollapsable) {
+            int visibleChildren = 0;
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                if (child.getVisibility() != GONE &&
+                        !(child == mMenuView && mMenuView.getChildCount() == 0)) {
+                    visibleChildren++;
+                }
+            }
+
+            if (visibleChildren == 0) {
+                // No size for an empty action bar when collapsable.
+                setMeasuredDimension(0, 0);
+                mIsCollapsed = true;
+                return;
+            }
+        }
+        mIsCollapsed = false;
+
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        if (widthMode != MeasureSpec.EXACTLY) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with android:layout_width=\"match_parent\" (or fill_parent)");
+        }
+
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        if (heightMode != MeasureSpec.AT_MOST) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with android:layout_height=\"wrap_content\"");
+        }
+
+        int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
+
+        int maxHeight = mContentHeight > 0 ?
+                mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
+
+        final int verticalPadding = getPaddingTop() + getPaddingBottom();
+        final int paddingLeft = getPaddingLeft();
+        final int paddingRight = getPaddingRight();
+        final int height = maxHeight - verticalPadding;
+        final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+
+        int availableWidth = contentWidth - paddingLeft - paddingRight;
+        int leftOfCenter = availableWidth / 2;
+        int rightOfCenter = leftOfCenter;
+
+        HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
+
+        if (homeLayout.getVisibility() != GONE) {
+            final ViewGroup.LayoutParams lp = homeLayout.getLayoutParams();
+            int homeWidthSpec;
+            if (lp.width < 0) {
+                homeWidthSpec = MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST);
+            } else {
+                homeWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
+            }
+            homeLayout.measure(homeWidthSpec,
+                    MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+            final int homeWidth = homeLayout.getMeasuredWidth() + homeLayout.getLeftOffset();
+            availableWidth = Math.max(0, availableWidth - homeWidth);
+            leftOfCenter = Math.max(0, availableWidth - homeWidth);
+        }
+
+        if (mMenuView != null && mMenuView.getParent() == this) {
+            availableWidth = measureChildView(mMenuView, availableWidth,
+                    childSpecHeight, 0);
+            rightOfCenter = Math.max(0, rightOfCenter - mMenuView.getMeasuredWidth());
+        }
+
+        if (mIndeterminateProgressView != null &&
+                mIndeterminateProgressView.getVisibility() != GONE) {
+            availableWidth = measureChildView(mIndeterminateProgressView, availableWidth,
+                    childSpecHeight, 0);
+            rightOfCenter = Math.max(0,
+                    rightOfCenter - mIndeterminateProgressView.getMeasuredWidth());
+        }
+
+        final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
+                (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
+
+        if (mExpandedActionView == null) {
+            switch (mNavigationMode) {
+                case ActionBar.NAVIGATION_MODE_LIST:
+                    if (mListNavLayout != null) {
+                        final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding;
+                        availableWidth = Math.max(0, availableWidth - itemPaddingSize);
+                        leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize);
+                        mListNavLayout.measure(
+                                MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+                                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+                        final int listNavWidth = mListNavLayout.getMeasuredWidth();
+                        availableWidth = Math.max(0, availableWidth - listNavWidth);
+                        leftOfCenter = Math.max(0, leftOfCenter - listNavWidth);
+                    }
+                    break;
+                case ActionBar.NAVIGATION_MODE_TABS:
+                    if (mTabScrollView != null) {
+                        final int itemPaddingSize = showTitle ? mItemPadding * 2 : mItemPadding;
+                        availableWidth = Math.max(0, availableWidth - itemPaddingSize);
+                        leftOfCenter = Math.max(0, leftOfCenter - itemPaddingSize);
+                        mTabScrollView.measure(
+                                MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+                                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+                        final int tabWidth = mTabScrollView.getMeasuredWidth();
+                        availableWidth = Math.max(0, availableWidth - tabWidth);
+                        leftOfCenter = Math.max(0, leftOfCenter - tabWidth);
+                    }
+                    break;
+            }
+        }
+
+        View customView = null;
+        if (mExpandedActionView != null) {
+            customView = mExpandedActionView;
+        } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 &&
+                mCustomNavView != null) {
+            customView = mCustomNavView;
+        }
+
+        if (customView != null) {
+            final ViewGroup.LayoutParams lp = generateLayoutParams(customView.getLayoutParams());
+            final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
+                    (ActionBar.LayoutParams) lp : null;
+
+            int horizontalMargin = 0;
+            int verticalMargin = 0;
+            if (ablp != null) {
+                horizontalMargin = ablp.leftMargin + ablp.rightMargin;
+                verticalMargin = ablp.topMargin + ablp.bottomMargin;
+            }
+
+            // If the action bar is wrapping to its content height, don't allow a custom
+            // view to MATCH_PARENT.
+            int customNavHeightMode;
+            if (mContentHeight <= 0) {
+                customNavHeightMode = MeasureSpec.AT_MOST;
+            } else {
+                customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
+                        MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            }
+            final int customNavHeight = Math.max(0,
+                    (lp.height >= 0 ? Math.min(lp.height, height) : height) - verticalMargin);
+
+            final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
+                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            int customNavWidth = Math.max(0,
+                    (lp.width >= 0 ? Math.min(lp.width, availableWidth) : availableWidth)
+                    - horizontalMargin);
+            final int hgrav = (ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY) &
+                    Gravity.HORIZONTAL_GRAVITY_MASK;
+
+            // Centering a custom view is treated specially; we try to center within the whole
+            // action bar rather than in the available space.
+            if (hgrav == Gravity.CENTER_HORIZONTAL && lp.width == LayoutParams.MATCH_PARENT) {
+                customNavWidth = Math.min(leftOfCenter, rightOfCenter) * 2;
+            }
+
+            customView.measure(
+                    MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode),
+                    MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
+            availableWidth -= horizontalMargin + customView.getMeasuredWidth();
+        }
+
+        if (mExpandedActionView == null && showTitle) {
+            availableWidth = measureChildView(mTitleLayout, availableWidth,
+                    MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY), 0);
+            leftOfCenter = Math.max(0, leftOfCenter - mTitleLayout.getMeasuredWidth());
+        }
+
+        if (mContentHeight <= 0) {
+            int measuredHeight = 0;
+            for (int i = 0; i < childCount; i++) {
+                View v = getChildAt(i);
+                int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
+                if (paddedViewHeight > measuredHeight) {
+                    measuredHeight = paddedViewHeight;
+                }
+            }
+            setMeasuredDimension(contentWidth, measuredHeight);
+        } else {
+            setMeasuredDimension(contentWidth, maxHeight);
+        }
+
+        if (mContextView != null) {
+            mContextView.setContentHeight(getMeasuredHeight());
+        }
+
+        if (mProgressView != null && mProgressView.getVisibility() != GONE) {
+            mProgressView.measure(MeasureSpec.makeMeasureSpec(
+                    contentWidth - mProgressBarPadding * 2, MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.AT_MOST));
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int x = getPaddingLeft();
+        final int y = getPaddingTop();
+        final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
+
+        if (contentHeight <= 0) {
+            // Nothing to do if we can't see anything.
+            return;
+        }
+
+        HomeView homeLayout = mExpandedActionView != null ? mExpandedHomeLayout : mHomeLayout;
+        if (homeLayout.getVisibility() != GONE) {
+            final int leftOffset = homeLayout.getLeftOffset();
+            x += positionChild(homeLayout, x + leftOffset, y, contentHeight) + leftOffset;
+        }
+
+        if (mExpandedActionView == null) {
+            final boolean showTitle = mTitleLayout != null && mTitleLayout.getVisibility() != GONE &&
+                    (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0;
+            if (showTitle) {
+                x += positionChild(mTitleLayout, x, y, contentHeight);
+            }
+
+            switch (mNavigationMode) {
+                case ActionBar.NAVIGATION_MODE_STANDARD:
+                    break;
+                case ActionBar.NAVIGATION_MODE_LIST:
+                    if (mListNavLayout != null) {
+                        if (showTitle) x += mItemPadding;
+                        x += positionChild(mListNavLayout, x, y, contentHeight) + mItemPadding;
+                    }
+                    break;
+                case ActionBar.NAVIGATION_MODE_TABS:
+                    if (mTabScrollView != null) {
+                        if (showTitle) x += mItemPadding;
+                        x += positionChild(mTabScrollView, x, y, contentHeight) + mItemPadding;
+                    }
+                    break;
+            }
+        }
+
+        int menuLeft = r - l - getPaddingRight();
+        if (mMenuView != null && mMenuView.getParent() == this) {
+            positionChildInverse(mMenuView, menuLeft, y, contentHeight);
+            menuLeft -= mMenuView.getMeasuredWidth();
+        }
+
+        if (mIndeterminateProgressView != null &&
+                mIndeterminateProgressView.getVisibility() != GONE) {
+            positionChildInverse(mIndeterminateProgressView, menuLeft, y, contentHeight);
+            menuLeft -= mIndeterminateProgressView.getMeasuredWidth();
+        }
+
+        View customView = null;
+        if (mExpandedActionView != null) {
+            customView = mExpandedActionView;
+        } else if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 &&
+                mCustomNavView != null) {
+            customView = mCustomNavView;
+        }
+        if (customView != null) {
+            ViewGroup.LayoutParams lp = customView.getLayoutParams();
+            final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
+                    (ActionBar.LayoutParams) lp : null;
+
+            final int gravity = ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY;
+            final int navWidth = customView.getMeasuredWidth();
+
+            int topMargin = 0;
+            int bottomMargin = 0;
+            if (ablp != null) {
+                x += ablp.leftMargin;
+                menuLeft -= ablp.rightMargin;
+                topMargin = ablp.topMargin;
+                bottomMargin = ablp.bottomMargin;
+            }
+
+            int hgravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+            // See if we actually have room to truly center; if not push against left or right.
+            if (hgravity == Gravity.CENTER_HORIZONTAL) {
+                final int centeredLeft = ((getRight() - getLeft()) - navWidth) / 2;
+                if (centeredLeft < x) {
+                    hgravity = Gravity.LEFT;
+                } else if (centeredLeft + navWidth > menuLeft) {
+                    hgravity = Gravity.RIGHT;
+                }
+            } else if (gravity == -1) {
+                hgravity = Gravity.LEFT;
+            }
+
+            int xpos = 0;
+            switch (hgravity) {
+                case Gravity.CENTER_HORIZONTAL:
+                    xpos = ((getRight() - getLeft()) - navWidth) / 2;
+                    break;
+                case Gravity.LEFT:
+                    xpos = x;
+                    break;
+                case Gravity.RIGHT:
+                    xpos = menuLeft - navWidth;
+                    break;
+            }
+
+            int vgravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+
+            if (gravity == -1) {
+                vgravity = Gravity.CENTER_VERTICAL;
+            }
+
+            int ypos = 0;
+            switch (vgravity) {
+                case Gravity.CENTER_VERTICAL:
+                    final int paddedTop = getPaddingTop();
+                    final int paddedBottom = getBottom() - getTop() - getPaddingBottom();
+                    ypos = ((paddedBottom - paddedTop) - customView.getMeasuredHeight()) / 2;
+                    break;
+                case Gravity.TOP:
+                    ypos = getPaddingTop() + topMargin;
+                    break;
+                case Gravity.BOTTOM:
+                    ypos = getHeight() - getPaddingBottom() - customView.getMeasuredHeight()
+                            - bottomMargin;
+                    break;
+            }
+            final int customWidth = customView.getMeasuredWidth();
+            customView.layout(xpos, ypos, xpos + customWidth,
+                    ypos + customView.getMeasuredHeight());
+            x += customWidth;
+        }
+
+        if (mProgressView != null) {
+            mProgressView.bringToFront();
+            final int halfProgressHeight = mProgressView.getMeasuredHeight() / 2;
+            mProgressView.layout(mProgressBarPadding, -halfProgressHeight,
+                    mProgressBarPadding + mProgressView.getMeasuredWidth(), halfProgressHeight);
+        }
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new ActionBar.LayoutParams(getContext(), attrs);
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
+        if (lp == null) {
+            lp = generateDefaultLayoutParams();
+        }
+        return lp;
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState state = new SavedState(superState);
+
+        if (mExpandedMenuPresenter != null && mExpandedMenuPresenter.mCurrentExpandedItem != null) {
+            state.expandedMenuItemId = mExpandedMenuPresenter.mCurrentExpandedItem.getItemId();
+        }
+
+        state.isOverflowOpen = isOverflowMenuShowing();
+
+        return state;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable p) {
+        SavedState state = (SavedState) p;
+
+        super.onRestoreInstanceState(state.getSuperState());
+
+        if (state.expandedMenuItemId != 0 &&
+                mExpandedMenuPresenter != null && mOptionsMenu != null) {
+            final MenuItem item = mOptionsMenu.findItem(state.expandedMenuItemId);
+            if (item != null) {
+                item.expandActionView();
+            }
+        }
+
+        if (state.isOverflowOpen) {
+            postShowOverflowMenu();
+        }
+    }
+
+    static class SavedState extends BaseSavedState {
+        int expandedMenuItemId;
+        boolean isOverflowOpen;
+
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        private SavedState(Parcel in) {
+            super(in);
+            expandedMenuItemId = in.readInt();
+            isOverflowOpen = in.readInt() != 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(expandedMenuItemId);
+            out.writeInt(isOverflowOpen ? 1 : 0);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR =
+                new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    public static class HomeView extends FrameLayout {
+        private View mUpView;
+        private ImageView mIconView;
+        private int mUpWidth;
+
+        public HomeView(Context context) {
+            this(context, null);
+        }
+
+        public HomeView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public void setUp(boolean isUp) {
+            mUpView.setVisibility(isUp ? VISIBLE : GONE);
+        }
+
+        public void setIcon(Drawable icon) {
+            mIconView.setImageDrawable(icon);
+        }
+
+        @Override
+        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+            onPopulateAccessibilityEvent(event);
+            return true;
+        }
+
+        @Override
+        public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+                super.onPopulateAccessibilityEvent(event);
+            }
+            final CharSequence cdesc = getContentDescription();
+            if (!TextUtils.isEmpty(cdesc)) {
+                event.getText().add(cdesc);
+            }
+        }
+
+        @Override
+        public boolean dispatchHoverEvent(MotionEvent event) {
+            // Don't allow children to hover; we want this to be treated as a single component.
+            return onHoverEvent(event);
+        }
+
+        @Override
+        protected void onFinishInflate() {
+            mUpView = findViewById(R.id.abs__up);
+            mIconView = (ImageView) findViewById(R.id.abs__home);
+        }
+
+        public int getLeftOffset() {
+            return mUpView.getVisibility() == GONE ? mUpWidth : 0;
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            measureChildWithMargins(mUpView, widthMeasureSpec, 0, heightMeasureSpec, 0);
+            final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
+            mUpWidth = upLp.leftMargin + mUpView.getMeasuredWidth() + upLp.rightMargin;
+            int width = mUpView.getVisibility() == GONE ? 0 : mUpWidth;
+            int height = upLp.topMargin + mUpView.getMeasuredHeight() + upLp.bottomMargin;
+            measureChildWithMargins(mIconView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+            width += iconLp.leftMargin + mIconView.getMeasuredWidth() + iconLp.rightMargin;
+            height = Math.max(height,
+                    iconLp.topMargin + mIconView.getMeasuredHeight() + iconLp.bottomMargin);
+
+            final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+            final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+            final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+            final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+            switch (widthMode) {
+                case MeasureSpec.AT_MOST:
+                    width = Math.min(width, widthSize);
+                    break;
+                case MeasureSpec.EXACTLY:
+                    width = widthSize;
+                    break;
+                case MeasureSpec.UNSPECIFIED:
+                default:
+                    break;
+            }
+            switch (heightMode) {
+                case MeasureSpec.AT_MOST:
+                    height = Math.min(height, heightSize);
+                    break;
+                case MeasureSpec.EXACTLY:
+                    height = heightSize;
+                    break;
+                case MeasureSpec.UNSPECIFIED:
+                default:
+                    break;
+            }
+            setMeasuredDimension(width, height);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            final int vCenter = (b - t) / 2;
+            //UNUSED int width = r - l;
+            int upOffset = 0;
+            if (mUpView.getVisibility() != GONE) {
+                final LayoutParams upLp = (LayoutParams) mUpView.getLayoutParams();
+                final int upHeight = mUpView.getMeasuredHeight();
+                final int upWidth = mUpView.getMeasuredWidth();
+                final int upTop = vCenter - upHeight / 2;
+                mUpView.layout(0, upTop, upWidth, upTop + upHeight);
+                upOffset = upLp.leftMargin + upWidth + upLp.rightMargin;
+                //UNUSED width -= upOffset;
+                l += upOffset;
+            }
+            final LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
+            final int iconHeight = mIconView.getMeasuredHeight();
+            final int iconWidth = mIconView.getMeasuredWidth();
+            final int hCenter = (r - l) / 2;
+            final int iconLeft = upOffset + Math.max(iconLp.leftMargin, hCenter - iconWidth / 2);
+            final int iconTop = Math.max(iconLp.topMargin, vCenter - iconHeight / 2);
+            mIconView.layout(iconLeft, iconTop, iconLeft + iconWidth, iconTop + iconHeight);
+        }
+    }
+
+    private class ExpandedActionViewMenuPresenter implements MenuPresenter {
+        MenuBuilder mMenu;
+        MenuItemImpl mCurrentExpandedItem;
+
+        @Override
+        public void initForMenu(Context context, MenuBuilder menu) {
+            // Clear the expanded action view when menus change.
+            if (mMenu != null && mCurrentExpandedItem != null) {
+                mMenu.collapseItemActionView(mCurrentExpandedItem);
+            }
+            mMenu = menu;
+        }
+
+        @Override
+        public MenuView getMenuView(ViewGroup root) {
+            return null;
+        }
+
+        @Override
+        public void updateMenuView(boolean cleared) {
+            // Make sure the expanded item we have is still there.
+            if (mCurrentExpandedItem != null) {
+                boolean found = false;
+
+                if (mMenu != null) {
+                    final int count = mMenu.size();
+                    for (int i = 0; i < count; i++) {
+                        final MenuItem item = mMenu.getItem(i);
+                        if (item == mCurrentExpandedItem) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+
+                if (!found) {
+                    // The item we had expanded disappeared. Collapse.
+                    collapseItemActionView(mMenu, mCurrentExpandedItem);
+                }
+            }
+        }
+
+        @Override
+        public void setCallback(Callback cb) {
+        }
+
+        @Override
+        public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+            return false;
+        }
+
+        @Override
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        }
+
+        @Override
+        public boolean flagActionItems() {
+            return false;
+        }
+
+        @Override
+        public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            mExpandedActionView = item.getActionView();
+            mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(/* TODO getResources() */));
+            mCurrentExpandedItem = item;
+            if (mExpandedActionView.getParent() != ActionBarView.this) {
+                addView(mExpandedActionView);
+            }
+            if (mExpandedHomeLayout.getParent() != ActionBarView.this) {
+                addView(mExpandedHomeLayout);
+            }
+            mHomeLayout.setVisibility(GONE);
+            if (mTitleLayout != null) mTitleLayout.setVisibility(GONE);
+            if (mTabScrollView != null) mTabScrollView.setVisibility(GONE);
+            if (mSpinner != null) mSpinner.setVisibility(GONE);
+            if (mCustomNavView != null) mCustomNavView.setVisibility(GONE);
+            requestLayout();
+            item.setActionViewExpanded(true);
+
+            if (mExpandedActionView instanceof CollapsibleActionView) {
+                ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
+            }
+
+            return true;
+        }
+
+        @Override
+        public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            // Do this before detaching the actionview from the hierarchy, in case
+            // it needs to dismiss the soft keyboard, etc.
+            if (mExpandedActionView instanceof CollapsibleActionView) {
+                ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
+            }
+
+            removeView(mExpandedActionView);
+            removeView(mExpandedHomeLayout);
+            mExpandedActionView = null;
+            if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0) {
+                mHomeLayout.setVisibility(VISIBLE);
+            }
+            if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                if (mTitleLayout == null) {
+                    initTitle();
+                } else {
+                    mTitleLayout.setVisibility(VISIBLE);
+                }
+            }
+            if (mTabScrollView != null && mNavigationMode == ActionBar.NAVIGATION_MODE_TABS) {
+                mTabScrollView.setVisibility(VISIBLE);
+            }
+            if (mSpinner != null && mNavigationMode == ActionBar.NAVIGATION_MODE_LIST) {
+                mSpinner.setVisibility(VISIBLE);
+            }
+            if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+                mCustomNavView.setVisibility(VISIBLE);
+            }
+            mExpandedHomeLayout.setIcon(null);
+            mCurrentExpandedItem = null;
+            requestLayout();
+            item.setActionViewExpanded(false);
+
+            return true;
+        }
+
+        @Override
+        public int getId() {
+            return 0;
+        }
+
+        @Override
+        public Parcelable onSaveInstanceState() {
+            return null;
+        }
+
+        @Override
+        public void onRestoreInstanceState(Parcelable state) {
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/CapitalizingButton.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/CapitalizingButton.java
new file mode 100644 (file)
index 0000000..fa3698f
--- /dev/null
@@ -0,0 +1,40 @@
+package com.actionbarsherlock.internal.widget;
+
+import java.util.Locale;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.widget.Button;
+
+public class CapitalizingButton extends Button {
+    private static final boolean SANS_ICE_CREAM = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+    private static final boolean IS_GINGERBREAD = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
+
+    private static final int[] R_styleable_Button = new int[] {
+        android.R.attr.textAllCaps
+    };
+    private static final int R_styleable_Button_textAllCaps = 0;
+
+    private boolean mAllCaps;
+
+    public CapitalizingButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R_styleable_Button);
+        mAllCaps = a.getBoolean(R_styleable_Button_textAllCaps, true);
+        a.recycle();
+    }
+
+    public void setTextCompat(CharSequence text) {
+        if (SANS_ICE_CREAM && mAllCaps && text != null) {
+            if (IS_GINGERBREAD) {
+                setText(text.toString().toUpperCase(Locale.ROOT));
+            } else {
+                setText(text.toString().toUpperCase());
+            }
+        } else {
+            setText(text);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/CapitalizingTextView.java
new file mode 100644 (file)
index 0000000..673ec55
--- /dev/null
@@ -0,0 +1,44 @@
+package com.actionbarsherlock.internal.widget;
+
+import java.util.Locale;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+public class CapitalizingTextView extends TextView {
+    private static final boolean SANS_ICE_CREAM = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
+    private static final boolean IS_GINGERBREAD = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
+
+    private static final int[] R_styleable_TextView = new int[] {
+        android.R.attr.textAllCaps
+    };
+    private static final int R_styleable_TextView_textAllCaps = 0;
+
+    private boolean mAllCaps;
+
+    public CapitalizingTextView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public CapitalizingTextView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R_styleable_TextView, defStyle, 0);
+        mAllCaps = a.getBoolean(R_styleable_TextView_textAllCaps, true);
+        a.recycle();
+    }
+
+    public void setTextCompat(CharSequence text) {
+        if (SANS_ICE_CREAM && mAllCaps && text != null) {
+            if (IS_GINGERBREAD) {
+                setText(text.toString().toUpperCase(Locale.ROOT));
+            } else {
+                setText(text.toString().toUpperCase());
+            }
+        } else {
+            setText(text);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/FakeDialogPhoneWindow.java
new file mode 100644 (file)
index 0000000..ad1b4f0
--- /dev/null
@@ -0,0 +1,64 @@
+package com.actionbarsherlock.internal.widget;
+
+import static android.view.View.MeasureSpec.EXACTLY;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.widget.LinearLayout;
+import com.actionbarsherlock.R;
+
+public class FakeDialogPhoneWindow extends LinearLayout {
+    final TypedValue mMinWidthMajor = new TypedValue();
+    final TypedValue mMinWidthMinor = new TypedValue();
+
+    public FakeDialogPhoneWindow(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockTheme);
+
+        a.getValue(R.styleable.SherlockTheme_windowMinWidthMajor, mMinWidthMajor);
+        a.getValue(R.styleable.SherlockTheme_windowMinWidthMinor, mMinWidthMinor);
+
+        a.recycle();
+    }
+
+    /* Stolen from PhoneWindow */
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
+        final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
+
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+        int width = getMeasuredWidth();
+        boolean measure = false;
+
+        widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
+
+        final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
+
+        if (tv.type != TypedValue.TYPE_NULL) {
+            final int min;
+            if (tv.type == TypedValue.TYPE_DIMENSION) {
+                min = (int)tv.getDimension(metrics);
+            } else if (tv.type == TypedValue.TYPE_FRACTION) {
+                min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
+            } else {
+                min = 0;
+            }
+
+            if (width < min) {
+                widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
+                measure = true;
+            }
+        }
+
+        // TODO: Support height?
+
+        if (measure) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsAbsSpinner.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsAbsSpinner.java
new file mode 100644 (file)
index 0000000..ce0cb3b
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SpinnerAdapter;
+
+/**
+ * An abstract base class for spinner widgets. SDK users will probably not
+ * need to use this class.
+ *
+ * @attr ref android.R.styleable#AbsSpinner_entries
+ */
+public abstract class IcsAbsSpinner extends IcsAdapterView<SpinnerAdapter> {
+    private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
+
+    SpinnerAdapter mAdapter;
+
+    int mHeightMeasureSpec;
+    int mWidthMeasureSpec;
+    boolean mBlockLayoutRequests;
+
+    int mSelectionLeftPadding = 0;
+    int mSelectionTopPadding = 0;
+    int mSelectionRightPadding = 0;
+    int mSelectionBottomPadding = 0;
+    final Rect mSpinnerPadding = new Rect();
+
+    final RecycleBin mRecycler = new RecycleBin();
+    private DataSetObserver mDataSetObserver;
+
+    /** Temporary frame to hold a child View's frame rectangle */
+    private Rect mTouchFrame;
+
+    public IcsAbsSpinner(Context context) {
+        super(context);
+        initAbsSpinner();
+    }
+
+    public IcsAbsSpinner(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public IcsAbsSpinner(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        initAbsSpinner();
+
+        /*
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.AbsSpinner, defStyle, 0);
+
+        CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
+        if (entries != null) {
+            ArrayAdapter<CharSequence> adapter =
+                    new ArrayAdapter<CharSequence>(context,
+                            R.layout.simple_spinner_item, entries);
+            adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
+            setAdapter(adapter);
+        }
+
+        a.recycle();
+        */
+    }
+
+    /**
+     * Common code for different constructor flavors
+     */
+    private void initAbsSpinner() {
+        setFocusable(true);
+        setWillNotDraw(false);
+    }
+
+    /**
+     * The Adapter is used to provide the data which backs this Spinner.
+     * It also provides methods to transform spinner items based on their position
+     * relative to the selected item.
+     * @param adapter The SpinnerAdapter to use for this Spinner
+     */
+    @Override
+    public void setAdapter(SpinnerAdapter adapter) {
+        if (null != mAdapter) {
+            mAdapter.unregisterDataSetObserver(mDataSetObserver);
+            resetList();
+        }
+
+        mAdapter = adapter;
+
+        mOldSelectedPosition = INVALID_POSITION;
+        mOldSelectedRowId = INVALID_ROW_ID;
+
+        if (mAdapter != null) {
+            mOldItemCount = mItemCount;
+            mItemCount = mAdapter.getCount();
+            checkFocus();
+
+            mDataSetObserver = new AdapterDataSetObserver();
+            mAdapter.registerDataSetObserver(mDataSetObserver);
+
+            int position = mItemCount > 0 ? 0 : INVALID_POSITION;
+
+            setSelectedPositionInt(position);
+            setNextSelectedPositionInt(position);
+
+            if (mItemCount == 0) {
+                // Nothing selected
+                checkSelectionChanged();
+            }
+
+        } else {
+            checkFocus();
+            resetList();
+            // Nothing selected
+            checkSelectionChanged();
+        }
+
+        requestLayout();
+    }
+
+    /**
+     * Clear out all children from the list
+     */
+    void resetList() {
+        mDataChanged = false;
+        mNeedSync = false;
+
+        removeAllViewsInLayout();
+        mOldSelectedPosition = INVALID_POSITION;
+        mOldSelectedRowId = INVALID_ROW_ID;
+
+        setSelectedPositionInt(INVALID_POSITION);
+        setNextSelectedPositionInt(INVALID_POSITION);
+        invalidate();
+    }
+
+    /**
+     * @see android.view.View#measure(int, int)
+     *
+     * Figure out the dimensions of this Spinner. The width comes from
+     * the widthMeasureSpec as Spinnners can't have their width set to
+     * UNSPECIFIED. The height is based on the height of the selected item
+     * plus padding.
+     */
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        int widthSize;
+        int heightSize;
+
+        final int mPaddingLeft = getPaddingLeft();
+        final int mPaddingTop = getPaddingTop();
+        final int mPaddingRight = getPaddingRight();
+        final int mPaddingBottom = getPaddingBottom();
+
+        mSpinnerPadding.left = mPaddingLeft > mSelectionLeftPadding ? mPaddingLeft
+                : mSelectionLeftPadding;
+        mSpinnerPadding.top = mPaddingTop > mSelectionTopPadding ? mPaddingTop
+                : mSelectionTopPadding;
+        mSpinnerPadding.right = mPaddingRight > mSelectionRightPadding ? mPaddingRight
+                : mSelectionRightPadding;
+        mSpinnerPadding.bottom = mPaddingBottom > mSelectionBottomPadding ? mPaddingBottom
+                : mSelectionBottomPadding;
+
+        if (mDataChanged) {
+            handleDataChanged();
+        }
+
+        int preferredHeight = 0;
+        int preferredWidth = 0;
+        boolean needsMeasuring = true;
+
+        int selectedPosition = getSelectedItemPosition();
+        if (selectedPosition >= 0 && mAdapter != null && selectedPosition < mAdapter.getCount()) {
+            // Try looking in the recycler. (Maybe we were measured once already)
+            View view = mRecycler.get(selectedPosition);
+            if (view == null) {
+                // Make a new one
+                view = mAdapter.getView(selectedPosition, null, this);
+            }
+
+            if (view != null) {
+                // Put in recycler for re-measuring and/or layout
+                mRecycler.put(selectedPosition, view);
+            }
+
+            if (view != null) {
+                if (view.getLayoutParams() == null) {
+                    mBlockLayoutRequests = true;
+                    view.setLayoutParams(generateDefaultLayoutParams());
+                    mBlockLayoutRequests = false;
+                }
+                measureChild(view, widthMeasureSpec, heightMeasureSpec);
+
+                preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom;
+                preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right;
+
+                needsMeasuring = false;
+            }
+        }
+
+        if (needsMeasuring) {
+            // No views -- just use padding
+            preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom;
+            if (widthMode == MeasureSpec.UNSPECIFIED) {
+                preferredWidth = mSpinnerPadding.left + mSpinnerPadding.right;
+            }
+        }
+
+        preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight());
+        preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth());
+
+        if (IS_HONEYCOMB) {
+            heightSize = resolveSizeAndState(preferredHeight, heightMeasureSpec, 0);
+            widthSize = resolveSizeAndState(preferredWidth, widthMeasureSpec, 0);
+        } else {
+            heightSize = resolveSize(preferredHeight, heightMeasureSpec);
+            widthSize = resolveSize(preferredWidth, widthMeasureSpec);
+        }
+
+        setMeasuredDimension(widthSize, heightSize);
+        mHeightMeasureSpec = heightMeasureSpec;
+        mWidthMeasureSpec = widthMeasureSpec;
+    }
+
+    int getChildHeight(View child) {
+        return child.getMeasuredHeight();
+    }
+
+    int getChildWidth(View child) {
+        return child.getMeasuredWidth();
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+    }
+
+    void recycleAllViews() {
+        final int childCount = getChildCount();
+        final IcsAbsSpinner.RecycleBin recycleBin = mRecycler;
+        final int position = mFirstPosition;
+
+        // All views go in recycler
+        for (int i = 0; i < childCount; i++) {
+            View v = getChildAt(i);
+            int index = position + i;
+            recycleBin.put(index, v);
+        }
+    }
+
+    /**
+     * Jump directly to a specific item in the adapter data.
+     */
+    public void setSelection(int position, boolean animate) {
+        // Animate only if requested position is already on screen somewhere
+        boolean shouldAnimate = animate && mFirstPosition <= position &&
+                position <= mFirstPosition + getChildCount() - 1;
+        setSelectionInt(position, shouldAnimate);
+    }
+
+    @Override
+    public void setSelection(int position) {
+        setNextSelectedPositionInt(position);
+        requestLayout();
+        invalidate();
+    }
+
+
+    /**
+     * Makes the item at the supplied position selected.
+     *
+     * @param position Position to select
+     * @param animate Should the transition be animated
+     *
+     */
+    void setSelectionInt(int position, boolean animate) {
+        if (position != mOldSelectedPosition) {
+            mBlockLayoutRequests = true;
+            int delta  = position - mSelectedPosition;
+            setNextSelectedPositionInt(position);
+            layout(delta, animate);
+            mBlockLayoutRequests = false;
+        }
+    }
+
+    abstract void layout(int delta, boolean animate);
+
+    @Override
+    public View getSelectedView() {
+        if (mItemCount > 0 && mSelectedPosition >= 0) {
+            return getChildAt(mSelectedPosition - mFirstPosition);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Override to prevent spamming ourselves with layout requests
+     * as we place views
+     *
+     * @see android.view.View#requestLayout()
+     */
+    @Override
+    public void requestLayout() {
+        if (!mBlockLayoutRequests) {
+            super.requestLayout();
+        }
+    }
+
+    @Override
+    public SpinnerAdapter getAdapter() {
+        return mAdapter;
+    }
+
+    @Override
+    public int getCount() {
+        return mItemCount;
+    }
+
+    /**
+     * Maps a point to a position in the list.
+     *
+     * @param x X in local coordinate
+     * @param y Y in local coordinate
+     * @return The position of the item which contains the specified point, or
+     *         {@link #INVALID_POSITION} if the point does not intersect an item.
+     */
+    public int pointToPosition(int x, int y) {
+        Rect frame = mTouchFrame;
+        if (frame == null) {
+            mTouchFrame = new Rect();
+            frame = mTouchFrame;
+        }
+
+        final int count = getChildCount();
+        for (int i = count - 1; i >= 0; i--) {
+            View child = getChildAt(i);
+            if (child.getVisibility() == View.VISIBLE) {
+                child.getHitRect(frame);
+                if (frame.contains(x, y)) {
+                    return mFirstPosition + i;
+                }
+            }
+        }
+        return INVALID_POSITION;
+    }
+
+    static class SavedState extends BaseSavedState {
+        long selectedId;
+        int position;
+
+        /**
+         * Constructor called from {@link AbsSpinner#onSaveInstanceState()}
+         */
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        /**
+         * Constructor called from {@link #CREATOR}
+         */
+        private SavedState(Parcel in) {
+            super(in);
+            selectedId = in.readLong();
+            position = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeLong(selectedId);
+            out.writeInt(position);
+        }
+
+        @Override
+        public String toString() {
+            return "AbsSpinner.SavedState{"
+                    + Integer.toHexString(System.identityHashCode(this))
+                    + " selectedId=" + selectedId
+                    + " position=" + position + "}";
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+        ss.selectedId = getSelectedItemId();
+        if (ss.selectedId >= 0) {
+            ss.position = getSelectedItemPosition();
+        } else {
+            ss.position = INVALID_POSITION;
+        }
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        SavedState ss = (SavedState) state;
+
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        if (ss.selectedId >= 0) {
+            mDataChanged = true;
+            mNeedSync = true;
+            mSyncRowId = ss.selectedId;
+            mSyncPosition = ss.position;
+            mSyncMode = SYNC_SELECTED_POSITION;
+            requestLayout();
+        }
+    }
+
+    class RecycleBin {
+        private final SparseArray<View> mScrapHeap = new SparseArray<View>();
+
+        public void put(int position, View v) {
+            mScrapHeap.put(position, v);
+        }
+
+        View get(int position) {
+            // System.out.print("Looking for " + position);
+            View result = mScrapHeap.get(position);
+            if (result != null) {
+                // System.out.println(" HIT");
+                mScrapHeap.delete(position);
+            } else {
+                // System.out.println(" MISS");
+            }
+            return result;
+        }
+
+        void clear() {
+            final SparseArray<View> scrapHeap = mScrapHeap;
+            final int count = scrapHeap.size();
+            for (int i = 0; i < count; i++) {
+                final View view = scrapHeap.valueAt(i);
+                if (view != null) {
+                    removeDetachedView(view, true);
+                }
+            }
+            scrapHeap.clear();
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsAdapterView.java
new file mode 100644 (file)
index 0000000..c786dc5
--- /dev/null
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.ContextMenu;
+import android.view.SoundEffectConstants;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Adapter;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ListView;
+
+
+/**
+ * An AdapterView is a view whose children are determined by an {@link Adapter}.
+ *
+ * <p>
+ * See {@link ListView}, {@link GridView}, {@link Spinner} and
+ *      {@link Gallery} for commonly used subclasses of AdapterView.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about using AdapterView, read the
+ * <a href="{@docRoot}guide/topics/ui/binding.html">Binding to Data with AdapterView</a>
+ * developer guide.</p></div>
+ */
+public abstract class IcsAdapterView<T extends Adapter> extends ViewGroup {
+
+    /**
+     * The item view type returned by {@link Adapter#getItemViewType(int)} when
+     * the adapter does not want the item's view recycled.
+     */
+    public static final int ITEM_VIEW_TYPE_IGNORE = -1;
+
+    /**
+     * The item view type returned by {@link Adapter#getItemViewType(int)} when
+     * the item is a header or footer.
+     */
+    public static final int ITEM_VIEW_TYPE_HEADER_OR_FOOTER = -2;
+
+    /**
+     * The position of the first child displayed
+     */
+    @ViewDebug.ExportedProperty(category = "scrolling")
+    int mFirstPosition = 0;
+
+    /**
+     * The offset in pixels from the top of the AdapterView to the top
+     * of the view to select during the next layout.
+     */
+    int mSpecificTop;
+
+    /**
+     * Position from which to start looking for mSyncRowId
+     */
+    int mSyncPosition;
+
+    /**
+     * Row id to look for when data has changed
+     */
+    long mSyncRowId = INVALID_ROW_ID;
+
+    /**
+     * Height of the view when mSyncPosition and mSyncRowId where set
+     */
+    long mSyncHeight;
+
+    /**
+     * True if we need to sync to mSyncRowId
+     */
+    boolean mNeedSync = false;
+
+    /**
+     * Indicates whether to sync based on the selection or position. Possible
+     * values are {@link #SYNC_SELECTED_POSITION} or
+     * {@link #SYNC_FIRST_POSITION}.
+     */
+    int mSyncMode;
+
+    /**
+     * Our height after the last layout
+     */
+    private int mLayoutHeight;
+
+    /**
+     * Sync based on the selected child
+     */
+    static final int SYNC_SELECTED_POSITION = 0;
+
+    /**
+     * Sync based on the first child displayed
+     */
+    static final int SYNC_FIRST_POSITION = 1;
+
+    /**
+     * Maximum amount of time to spend in {@link #findSyncPosition()}
+     */
+    static final int SYNC_MAX_DURATION_MILLIS = 100;
+
+    /**
+     * Indicates that this view is currently being laid out.
+     */
+    boolean mInLayout = false;
+
+    /**
+     * The listener that receives notifications when an item is selected.
+     */
+    OnItemSelectedListener mOnItemSelectedListener;
+
+    /**
+     * The listener that receives notifications when an item is clicked.
+     */
+    OnItemClickListener mOnItemClickListener;
+
+    /**
+     * The listener that receives notifications when an item is long clicked.
+     */
+    OnItemLongClickListener mOnItemLongClickListener;
+
+    /**
+     * True if the data has changed since the last layout
+     */
+    boolean mDataChanged;
+
+    /**
+     * The position within the adapter's data set of the item to select
+     * during the next layout.
+     */
+    @ViewDebug.ExportedProperty(category = "list")
+    int mNextSelectedPosition = INVALID_POSITION;
+
+    /**
+     * The item id of the item to select during the next layout.
+     */
+    long mNextSelectedRowId = INVALID_ROW_ID;
+
+    /**
+     * The position within the adapter's data set of the currently selected item.
+     */
+    @ViewDebug.ExportedProperty(category = "list")
+    int mSelectedPosition = INVALID_POSITION;
+
+    /**
+     * The item id of the currently selected item.
+     */
+    long mSelectedRowId = INVALID_ROW_ID;
+
+    /**
+     * View to show if there are no items to show.
+     */
+    private View mEmptyView;
+
+    /**
+     * The number of items in the current adapter.
+     */
+    @ViewDebug.ExportedProperty(category = "list")
+    int mItemCount;
+
+    /**
+     * The number of items in the adapter before a data changed event occurred.
+     */
+    int mOldItemCount;
+
+    /**
+     * Represents an invalid position. All valid positions are in the range 0 to 1 less than the
+     * number of items in the current adapter.
+     */
+    public static final int INVALID_POSITION = -1;
+
+    /**
+     * Represents an empty or invalid row id
+     */
+    public static final long INVALID_ROW_ID = Long.MIN_VALUE;
+
+    /**
+     * The last selected position we used when notifying
+     */
+    int mOldSelectedPosition = INVALID_POSITION;
+
+    /**
+     * The id of the last selected position we used when notifying
+     */
+    long mOldSelectedRowId = INVALID_ROW_ID;
+
+    /**
+     * Indicates what focusable state is requested when calling setFocusable().
+     * In addition to this, this view has other criteria for actually
+     * determining the focusable state (such as whether its empty or the text
+     * filter is shown).
+     *
+     * @see #setFocusable(boolean)
+     * @see #checkFocus()
+     */
+    private boolean mDesiredFocusableState;
+    private boolean mDesiredFocusableInTouchModeState;
+
+    private SelectionNotifier mSelectionNotifier;
+    /**
+     * When set to true, calls to requestLayout() will not propagate up the parent hierarchy.
+     * This is used to layout the children during a layout pass.
+     */
+    boolean mBlockLayoutRequests = false;
+
+    public IcsAdapterView(Context context) {
+        super(context);
+    }
+
+    public IcsAdapterView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public IcsAdapterView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    /**
+     * Register a callback to be invoked when an item in this AdapterView has
+     * been clicked.
+     *
+     * @param listener The callback that will be invoked.
+     */
+    public void setOnItemClickListener(OnItemClickListener listener) {
+        mOnItemClickListener = listener;
+    }
+
+    /**
+     * @return The callback to be invoked with an item in this AdapterView has
+     *         been clicked, or null id no callback has been set.
+     */
+    public final OnItemClickListener getOnItemClickListener() {
+        return mOnItemClickListener;
+    }
+
+    /**
+     * Call the OnItemClickListener, if it is defined.
+     *
+     * @param view The view within the AdapterView that was clicked.
+     * @param position The position of the view in the adapter.
+     * @param id The row id of the item that was clicked.
+     * @return True if there was an assigned OnItemClickListener that was
+     *         called, false otherwise is returned.
+     */
+    public boolean performItemClick(View view, int position, long id) {
+        if (mOnItemClickListener != null) {
+            playSoundEffect(SoundEffectConstants.CLICK);
+            if (view != null) {
+                view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
+            }
+            mOnItemClickListener.onItemClick(/*this*/null, view, position, id);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when an item in this
+     * view has been clicked and held.
+     */
+    public interface OnItemLongClickListener {
+        /**
+         * Callback method to be invoked when an item in this view has been
+         * clicked and held.
+         *
+         * Implementers can call getItemAtPosition(position) if they need to access
+         * the data associated with the selected item.
+         *
+         * @param parent The AbsListView where the click happened
+         * @param view The view within the AbsListView that was clicked
+         * @param position The position of the view in the list
+         * @param id The row id of the item that was clicked
+         *
+         * @return true if the callback consumed the long click, false otherwise
+         */
+        boolean onItemLongClick(IcsAdapterView<?> parent, View view, int position, long id);
+    }
+
+
+    /**
+     * Register a callback to be invoked when an item in this AdapterView has
+     * been clicked and held
+     *
+     * @param listener The callback that will run
+     */
+    public void setOnItemLongClickListener(OnItemLongClickListener listener) {
+        if (!isLongClickable()) {
+            setLongClickable(true);
+        }
+        mOnItemLongClickListener = listener;
+    }
+
+    /**
+     * @return The callback to be invoked with an item in this AdapterView has
+     *         been clicked and held, or null id no callback as been set.
+     */
+    public final OnItemLongClickListener getOnItemLongClickListener() {
+        return mOnItemLongClickListener;
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when
+     * an item in this view has been selected.
+     */
+    public interface OnItemSelectedListener {
+        /**
+         * <p>Callback method to be invoked when an item in this view has been
+         * selected. This callback is invoked only when the newly selected
+         * position is different from the previously selected position or if
+         * there was no selected item.</p>
+         *
+         * Impelmenters can call getItemAtPosition(position) if they need to access the
+         * data associated with the selected item.
+         *
+         * @param parent The AdapterView where the selection happened
+         * @param view The view within the AdapterView that was clicked
+         * @param position The position of the view in the adapter
+         * @param id The row id of the item that is selected
+         */
+        void onItemSelected(IcsAdapterView<?> parent, View view, int position, long id);
+
+        /**
+         * Callback method to be invoked when the selection disappears from this
+         * view. The selection can disappear for instance when touch is activated
+         * or when the adapter becomes empty.
+         *
+         * @param parent The AdapterView that now contains no selected item.
+         */
+        void onNothingSelected(IcsAdapterView<?> parent);
+    }
+
+
+    /**
+     * Register a callback to be invoked when an item in this AdapterView has
+     * been selected.
+     *
+     * @param listener The callback that will run
+     */
+    public void setOnItemSelectedListener(OnItemSelectedListener listener) {
+        mOnItemSelectedListener = listener;
+    }
+
+    public final OnItemSelectedListener getOnItemSelectedListener() {
+        return mOnItemSelectedListener;
+    }
+
+    /**
+     * Extra menu information provided to the
+     * {@link android.view.View.OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) }
+     * callback when a context menu is brought up for this AdapterView.
+     *
+     */
+    public static class AdapterContextMenuInfo implements ContextMenu.ContextMenuInfo {
+
+        public AdapterContextMenuInfo(View targetView, int position, long id) {
+            this.targetView = targetView;
+            this.position = position;
+            this.id = id;
+        }
+
+        /**
+         * The child view for which the context menu is being displayed. This
+         * will be one of the children of this AdapterView.
+         */
+        public View targetView;
+
+        /**
+         * The position in the adapter for which the context menu is being
+         * displayed.
+         */
+        public int position;
+
+        /**
+         * The row id of the item for which the context menu is being displayed.
+         */
+        public long id;
+    }
+
+    /**
+     * Returns the adapter currently associated with this widget.
+     *
+     * @return The adapter used to provide this view's content.
+     */
+    public abstract T getAdapter();
+
+    /**
+     * Sets the adapter that provides the data and the views to represent the data
+     * in this widget.
+     *
+     * @param adapter The adapter to use to create this view's content.
+     */
+    public abstract void setAdapter(T adapter);
+
+    /**
+     * This method is not supported and throws an UnsupportedOperationException when called.
+     *
+     * @param child Ignored.
+     *
+     * @throws UnsupportedOperationException Every time this method is invoked.
+     */
+    @Override
+    public void addView(View child) {
+        throw new UnsupportedOperationException("addView(View) is not supported in AdapterView");
+    }
+
+    /**
+     * This method is not supported and throws an UnsupportedOperationException when called.
+     *
+     * @param child Ignored.
+     * @param index Ignored.
+     *
+     * @throws UnsupportedOperationException Every time this method is invoked.
+     */
+    @Override
+    public void addView(View child, int index) {
+        throw new UnsupportedOperationException("addView(View, int) is not supported in AdapterView");
+    }
+
+    /**
+     * This method is not supported and throws an UnsupportedOperationException when called.
+     *
+     * @param child Ignored.
+     * @param params Ignored.
+     *
+     * @throws UnsupportedOperationException Every time this method is invoked.
+     */
+    @Override
+    public void addView(View child, LayoutParams params) {
+        throw new UnsupportedOperationException("addView(View, LayoutParams) "
+                + "is not supported in AdapterView");
+    }
+
+    /**
+     * This method is not supported and throws an UnsupportedOperationException when called.
+     *
+     * @param child Ignored.
+     * @param index Ignored.
+     * @param params Ignored.
+     *
+     * @throws UnsupportedOperationException Every time this method is invoked.
+     */
+    @Override
+    public void addView(View child, int index, LayoutParams params) {
+        throw new UnsupportedOperationException("addView(View, int, LayoutParams) "
+                + "is not supported in AdapterView");
+    }
+
+    /**
+     * This method is not supported and throws an UnsupportedOperationException when called.
+     *
+     * @param child Ignored.
+     *
+     * @throws UnsupportedOperationException Every time this method is invoked.
+     */
+    @Override
+    public void removeView(View child) {
+        throw new UnsupportedOperationException("removeView(View) is not supported in AdapterView");
+    }
+
+    /**
+     * This method is not supported and throws an UnsupportedOperationException when called.
+     *
+     * @param index Ignored.
+     *
+     * @throws UnsupportedOperationException Every time this method is invoked.
+     */
+    @Override
+    public void removeViewAt(int index) {
+        throw new UnsupportedOperationException("removeViewAt(int) is not supported in AdapterView");
+    }
+
+    /**
+     * This method is not supported and throws an UnsupportedOperationException when called.
+     *
+     * @throws UnsupportedOperationException Every time this method is invoked.
+     */
+    @Override
+    public void removeAllViews() {
+        throw new UnsupportedOperationException("removeAllViews() is not supported in AdapterView");
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        mLayoutHeight = getHeight();
+    }
+
+    /**
+     * Return the position of the currently selected item within the adapter's data set
+     *
+     * @return int Position (starting at 0), or {@link #INVALID_POSITION} if there is nothing selected.
+     */
+    @ViewDebug.CapturedViewProperty
+    public int getSelectedItemPosition() {
+        return mNextSelectedPosition;
+    }
+
+    /**
+     * @return The id corresponding to the currently selected item, or {@link #INVALID_ROW_ID}
+     * if nothing is selected.
+     */
+    @ViewDebug.CapturedViewProperty
+    public long getSelectedItemId() {
+        return mNextSelectedRowId;
+    }
+
+    /**
+     * @return The view corresponding to the currently selected item, or null
+     * if nothing is selected
+     */
+    public abstract View getSelectedView();
+
+    /**
+     * @return The data corresponding to the currently selected item, or
+     * null if there is nothing selected.
+     */
+    public Object getSelectedItem() {
+        T adapter = getAdapter();
+        int selection = getSelectedItemPosition();
+        if (adapter != null && adapter.getCount() > 0 && selection >= 0) {
+            return adapter.getItem(selection);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @return The number of items owned by the Adapter associated with this
+     *         AdapterView. (This is the number of data items, which may be
+     *         larger than the number of visible views.)
+     */
+    @ViewDebug.CapturedViewProperty
+    public int getCount() {
+        return mItemCount;
+    }
+
+    /**
+     * Get the position within the adapter's data set for the view, where view is a an adapter item
+     * or a descendant of an adapter item.
+     *
+     * @param view an adapter item, or a descendant of an adapter item. This must be visible in this
+     *        AdapterView at the time of the call.
+     * @return the position within the adapter's data set of the view, or {@link #INVALID_POSITION}
+     *         if the view does not correspond to a list item (or it is not currently visible).
+     */
+    public int getPositionForView(View view) {
+        View listItem = view;
+        try {
+            View v;
+            while (!(v = (View) listItem.getParent()).equals(this)) {
+                listItem = v;
+            }
+        } catch (ClassCastException e) {
+            // We made it up to the window without find this list view
+            return INVALID_POSITION;
+        }
+
+        // Search the children for the list item
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            if (getChildAt(i).equals(listItem)) {
+                return mFirstPosition + i;
+            }
+        }
+
+        // Child not found!
+        return INVALID_POSITION;
+    }
+
+    /**
+     * Returns the position within the adapter's data set for the first item
+     * displayed on screen.
+     *
+     * @return The position within the adapter's data set
+     */
+    public int getFirstVisiblePosition() {
+        return mFirstPosition;
+    }
+
+    /**
+     * Returns the position within the adapter's data set for the last item
+     * displayed on screen.
+     *
+     * @return The position within the adapter's data set
+     */
+    public int getLastVisiblePosition() {
+        return mFirstPosition + getChildCount() - 1;
+    }
+
+    /**
+     * Sets the currently selected item. To support accessibility subclasses that
+     * override this method must invoke the overriden super method first.
+     *
+     * @param position Index (starting at 0) of the data item to be selected.
+     */
+    public abstract void setSelection(int position);
+
+    /**
+     * Sets the view to show if the adapter is empty
+     */
+    public void setEmptyView(View emptyView) {
+        mEmptyView = emptyView;
+
+        final T adapter = getAdapter();
+        final boolean empty = ((adapter == null) || adapter.isEmpty());
+        updateEmptyStatus(empty);
+    }
+
+    /**
+     * When the current adapter is empty, the AdapterView can display a special view
+     * call the empty view. The empty view is used to provide feedback to the user
+     * that no data is available in this AdapterView.
+     *
+     * @return The view to show if the adapter is empty.
+     */
+    public View getEmptyView() {
+        return mEmptyView;
+    }
+
+    /**
+     * Indicates whether this view is in filter mode. Filter mode can for instance
+     * be enabled by a user when typing on the keyboard.
+     *
+     * @return True if the view is in filter mode, false otherwise.
+     */
+    boolean isInFilterMode() {
+        return false;
+    }
+
+    @Override
+    public void setFocusable(boolean focusable) {
+        final T adapter = getAdapter();
+        final boolean empty = adapter == null || adapter.getCount() == 0;
+
+        mDesiredFocusableState = focusable;
+        if (!focusable) {
+            mDesiredFocusableInTouchModeState = false;
+        }
+
+        super.setFocusable(focusable && (!empty || isInFilterMode()));
+    }
+
+    @Override
+    public void setFocusableInTouchMode(boolean focusable) {
+        final T adapter = getAdapter();
+        final boolean empty = adapter == null || adapter.getCount() == 0;
+
+        mDesiredFocusableInTouchModeState = focusable;
+        if (focusable) {
+            mDesiredFocusableState = true;
+        }
+
+        super.setFocusableInTouchMode(focusable && (!empty || isInFilterMode()));
+    }
+
+    void checkFocus() {
+        final T adapter = getAdapter();
+        final boolean empty = adapter == null || adapter.getCount() == 0;
+        final boolean focusable = !empty || isInFilterMode();
+        // The order in which we set focusable in touch mode/focusable may matter
+        // for the client, see View.setFocusableInTouchMode() comments for more
+        // details
+        super.setFocusableInTouchMode(focusable && mDesiredFocusableInTouchModeState);
+        super.setFocusable(focusable && mDesiredFocusableState);
+        if (mEmptyView != null) {
+            updateEmptyStatus((adapter == null) || adapter.isEmpty());
+        }
+    }
+
+    /**
+     * Update the status of the list based on the empty parameter.  If empty is true and
+     * we have an empty view, display it.  In all the other cases, make sure that the listview
+     * is VISIBLE and that the empty view is GONE (if it's not null).
+     */
+    private void updateEmptyStatus(boolean empty) {
+        if (isInFilterMode()) {
+            empty = false;
+        }
+
+        if (empty) {
+            if (mEmptyView != null) {
+                mEmptyView.setVisibility(View.VISIBLE);
+                setVisibility(View.GONE);
+            } else {
+                // If the caller just removed our empty view, make sure the list view is visible
+                setVisibility(View.VISIBLE);
+            }
+
+            // We are now GONE, so pending layouts will not be dispatched.
+            // Force one here to make sure that the state of the list matches
+            // the state of the adapter.
+            if (mDataChanged) {
+                this.onLayout(false, getLeft(), getTop(), getRight(), getBottom());
+            }
+        } else {
+            if (mEmptyView != null) mEmptyView.setVisibility(View.GONE);
+            setVisibility(View.VISIBLE);
+        }
+    }
+
+    /**
+     * Gets the data associated with the specified position in the list.
+     *
+     * @param position Which data to get
+     * @return The data associated with the specified position in the list
+     */
+    public Object getItemAtPosition(int position) {
+        T adapter = getAdapter();
+        return (adapter == null || position < 0) ? null : adapter.getItem(position);
+    }
+
+    public long getItemIdAtPosition(int position) {
+        T adapter = getAdapter();
+        return (adapter == null || position < 0) ? INVALID_ROW_ID : adapter.getItemId(position);
+    }
+
+    @Override
+    public void setOnClickListener(OnClickListener l) {
+        throw new RuntimeException("Don't call setOnClickListener for an AdapterView. "
+                + "You probably want setOnItemClickListener instead");
+    }
+
+    /**
+     * Override to prevent freezing of any views created by the adapter.
+     */
+    @Override
+    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
+        dispatchFreezeSelfOnly(container);
+    }
+
+    /**
+     * Override to prevent thawing of any views created by the adapter.
+     */
+    @Override
+    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
+        dispatchThawSelfOnly(container);
+    }
+
+    class AdapterDataSetObserver extends DataSetObserver {
+
+        private Parcelable mInstanceState = null;
+
+        @Override
+        public void onChanged() {
+            mDataChanged = true;
+            mOldItemCount = mItemCount;
+            mItemCount = getAdapter().getCount();
+
+            // Detect the case where a cursor that was previously invalidated has
+            // been repopulated with new data.
+            if (IcsAdapterView.this.getAdapter().hasStableIds() && mInstanceState != null
+                    && mOldItemCount == 0 && mItemCount > 0) {
+                IcsAdapterView.this.onRestoreInstanceState(mInstanceState);
+                mInstanceState = null;
+            } else {
+                rememberSyncState();
+            }
+            checkFocus();
+            requestLayout();
+        }
+
+        @Override
+        public void onInvalidated() {
+            mDataChanged = true;
+
+            if (IcsAdapterView.this.getAdapter().hasStableIds()) {
+                // Remember the current state for the case where our hosting activity is being
+                // stopped and later restarted
+                mInstanceState = IcsAdapterView.this.onSaveInstanceState();
+            }
+
+            // Data is invalid so we should reset our state
+            mOldItemCount = mItemCount;
+            mItemCount = 0;
+            mSelectedPosition = INVALID_POSITION;
+            mSelectedRowId = INVALID_ROW_ID;
+            mNextSelectedPosition = INVALID_POSITION;
+            mNextSelectedRowId = INVALID_ROW_ID;
+            mNeedSync = false;
+
+            checkFocus();
+            requestLayout();
+        }
+
+        public void clearSavedState() {
+            mInstanceState = null;
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        removeCallbacks(mSelectionNotifier);
+    }
+
+    private class SelectionNotifier implements Runnable {
+        public void run() {
+            if (mDataChanged) {
+                // Data has changed between when this SelectionNotifier
+                // was posted and now. We need to wait until the AdapterView
+                // has been synched to the new data.
+                if (getAdapter() != null) {
+                    post(this);
+                }
+            } else {
+                fireOnSelected();
+            }
+        }
+    }
+
+    void selectionChanged() {
+        if (mOnItemSelectedListener != null) {
+            if (mInLayout || mBlockLayoutRequests) {
+                // If we are in a layout traversal, defer notification
+                // by posting. This ensures that the view tree is
+                // in a consistent state and is able to accomodate
+                // new layout or invalidate requests.
+                if (mSelectionNotifier == null) {
+                    mSelectionNotifier = new SelectionNotifier();
+                }
+                post(mSelectionNotifier);
+            } else {
+                fireOnSelected();
+            }
+        }
+
+        // we fire selection events here not in View
+        if (mSelectedPosition != ListView.INVALID_POSITION && isShown() && !isInTouchMode()) {
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        }
+    }
+
+    private void fireOnSelected() {
+        if (mOnItemSelectedListener == null)
+            return;
+
+        int selection = this.getSelectedItemPosition();
+        if (selection >= 0) {
+            View v = getSelectedView();
+            mOnItemSelectedListener.onItemSelected(this, v, selection,
+                    getAdapter().getItemId(selection));
+        } else {
+            mOnItemSelectedListener.onNothingSelected(this);
+        }
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        View selectedView = getSelectedView();
+        if (selectedView != null && selectedView.getVisibility() == VISIBLE
+                && selectedView.dispatchPopulateAccessibilityEvent(event)) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
+        if (super.onRequestSendAccessibilityEvent(child, event)) {
+            // Add a record for ourselves as well.
+            AccessibilityEvent record = AccessibilityEvent.obtain();
+            onInitializeAccessibilityEvent(record);
+            // Populate with the text of the requesting child.
+            child.dispatchPopulateAccessibilityEvent(record);
+            event.appendRecord(record);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setScrollable(isScrollableForAccessibility());
+        View selectedView = getSelectedView();
+        if (selectedView != null) {
+            info.setEnabled(selectedView.isEnabled());
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        event.setScrollable(isScrollableForAccessibility());
+        View selectedView = getSelectedView();
+        if (selectedView != null) {
+            event.setEnabled(selectedView.isEnabled());
+        }
+        event.setCurrentItemIndex(getSelectedItemPosition());
+        event.setFromIndex(getFirstVisiblePosition());
+        event.setToIndex(getLastVisiblePosition());
+        event.setItemCount(getCount());
+    }
+
+    private boolean isScrollableForAccessibility() {
+        T adapter = getAdapter();
+        if (adapter != null) {
+            final int itemCount = adapter.getCount();
+            return itemCount > 0
+                && (getFirstVisiblePosition() > 0 || getLastVisiblePosition() < itemCount - 1);
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean canAnimate() {
+        return super.canAnimate() && mItemCount > 0;
+    }
+
+    void handleDataChanged() {
+        final int count = mItemCount;
+        boolean found = false;
+
+        if (count > 0) {
+
+            int newPos;
+
+            // Find the row we are supposed to sync to
+            if (mNeedSync) {
+                // Update this first, since setNextSelectedPositionInt inspects
+                // it
+                mNeedSync = false;
+
+                // See if we can find a position in the new data with the same
+                // id as the old selection
+                newPos = findSyncPosition();
+                if (newPos >= 0) {
+                    // Verify that new selection is selectable
+                    int selectablePos = lookForSelectablePosition(newPos, true);
+                    if (selectablePos == newPos) {
+                        // Same row id is selected
+                        setNextSelectedPositionInt(newPos);
+                        found = true;
+                    }
+                }
+            }
+            if (!found) {
+                // Try to use the same position if we can't find matching data
+                newPos = getSelectedItemPosition();
+
+                // Pin position to the available range
+                if (newPos >= count) {
+                    newPos = count - 1;
+                }
+                if (newPos < 0) {
+                    newPos = 0;
+                }
+
+                // Make sure we select something selectable -- first look down
+                int selectablePos = lookForSelectablePosition(newPos, true);
+                if (selectablePos < 0) {
+                    // Looking down didn't work -- try looking up
+                    selectablePos = lookForSelectablePosition(newPos, false);
+                }
+                if (selectablePos >= 0) {
+                    setNextSelectedPositionInt(selectablePos);
+                    checkSelectionChanged();
+                    found = true;
+                }
+            }
+        }
+        if (!found) {
+            // Nothing is selected
+            mSelectedPosition = INVALID_POSITION;
+            mSelectedRowId = INVALID_ROW_ID;
+            mNextSelectedPosition = INVALID_POSITION;
+            mNextSelectedRowId = INVALID_ROW_ID;
+            mNeedSync = false;
+            checkSelectionChanged();
+        }
+    }
+
+    void checkSelectionChanged() {
+        if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
+            selectionChanged();
+            mOldSelectedPosition = mSelectedPosition;
+            mOldSelectedRowId = mSelectedRowId;
+        }
+    }
+
+    /**
+     * Searches the adapter for a position matching mSyncRowId. The search starts at mSyncPosition
+     * and then alternates between moving up and moving down until 1) we find the right position, or
+     * 2) we run out of time, or 3) we have looked at every position
+     *
+     * @return Position of the row that matches mSyncRowId, or {@link #INVALID_POSITION} if it can't
+     *         be found
+     */
+    int findSyncPosition() {
+        int count = mItemCount;
+
+        if (count == 0) {
+            return INVALID_POSITION;
+        }
+
+        long idToMatch = mSyncRowId;
+        int seed = mSyncPosition;
+
+        // If there isn't a selection don't hunt for it
+        if (idToMatch == INVALID_ROW_ID) {
+            return INVALID_POSITION;
+        }
+
+        // Pin seed to reasonable values
+        seed = Math.max(0, seed);
+        seed = Math.min(count - 1, seed);
+
+        long endTime = SystemClock.uptimeMillis() + SYNC_MAX_DURATION_MILLIS;
+
+        long rowId;
+
+        // first position scanned so far
+        int first = seed;
+
+        // last position scanned so far
+        int last = seed;
+
+        // True if we should move down on the next iteration
+        boolean next = false;
+
+        // True when we have looked at the first item in the data
+        boolean hitFirst;
+
+        // True when we have looked at the last item in the data
+        boolean hitLast;
+
+        // Get the item ID locally (instead of getItemIdAtPosition), so
+        // we need the adapter
+        T adapter = getAdapter();
+        if (adapter == null) {
+            return INVALID_POSITION;
+        }
+
+        while (SystemClock.uptimeMillis() <= endTime) {
+            rowId = adapter.getItemId(seed);
+            if (rowId == idToMatch) {
+                // Found it!
+                return seed;
+            }
+
+            hitLast = last == count - 1;
+            hitFirst = first == 0;
+
+            if (hitLast && hitFirst) {
+                // Looked at everything
+                break;
+            }
+
+            if (hitFirst || (next && !hitLast)) {
+                // Either we hit the top, or we are trying to move down
+                last++;
+                seed = last;
+                // Try going up next time
+                next = false;
+            } else if (hitLast || (!next && !hitFirst)) {
+                // Either we hit the bottom, or we are trying to move up
+                first--;
+                seed = first;
+                // Try going down next time
+                next = true;
+            }
+
+        }
+
+        return INVALID_POSITION;
+    }
+
+    /**
+     * Find a position that can be selected (i.e., is not a separator).
+     *
+     * @param position The starting position to look at.
+     * @param lookDown Whether to look down for other positions.
+     * @return The next selectable position starting at position and then searching either up or
+     *         down. Returns {@link #INVALID_POSITION} if nothing can be found.
+     */
+    int lookForSelectablePosition(int position, boolean lookDown) {
+        return position;
+    }
+
+    /**
+     * Utility to keep mSelectedPosition and mSelectedRowId in sync
+     * @param position Our current position
+     */
+    void setSelectedPositionInt(int position) {
+        mSelectedPosition = position;
+        mSelectedRowId = getItemIdAtPosition(position);
+    }
+
+    /**
+     * Utility to keep mNextSelectedPosition and mNextSelectedRowId in sync
+     * @param position Intended value for mSelectedPosition the next time we go
+     * through layout
+     */
+    void setNextSelectedPositionInt(int position) {
+        mNextSelectedPosition = position;
+        mNextSelectedRowId = getItemIdAtPosition(position);
+        // If we are trying to sync to the selection, update that too
+        if (mNeedSync && mSyncMode == SYNC_SELECTED_POSITION && position >= 0) {
+            mSyncPosition = position;
+            mSyncRowId = mNextSelectedRowId;
+        }
+    }
+
+    /**
+     * Remember enough information to restore the screen state when the data has
+     * changed.
+     *
+     */
+    void rememberSyncState() {
+        if (getChildCount() > 0) {
+            mNeedSync = true;
+            mSyncHeight = mLayoutHeight;
+            if (mSelectedPosition >= 0) {
+                // Sync the selection state
+                View v = getChildAt(mSelectedPosition - mFirstPosition);
+                mSyncRowId = mNextSelectedRowId;
+                mSyncPosition = mNextSelectedPosition;
+                if (v != null) {
+                    mSpecificTop = v.getTop();
+                }
+                mSyncMode = SYNC_SELECTED_POSITION;
+            } else {
+                // Sync the based on the offset of the first view
+                View v = getChildAt(0);
+                T adapter = getAdapter();
+                if (mFirstPosition >= 0 && mFirstPosition < adapter.getCount()) {
+                    mSyncRowId = adapter.getItemId(mFirstPosition);
+                } else {
+                    mSyncRowId = NO_ID;
+                }
+                mSyncPosition = mFirstPosition;
+                if (v != null) {
+                    mSpecificTop = v.getTop();
+                }
+                mSyncMode = SYNC_FIRST_POSITION;
+            }
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsLinearLayout.java
new file mode 100644 (file)
index 0000000..1b4463a
--- /dev/null
@@ -0,0 +1,272 @@
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
+
+/**
+ * A simple extension of a regular linear layout that supports the divider API
+ * of Android 4.0+. The dividers are added adjacent to the children by changing
+ * their layout params. If you need to rely on the margins which fall in the
+ * same orientation as the layout you should wrap the child in a simple
+ * {@link android.widget.FrameLayout} so it can receive the margin.
+ */
+public class IcsLinearLayout extends NineLinearLayout {
+    private static final int[] LinearLayout = new int[] {
+        /* 0 */ android.R.attr.divider,
+        /* 1 */ android.R.attr.showDividers,
+        /* 2 */ android.R.attr.dividerPadding,
+    };
+    private static final int LinearLayout_divider = 0;
+    private static final int LinearLayout_showDividers = 1;
+    private static final int LinearLayout_dividerPadding = 2;
+
+    /**
+     * Don't show any dividers.
+     */
+    public static final int SHOW_DIVIDER_NONE = 0;
+    /**
+     * Show a divider at the beginning of the group.
+     */
+    public static final int SHOW_DIVIDER_BEGINNING = 1;
+    /**
+     * Show dividers between each item in the group.
+     */
+    public static final int SHOW_DIVIDER_MIDDLE = 2;
+    /**
+     * Show a divider at the end of the group.
+     */
+    public static final int SHOW_DIVIDER_END = 4;
+
+
+    private Drawable mDivider;
+    private int mDividerWidth;
+    private int mDividerHeight;
+    private int mShowDividers;
+    private int mDividerPadding;
+
+
+    public IcsLinearLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/LinearLayout);
+
+        setDividerDrawable(a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider));
+        mShowDividers = a.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers, SHOW_DIVIDER_NONE);
+        mDividerPadding = a.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding, 0);
+
+        a.recycle();
+    }
+
+    /**
+     * Set how dividers should be shown between items in this layout
+     *
+     * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
+     *                     {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
+     *                     or {@link #SHOW_DIVIDER_NONE} to show no dividers.
+     */
+    public void setShowDividers(int showDividers) {
+        if (showDividers != mShowDividers) {
+            requestLayout();
+            invalidate(); //XXX This is required if you are toggling a divider off
+        }
+        mShowDividers = showDividers;
+    }
+
+    /**
+     * @return A flag set indicating how dividers should be shown around items.
+     * @see #setShowDividers(int)
+     */
+    public int getShowDividers() {
+        return mShowDividers;
+    }
+
+    /**
+     * Set a drawable to be used as a divider between items.
+     * @param divider Drawable that will divide each item.
+     * @see #setShowDividers(int)
+     */
+    public void setDividerDrawable(Drawable divider) {
+        if (divider == mDivider) {
+            return;
+        }
+        mDivider = divider;
+        if (divider != null) {
+            mDividerWidth = divider.getIntrinsicWidth();
+            mDividerHeight = divider.getIntrinsicHeight();
+        } else {
+            mDividerWidth = 0;
+            mDividerHeight = 0;
+        }
+        setWillNotDraw(divider == null);
+        requestLayout();
+    }
+
+    /**
+     * Set padding displayed on both ends of dividers.
+     *
+     * @param padding Padding value in pixels that will be applied to each end
+     *
+     * @see #setShowDividers(int)
+     * @see #setDividerDrawable(Drawable)
+     * @see #getDividerPadding()
+     */
+    public void setDividerPadding(int padding) {
+        mDividerPadding = padding;
+    }
+
+    /**
+     * Get the padding size used to inset dividers in pixels
+     *
+     * @see #setShowDividers(int)
+     * @see #setDividerDrawable(Drawable)
+     * @see #setDividerPadding(int)
+     */
+    public int getDividerPadding() {
+        return mDividerPadding;
+    }
+
+    /**
+     * Get the width of the current divider drawable.
+     *
+     * @hide Used internally by framework.
+     */
+    public int getDividerWidth() {
+        return mDividerWidth;
+    }
+
+    @Override
+    protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
+        final int index = indexOfChild(child);
+        final int orientation = getOrientation();
+        final LayoutParams params = (LayoutParams) child.getLayoutParams();
+        if (hasDividerBeforeChildAt(index)) {
+            if (orientation == VERTICAL) {
+                //Account for the divider by pushing everything up
+                params.topMargin = mDividerHeight;
+            } else {
+                //Account for the divider by pushing everything left
+                params.leftMargin = mDividerWidth;
+            }
+        }
+
+        final int count = getChildCount();
+        if (index == count - 1) {
+            if (hasDividerBeforeChildAt(count)) {
+                if (orientation == VERTICAL) {
+                    params.bottomMargin = mDividerHeight;
+                } else {
+                    params.rightMargin = mDividerWidth;
+                }
+            }
+        }
+        super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mDivider != null) {
+            if (getOrientation() == VERTICAL) {
+                drawDividersVertical(canvas);
+            } else {
+                drawDividersHorizontal(canvas);
+            }
+        }
+        super.onDraw(canvas);
+    }
+
+    void drawDividersVertical(Canvas canvas) {
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+
+            if (child != null && child.getVisibility() != GONE) {
+                if (hasDividerBeforeChildAt(i)) {
+                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                    final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
+                    drawHorizontalDivider(canvas, top);
+                }
+            }
+        }
+
+        if (hasDividerBeforeChildAt(count)) {
+            final View child = getChildAt(count - 1);
+            int bottom = 0;
+            if (child == null) {
+                bottom = getHeight() - getPaddingBottom() - mDividerHeight;
+            } else {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                bottom = child.getBottom()/* + lp.bottomMargin*/;
+            }
+            drawHorizontalDivider(canvas, bottom);
+        }
+    }
+
+    void drawDividersHorizontal(Canvas canvas) {
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+
+            if (child != null && child.getVisibility() != GONE) {
+                if (hasDividerBeforeChildAt(i)) {
+                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                    final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
+                    drawVerticalDivider(canvas, left);
+                }
+            }
+        }
+
+        if (hasDividerBeforeChildAt(count)) {
+            final View child = getChildAt(count - 1);
+            int right = 0;
+            if (child == null) {
+                right = getWidth() - getPaddingRight() - mDividerWidth;
+            } else {
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                right = child.getRight()/* + lp.rightMargin*/;
+            }
+            drawVerticalDivider(canvas, right);
+        }
+    }
+
+    void drawHorizontalDivider(Canvas canvas, int top) {
+        mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
+                getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
+        mDivider.draw(canvas);
+    }
+
+    void drawVerticalDivider(Canvas canvas, int left) {
+        mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
+                left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
+        mDivider.draw(canvas);
+    }
+
+    /**
+     * Determines where to position dividers between children.
+     *
+     * @param childIndex Index of child to check for preceding divider
+     * @return true if there should be a divider before the child at childIndex
+     * @hide Pending API consideration. Currently only used internally by the system.
+     */
+    protected boolean hasDividerBeforeChildAt(int childIndex) {
+        if (childIndex == 0) {
+            return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
+        } else if (childIndex == getChildCount()) {
+            return (mShowDividers & SHOW_DIVIDER_END) != 0;
+        } else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
+            boolean hasVisibleViewBefore = false;
+            for (int i = childIndex - 1; i >= 0; i--) {
+                if (getChildAt(i).getVisibility() != GONE) {
+                    hasVisibleViewBefore = true;
+                    break;
+                }
+            }
+            return hasVisibleViewBefore;
+        }
+        return false;
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsListPopupWindow.java
new file mode 100644 (file)
index 0000000..d13c6ce
--- /dev/null
@@ -0,0 +1,644 @@
+package com.actionbarsherlock.internal.widget;
+
+import com.actionbarsherlock.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.DataSetObserver;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.view.ContextThemeWrapper;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.PopupWindow;
+
+/**
+ * A proxy between pre- and post-Honeycomb implementations of this class.
+ */
+public class IcsListPopupWindow {
+    /**
+     * This value controls the length of time that the user
+     * must leave a pointer down without scrolling to expand
+     * the autocomplete dropdown list to cover the IME.
+     */
+    private static final int EXPAND_LIST_TIMEOUT = 250;
+
+    private Context mContext;
+    private PopupWindow mPopup;
+    private ListAdapter mAdapter;
+    private DropDownListView mDropDownList;
+
+    private int mDropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
+    private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
+    private int mDropDownHorizontalOffset;
+    private int mDropDownVerticalOffset;
+    private boolean mDropDownVerticalOffsetSet;
+
+    private int mListItemExpandMaximum = Integer.MAX_VALUE;
+
+    private View mPromptView;
+    private int mPromptPosition = POSITION_PROMPT_ABOVE;
+
+    private DataSetObserver mObserver;
+
+    private View mDropDownAnchorView;
+
+    private Drawable mDropDownListHighlight;
+
+    private AdapterView.OnItemClickListener mItemClickListener;
+    private AdapterView.OnItemSelectedListener mItemSelectedListener;
+
+    private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
+    private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor();
+    private final PopupScrollListener mScrollListener = new PopupScrollListener();
+    private final ListSelectorHider mHideSelector = new ListSelectorHider();
+
+    private Handler mHandler = new Handler();
+
+    private Rect mTempRect = new Rect();
+
+    private boolean mModal;
+
+    public static final int POSITION_PROMPT_ABOVE = 0;
+    public static final int POSITION_PROMPT_BELOW = 1;
+
+    public IcsListPopupWindow(Context context) {
+        this(context, null, R.attr.listPopupWindowStyle);
+    }
+
+    public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
+        mContext = context;
+        mPopup = new PopupWindow(context, attrs, defStyleAttr);
+        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+    }
+
+    public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        mContext = context;
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
+            Context wrapped = new ContextThemeWrapper(context, defStyleRes);
+            mPopup = new PopupWindow(wrapped, attrs, defStyleAttr);
+        } else {
+            mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
+        }
+        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
+    }
+
+    public void setAdapter(ListAdapter adapter) {
+        if (mObserver == null) {
+            mObserver = new PopupDataSetObserver();
+        } else if (mAdapter != null) {
+            mAdapter.unregisterDataSetObserver(mObserver);
+        }
+        mAdapter = adapter;
+        if (mAdapter != null) {
+            adapter.registerDataSetObserver(mObserver);
+        }
+
+        if (mDropDownList != null) {
+            mDropDownList.setAdapter(mAdapter);
+        }
+    }
+
+    public void setPromptPosition(int position) {
+        mPromptPosition = position;
+    }
+
+    public void setModal(boolean modal) {
+        mModal = true;
+        mPopup.setFocusable(modal);
+    }
+
+    public void setBackgroundDrawable(Drawable d) {
+        mPopup.setBackgroundDrawable(d);
+    }
+
+    public void setAnchorView(View anchor) {
+        mDropDownAnchorView = anchor;
+    }
+
+    public void setHorizontalOffset(int offset) {
+        mDropDownHorizontalOffset = offset;
+    }
+
+    public void setVerticalOffset(int offset) {
+        mDropDownVerticalOffset = offset;
+        mDropDownVerticalOffsetSet = true;
+    }
+
+    public void setContentWidth(int width) {
+        Drawable popupBackground = mPopup.getBackground();
+        if (popupBackground != null) {
+            popupBackground.getPadding(mTempRect);
+            mDropDownWidth = mTempRect.left + mTempRect.right + width;
+        } else {
+            mDropDownWidth = width;
+        }
+    }
+
+    public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
+        mItemClickListener = clickListener;
+    }
+
+    public void show() {
+        int height = buildDropDown();
+
+        int widthSpec = 0;
+        int heightSpec = 0;
+
+        boolean noInputMethod = isInputMethodNotNeeded();
+        //XXX mPopup.setAllowScrollingAnchorParent(!noInputMethod);
+
+        if (mPopup.isShowing()) {
+            if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
+                // The call to PopupWindow's update method below can accept -1 for any
+                // value you do not want to update.
+                widthSpec = -1;
+            } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
+                widthSpec = mDropDownAnchorView.getWidth();
+            } else {
+                widthSpec = mDropDownWidth;
+            }
+
+            if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
+                // The call to PopupWindow's update method below can accept -1 for any
+                // value you do not want to update.
+                heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
+                if (noInputMethod) {
+                    mPopup.setWindowLayoutMode(
+                            mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+                                    ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
+                } else {
+                    mPopup.setWindowLayoutMode(
+                            mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
+                                    ViewGroup.LayoutParams.MATCH_PARENT : 0,
+                            ViewGroup.LayoutParams.MATCH_PARENT);
+                }
+            } else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
+                heightSpec = height;
+            } else {
+                heightSpec = mDropDownHeight;
+            }
+
+            mPopup.setOutsideTouchable(true);
+
+            mPopup.update(mDropDownAnchorView, mDropDownHorizontalOffset,
+                    mDropDownVerticalOffset, widthSpec, heightSpec);
+        } else {
+            if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
+                widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
+            } else {
+                if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
+                    mPopup.setWidth(mDropDownAnchorView.getWidth());
+                } else {
+                    mPopup.setWidth(mDropDownWidth);
+                }
+            }
+
+            if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
+                heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
+            } else {
+                if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
+                    mPopup.setHeight(height);
+                } else {
+                    mPopup.setHeight(mDropDownHeight);
+                }
+            }
+
+            mPopup.setWindowLayoutMode(widthSpec, heightSpec);
+            //XXX mPopup.setClipToScreenEnabled(true);
+
+            // use outside touchable to dismiss drop down when touching outside of it, so
+            // only set this if the dropdown is not always visible
+            mPopup.setOutsideTouchable(true);
+            mPopup.setTouchInterceptor(mTouchInterceptor);
+            mPopup.showAsDropDown(mDropDownAnchorView,
+                    mDropDownHorizontalOffset, mDropDownVerticalOffset);
+            mDropDownList.setSelection(ListView.INVALID_POSITION);
+
+            if (!mModal || mDropDownList.isInTouchMode()) {
+                clearListSelection();
+            }
+            if (!mModal) {
+                mHandler.post(mHideSelector);
+            }
+        }
+    }
+
+    public void dismiss() {
+        mPopup.dismiss();
+        if (mPromptView != null) {
+            final ViewParent parent = mPromptView.getParent();
+            if (parent instanceof ViewGroup) {
+                final ViewGroup group = (ViewGroup) parent;
+                group.removeView(mPromptView);
+            }
+        }
+        mPopup.setContentView(null);
+        mDropDownList = null;
+        mHandler.removeCallbacks(mResizePopupRunnable);
+    }
+
+    public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
+        mPopup.setOnDismissListener(listener);
+    }
+
+    public void setInputMethodMode(int mode) {
+        mPopup.setInputMethodMode(mode);
+    }
+
+    public void clearListSelection() {
+        final DropDownListView list = mDropDownList;
+        if (list != null) {
+            // WARNING: Please read the comment where mListSelectionHidden is declared
+            list.mListSelectionHidden = true;
+            //XXX list.hideSelector();
+            list.requestLayout();
+        }
+    }
+
+    public boolean isShowing() {
+        return mPopup.isShowing();
+    }
+
+    private boolean isInputMethodNotNeeded() {
+        return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+    }
+
+    public ListView getListView() {
+        return mDropDownList;
+    }
+
+    private int buildDropDown() {
+        ViewGroup dropDownView;
+        int otherHeights = 0;
+
+        if (mDropDownList == null) {
+            Context context = mContext;
+
+            mDropDownList = new DropDownListView(context, !mModal);
+            if (mDropDownListHighlight != null) {
+                mDropDownList.setSelector(mDropDownListHighlight);
+            }
+            mDropDownList.setAdapter(mAdapter);
+            mDropDownList.setOnItemClickListener(mItemClickListener);
+            mDropDownList.setFocusable(true);
+            mDropDownList.setFocusableInTouchMode(true);
+            mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+                public void onItemSelected(AdapterView<?> parent, View view,
+                        int position, long id) {
+
+                    if (position != -1) {
+                        DropDownListView dropDownList = mDropDownList;
+
+                        if (dropDownList != null) {
+                            dropDownList.mListSelectionHidden = false;
+                        }
+                    }
+                }
+
+                public void onNothingSelected(AdapterView<?> parent) {
+                }
+            });
+            mDropDownList.setOnScrollListener(mScrollListener);
+
+            if (mItemSelectedListener != null) {
+                mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
+            }
+
+            dropDownView = mDropDownList;
+
+            View hintView = mPromptView;
+            if (hintView != null) {
+                // if an hint has been specified, we accomodate more space for it and
+                // add a text view in the drop down menu, at the bottom of the list
+                LinearLayout hintContainer = new LinearLayout(context);
+                hintContainer.setOrientation(LinearLayout.VERTICAL);
+
+                LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams(
+                        ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f
+                );
+
+                switch (mPromptPosition) {
+                case POSITION_PROMPT_BELOW:
+                    hintContainer.addView(dropDownView, hintParams);
+                    hintContainer.addView(hintView);
+                    break;
+
+                case POSITION_PROMPT_ABOVE:
+                    hintContainer.addView(hintView);
+                    hintContainer.addView(dropDownView, hintParams);
+                    break;
+
+                default:
+                    break;
+                }
+
+                // measure the hint's height to find how much more vertical space
+                // we need to add to the drop down's height
+                int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
+                int heightSpec = MeasureSpec.UNSPECIFIED;
+                hintView.measure(widthSpec, heightSpec);
+
+                hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
+                otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin
+                        + hintParams.bottomMargin;
+
+                dropDownView = hintContainer;
+            }
+
+            mPopup.setContentView(dropDownView);
+        } else {
+            dropDownView = (ViewGroup) mPopup.getContentView();
+            final View view = mPromptView;
+            if (view != null) {
+                LinearLayout.LayoutParams hintParams =
+                        (LinearLayout.LayoutParams) view.getLayoutParams();
+                otherHeights = view.getMeasuredHeight() + hintParams.topMargin
+                        + hintParams.bottomMargin;
+            }
+        }
+
+        // getMaxAvailableHeight() subtracts the padding, so we put it back
+        // to get the available height for the whole window
+        int padding = 0;
+        Drawable background = mPopup.getBackground();
+        if (background != null) {
+            background.getPadding(mTempRect);
+            padding = mTempRect.top + mTempRect.bottom;
+
+            // If we don't have an explicit vertical offset, determine one from the window
+            // background so that content will line up.
+            if (!mDropDownVerticalOffsetSet) {
+                mDropDownVerticalOffset = -mTempRect.top;
+            }
+        }
+
+        // Max height available on the screen for a popup.
+        boolean ignoreBottomDecorations =
+                mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
+        final int maxHeight = /*mPopup.*/getMaxAvailableHeight(
+                mDropDownAnchorView, mDropDownVerticalOffset, ignoreBottomDecorations);
+
+        if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
+            return maxHeight + padding;
+        }
+
+        final int listContent = /*mDropDownList.*/measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
+                0, -1/*ListView.NO_POSITION*/, maxHeight - otherHeights, -1);
+        // add padding only if the list has items in it, that way we don't show
+        // the popup if it is not needed
+        if (listContent > 0) otherHeights += padding;
+
+        return listContent + otherHeights;
+    }
+
+    private int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
+        final Rect displayFrame = new Rect();
+        anchor.getWindowVisibleDisplayFrame(displayFrame);
+
+        final int[] anchorPos = new int[2];
+        anchor.getLocationOnScreen(anchorPos);
+
+        int bottomEdge = displayFrame.bottom;
+        if (ignoreBottomDecorations) {
+            Resources res = anchor.getContext().getResources();
+            bottomEdge = res.getDisplayMetrics().heightPixels;
+        }
+        final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
+        final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
+
+        // anchorPos[1] is distance from anchor to top of screen
+        int returnedHeight = Math.max(distanceToBottom, distanceToTop);
+        if (mPopup.getBackground() != null) {
+            mPopup.getBackground().getPadding(mTempRect);
+            returnedHeight -= mTempRect.top + mTempRect.bottom;
+        }
+
+        return returnedHeight;
+    }
+
+    private int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
+            final int maxHeight, int disallowPartialChildPosition) {
+
+        final ListAdapter adapter = mAdapter;
+        if (adapter == null) {
+            return mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom();
+        }
+
+        // Include the padding of the list
+        int returnedHeight = mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom();
+        final int dividerHeight = ((mDropDownList.getDividerHeight() > 0) && mDropDownList.getDivider() != null) ? mDropDownList.getDividerHeight() : 0;
+        // The previous height value that was less than maxHeight and contained
+        // no partial children
+        int prevHeightWithoutPartialChild = 0;
+        int i;
+        View child;
+
+        // mItemCount - 1 since endPosition parameter is inclusive
+        endPosition = (endPosition == -1/*NO_POSITION*/) ? adapter.getCount() - 1 : endPosition;
+
+        for (i = startPosition; i <= endPosition; ++i) {
+            child = mAdapter.getView(i, null, mDropDownList);
+            if (mDropDownList.getCacheColorHint() != 0) {
+                child.setDrawingCacheBackgroundColor(mDropDownList.getCacheColorHint());
+            }
+
+            measureScrapChild(child, i, widthMeasureSpec);
+
+            if (i > 0) {
+                // Count the divider for all but one child
+                returnedHeight += dividerHeight;
+            }
+
+            returnedHeight += child.getMeasuredHeight();
+
+            if (returnedHeight >= maxHeight) {
+                // We went over, figure out which height to return.  If returnedHeight > maxHeight,
+                // then the i'th position did not fit completely.
+                return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)
+                            && (i > disallowPartialChildPosition) // We've past the min pos
+                            && (prevHeightWithoutPartialChild > 0) // We have a prev height
+                            && (returnedHeight != maxHeight) // i'th child did not fit completely
+                        ? prevHeightWithoutPartialChild
+                        : maxHeight;
+            }
+
+            if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {
+                prevHeightWithoutPartialChild = returnedHeight;
+            }
+        }
+
+        // At this point, we went through the range of children, and they each
+        // completely fit, so return the returnedHeight
+        return returnedHeight;
+    }
+    private void measureScrapChild(View child, int position, int widthMeasureSpec) {
+        ListView.LayoutParams p = (ListView.LayoutParams) child.getLayoutParams();
+        if (p == null) {
+            p = new ListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT, 0);
+            child.setLayoutParams(p);
+        }
+        //XXX p.viewType = mAdapter.getItemViewType(position);
+        //XXX p.forceAdd = true;
+
+        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
+                mDropDownList.getPaddingLeft() + mDropDownList.getPaddingRight(), p.width);
+        int lpHeight = p.height;
+        int childHeightSpec;
+        if (lpHeight > 0) {
+            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
+        } else {
+            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        }
+        child.measure(childWidthSpec, childHeightSpec);
+    }
+
+    private static class DropDownListView extends ListView {
+        /*
+         * WARNING: This is a workaround for a touch mode issue.
+         *
+         * Touch mode is propagated lazily to windows. This causes problems in
+         * the following scenario:
+         * - Type something in the AutoCompleteTextView and get some results
+         * - Move down with the d-pad to select an item in the list
+         * - Move up with the d-pad until the selection disappears
+         * - Type more text in the AutoCompleteTextView *using the soft keyboard*
+         *   and get new results; you are now in touch mode
+         * - The selection comes back on the first item in the list, even though
+         *   the list is supposed to be in touch mode
+         *
+         * Using the soft keyboard triggers the touch mode change but that change
+         * is propagated to our window only after the first list layout, therefore
+         * after the list attempts to resurrect the selection.
+         *
+         * The trick to work around this issue is to pretend the list is in touch
+         * mode when we know that the selection should not appear, that is when
+         * we know the user moved the selection away from the list.
+         *
+         * This boolean is set to true whenever we explicitly hide the list's
+         * selection and reset to false whenever we know the user moved the
+         * selection back to the list.
+         *
+         * When this boolean is true, isInTouchMode() returns true, otherwise it
+         * returns super.isInTouchMode().
+         */
+        private boolean mListSelectionHidden;
+
+        private boolean mHijackFocus;
+
+        public DropDownListView(Context context, boolean hijackFocus) {
+            super(context, null, /*com.android.internal.*/R.attr.dropDownListViewStyle);
+            mHijackFocus = hijackFocus;
+            // TODO: Add an API to control this
+            setCacheColorHint(0); // Transparent, since the background drawable could be anything.
+        }
+
+        //XXX @Override
+        //View obtainView(int position, boolean[] isScrap) {
+        //    View view = super.obtainView(position, isScrap);
+
+        //    if (view instanceof TextView) {
+        //        ((TextView) view).setHorizontallyScrolling(true);
+        //    }
+
+        //    return view;
+        //}
+
+        @Override
+        public boolean isInTouchMode() {
+            // WARNING: Please read the comment where mListSelectionHidden is declared
+            return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
+        }
+
+        @Override
+        public boolean hasWindowFocus() {
+            return mHijackFocus || super.hasWindowFocus();
+        }
+
+        @Override
+        public boolean isFocused() {
+            return mHijackFocus || super.isFocused();
+        }
+
+        @Override
+        public boolean hasFocus() {
+            return mHijackFocus || super.hasFocus();
+        }
+    }
+
+    private class PopupDataSetObserver extends DataSetObserver {
+        @Override
+        public void onChanged() {
+            if (isShowing()) {
+                // Resize the popup to fit new content
+                show();
+            }
+        }
+
+        @Override
+        public void onInvalidated() {
+            dismiss();
+        }
+    }
+
+    private class ListSelectorHider implements Runnable {
+        public void run() {
+            clearListSelection();
+        }
+    }
+
+    private class ResizePopupRunnable implements Runnable {
+        public void run() {
+            if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() &&
+                    mDropDownList.getChildCount() <= mListItemExpandMaximum) {
+                mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+                show();
+            }
+        }
+    }
+
+    private class PopupTouchInterceptor implements OnTouchListener {
+        public boolean onTouch(View v, MotionEvent event) {
+            final int action = event.getAction();
+            final int x = (int) event.getX();
+            final int y = (int) event.getY();
+
+            if (action == MotionEvent.ACTION_DOWN &&
+                    mPopup != null && mPopup.isShowing() &&
+                    (x >= 0 && x < mPopup.getWidth() && y >= 0 && y < mPopup.getHeight())) {
+                mHandler.postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT);
+            } else if (action == MotionEvent.ACTION_UP) {
+                mHandler.removeCallbacks(mResizePopupRunnable);
+            }
+            return false;
+        }
+    }
+
+    private class PopupScrollListener implements ListView.OnScrollListener {
+        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
+                int totalItemCount) {
+
+        }
+
+        public void onScrollStateChanged(AbsListView view, int scrollState) {
+            if (scrollState == SCROLL_STATE_TOUCH_SCROLL &&
+                    !isInputMethodNotNeeded() && mPopup.getContentView() != null) {
+                mHandler.removeCallbacks(mResizePopupRunnable);
+                mResizePopupRunnable.run();
+            }
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsProgressBar.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsProgressBar.java
new file mode 100644 (file)
index 0000000..1c02d4a
--- /dev/null
@@ -0,0 +1,1193 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.AnimationDrawable;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ClipDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RoundRectShape;
+import android.graphics.drawable.shapes.Shape;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+import android.view.animation.Transformation;
+import android.widget.RemoteViews.RemoteView;
+
+
+/**
+ * <p>
+ * Visual indicator of progress in some operation.  Displays a bar to the user
+ * representing how far the operation has progressed; the application can
+ * change the amount of progress (modifying the length of the bar) as it moves
+ * forward.  There is also a secondary progress displayable on a progress bar
+ * which is useful for displaying intermediate progress, such as the buffer
+ * level during a streaming playback progress bar.
+ * </p>
+ *
+ * <p>
+ * A progress bar can also be made indeterminate. In indeterminate mode, the
+ * progress bar shows a cyclic animation without an indication of progress. This mode is used by
+ * applications when the length of the task is unknown. The indeterminate progress bar can be either
+ * a spinning wheel or a horizontal bar.
+ * </p>
+ *
+ * <p>The following code example shows how a progress bar can be used from
+ * a worker thread to update the user interface to notify the user of progress:
+ * </p>
+ *
+ * <pre>
+ * public class MyActivity extends Activity {
+ *     private static final int PROGRESS = 0x1;
+ *
+ *     private ProgressBar mProgress;
+ *     private int mProgressStatus = 0;
+ *
+ *     private Handler mHandler = new Handler();
+ *
+ *     protected void onCreate(Bundle icicle) {
+ *         super.onCreate(icicle);
+ *
+ *         setContentView(R.layout.progressbar_activity);
+ *
+ *         mProgress = (ProgressBar) findViewById(R.id.progress_bar);
+ *
+ *         // Start lengthy operation in a background thread
+ *         new Thread(new Runnable() {
+ *             public void run() {
+ *                 while (mProgressStatus &lt; 100) {
+ *                     mProgressStatus = doWork();
+ *
+ *                     // Update the progress bar
+ *                     mHandler.post(new Runnable() {
+ *                         public void run() {
+ *                             mProgress.setProgress(mProgressStatus);
+ *                         }
+ *                     });
+ *                 }
+ *             }
+ *         }).start();
+ *     }
+ * }</pre>
+ *
+ * <p>To add a progress bar to a layout file, you can use the {@code &lt;ProgressBar&gt;} element.
+ * By default, the progress bar is a spinning wheel (an indeterminate indicator). To change to a
+ * horizontal progress bar, apply the {@link android.R.style#Widget_ProgressBar_Horizontal
+ * Widget.ProgressBar.Horizontal} style, like so:</p>
+ *
+ * <pre>
+ * &lt;ProgressBar
+ *     style="@android:style/Widget.ProgressBar.Horizontal"
+ *     ... /&gt;</pre>
+ *
+ * <p>If you will use the progress bar to show real progress, you must use the horizontal bar. You
+ * can then increment the  progress with {@link #incrementProgressBy incrementProgressBy()} or
+ * {@link #setProgress setProgress()}. By default, the progress bar is full when it reaches 100. If
+ * necessary, you can adjust the maximum value (the value for a full bar) using the {@link
+ * android.R.styleable#ProgressBar_max android:max} attribute. Other attributes available are listed
+ * below.</p>
+ *
+ * <p>Another common style to apply to the progress bar is {@link
+ * android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}, which shows a smaller
+ * version of the spinning wheel&mdash;useful when waiting for content to load.
+ * For example, you can insert this kind of progress bar into your default layout for
+ * a view that will be populated by some content fetched from the Internet&mdash;the spinning wheel
+ * appears immediately and when your application receives the content, it replaces the progress bar
+ * with the loaded content. For example:</p>
+ *
+ * <pre>
+ * &lt;LinearLayout
+ *     android:orientation="horizontal"
+ *     ... &gt;
+ *     &lt;ProgressBar
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         style="@android:style/Widget.ProgressBar.Small"
+ *         android:layout_marginRight="5dp" /&gt;
+ *     &lt;TextView
+ *         android:layout_width="wrap_content"
+ *         android:layout_height="wrap_content"
+ *         android:text="@string/loading" /&gt;
+ * &lt;/LinearLayout&gt;</pre>
+ *
+ * <p>Other progress bar styles provided by the system include:</p>
+ * <ul>
+ * <li>{@link android.R.style#Widget_ProgressBar_Horizontal Widget.ProgressBar.Horizontal}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Small Widget.ProgressBar.Small}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Large Widget.ProgressBar.Large}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Inverse Widget.ProgressBar.Inverse}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Small_Inverse
+ * Widget.ProgressBar.Small.Inverse}</li>
+ * <li>{@link android.R.style#Widget_ProgressBar_Large_Inverse
+ * Widget.ProgressBar.Large.Inverse}</li>
+ * </ul>
+ * <p>The "inverse" styles provide an inverse color scheme for the spinner, which may be necessary
+ * if your application uses a light colored theme (a white background).</p>
+ *
+ * <p><strong>XML attributes</b></strong>
+ * <p>
+ * See {@link android.R.styleable#ProgressBar ProgressBar Attributes},
+ * {@link android.R.styleable#View View Attributes}
+ * </p>
+ *
+ * @attr ref android.R.styleable#ProgressBar_animationResolution
+ * @attr ref android.R.styleable#ProgressBar_indeterminate
+ * @attr ref android.R.styleable#ProgressBar_indeterminateBehavior
+ * @attr ref android.R.styleable#ProgressBar_indeterminateDrawable
+ * @attr ref android.R.styleable#ProgressBar_indeterminateDuration
+ * @attr ref android.R.styleable#ProgressBar_indeterminateOnly
+ * @attr ref android.R.styleable#ProgressBar_interpolator
+ * @attr ref android.R.styleable#ProgressBar_max
+ * @attr ref android.R.styleable#ProgressBar_maxHeight
+ * @attr ref android.R.styleable#ProgressBar_maxWidth
+ * @attr ref android.R.styleable#ProgressBar_minHeight
+ * @attr ref android.R.styleable#ProgressBar_minWidth
+ * @attr ref android.R.styleable#ProgressBar_progress
+ * @attr ref android.R.styleable#ProgressBar_progressDrawable
+ * @attr ref android.R.styleable#ProgressBar_secondaryProgress
+ */
+@RemoteView
+public class IcsProgressBar extends View {
+    private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
+    private static final int MAX_LEVEL = 10000;
+    private static final int ANIMATION_RESOLUTION = 200;
+    private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;
+
+    private static final int[] ProgressBar = new int[] {
+        android.R.attr.maxWidth,
+        android.R.attr.maxHeight,
+        android.R.attr.max,
+        android.R.attr.progress,
+        android.R.attr.secondaryProgress,
+        android.R.attr.indeterminate,
+        android.R.attr.indeterminateOnly,
+        android.R.attr.indeterminateDrawable,
+        android.R.attr.progressDrawable,
+        android.R.attr.indeterminateDuration,
+        android.R.attr.indeterminateBehavior,
+        android.R.attr.minWidth,
+        android.R.attr.minHeight,
+        android.R.attr.interpolator,
+        android.R.attr.animationResolution,
+    };
+    private static final int ProgressBar_maxWidth = 0;
+    private static final int ProgressBar_maxHeight = 1;
+    private static final int ProgressBar_max = 2;
+    private static final int ProgressBar_progress = 3;
+    private static final int ProgressBar_secondaryProgress = 4;
+    private static final int ProgressBar_indeterminate = 5;
+    private static final int ProgressBar_indeterminateOnly = 6;
+    private static final int ProgressBar_indeterminateDrawable = 7;
+    private static final int ProgressBar_progressDrawable = 8;
+    private static final int ProgressBar_indeterminateDuration = 9;
+    private static final int ProgressBar_indeterminateBehavior = 10;
+    private static final int ProgressBar_minWidth = 11;
+    private static final int ProgressBar_minHeight = 12;
+    private static final int ProgressBar_interpolator = 13;
+    private static final int ProgressBar_animationResolution = 14;
+
+    int mMinWidth;
+    int mMaxWidth;
+    int mMinHeight;
+    int mMaxHeight;
+
+    private int mProgress;
+    private int mSecondaryProgress;
+    private int mMax;
+
+    private int mBehavior;
+    private int mDuration;
+    private boolean mIndeterminate;
+    private boolean mOnlyIndeterminate;
+    private Transformation mTransformation;
+    private AlphaAnimation mAnimation;
+    private Drawable mIndeterminateDrawable;
+    private int mIndeterminateRealLeft;
+    private int mIndeterminateRealTop;
+    private Drawable mProgressDrawable;
+    private Drawable mCurrentDrawable;
+    Bitmap mSampleTile;
+    private boolean mNoInvalidate;
+    private Interpolator mInterpolator;
+    private RefreshProgressRunnable mRefreshProgressRunnable;
+    private long mUiThreadId;
+    private boolean mShouldStartAnimationDrawable;
+    private long mLastDrawTime;
+
+    private boolean mInDrawing;
+
+    private int mAnimationResolution;
+
+    private AccessibilityManager mAccessibilityManager;
+    private AccessibilityEventSender mAccessibilityEventSender;
+
+    /**
+     * Create a new progress bar with range 0...100 and initial progress of 0.
+     * @param context the application environment
+     */
+    public IcsProgressBar(Context context) {
+        this(context, null);
+    }
+
+    public IcsProgressBar(Context context, AttributeSet attrs) {
+        this(context, attrs, android.R.attr.progressBarStyle);
+    }
+
+    public IcsProgressBar(Context context, AttributeSet attrs, int defStyle) {
+        this(context, attrs, defStyle, 0);
+    }
+
+    /**
+     * @hide
+     */
+    public IcsProgressBar(Context context, AttributeSet attrs, int defStyle, int styleRes) {
+        super(context, attrs, defStyle);
+        mUiThreadId = Thread.currentThread().getId();
+        initProgressBar();
+
+        TypedArray a =
+            context.obtainStyledAttributes(attrs, /*R.styleable.*/ProgressBar, defStyle, styleRes);
+
+        mNoInvalidate = true;
+
+        Drawable drawable = a.getDrawable(/*R.styleable.*/ProgressBar_progressDrawable);
+        if (drawable != null) {
+            drawable = tileify(drawable, false);
+            // Calling this method can set mMaxHeight, make sure the corresponding
+            // XML attribute for mMaxHeight is read after calling this method
+            setProgressDrawable(drawable);
+        }
+
+
+        mDuration = a.getInt(/*R.styleable.*/ProgressBar_indeterminateDuration, mDuration);
+
+        mMinWidth = a.getDimensionPixelSize(/*R.styleable.*/ProgressBar_minWidth, mMinWidth);
+        mMaxWidth = a.getDimensionPixelSize(/*R.styleable.*/ProgressBar_maxWidth, mMaxWidth);
+        mMinHeight = a.getDimensionPixelSize(/*R.styleable.*/ProgressBar_minHeight, mMinHeight);
+        mMaxHeight = a.getDimensionPixelSize(/*R.styleable.*/ProgressBar_maxHeight, mMaxHeight);
+
+        mBehavior = a.getInt(/*R.styleable.*/ProgressBar_indeterminateBehavior, mBehavior);
+
+        final int resID = a.getResourceId(
+                /*com.android.internal.R.styleable.*/ProgressBar_interpolator,
+                android.R.anim.linear_interpolator); // default to linear interpolator
+        if (resID > 0) {
+            setInterpolator(context, resID);
+        }
+
+        setMax(a.getInt(/*R.styleable.*/ProgressBar_max, mMax));
+
+        setProgress(a.getInt(/*R.styleable.*/ProgressBar_progress, mProgress));
+
+        setSecondaryProgress(
+                a.getInt(/*R.styleable.*/ProgressBar_secondaryProgress, mSecondaryProgress));
+
+        drawable = a.getDrawable(/*R.styleable.*/ProgressBar_indeterminateDrawable);
+        if (drawable != null) {
+            drawable = tileifyIndeterminate(drawable);
+            setIndeterminateDrawable(drawable);
+        }
+
+        mOnlyIndeterminate = a.getBoolean(
+                /*R.styleable.*/ProgressBar_indeterminateOnly, mOnlyIndeterminate);
+
+        mNoInvalidate = false;
+
+        setIndeterminate(mOnlyIndeterminate || a.getBoolean(
+                /*R.styleable.*/ProgressBar_indeterminate, mIndeterminate));
+
+        mAnimationResolution = a.getInteger(/*R.styleable.*/ProgressBar_animationResolution,
+                ANIMATION_RESOLUTION);
+
+        a.recycle();
+
+        mAccessibilityManager = (AccessibilityManager)context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+    }
+
+    /**
+     * Converts a drawable to a tiled version of itself. It will recursively
+     * traverse layer and state list drawables.
+     */
+    private Drawable tileify(Drawable drawable, boolean clip) {
+
+        if (drawable instanceof LayerDrawable) {
+            LayerDrawable background = (LayerDrawable) drawable;
+            final int N = background.getNumberOfLayers();
+            Drawable[] outDrawables = new Drawable[N];
+
+            for (int i = 0; i < N; i++) {
+                int id = background.getId(i);
+                outDrawables[i] = tileify(background.getDrawable(i),
+                        (id == android.R.id.progress || id == android.R.id.secondaryProgress));
+            }
+
+            LayerDrawable newBg = new LayerDrawable(outDrawables);
+
+            for (int i = 0; i < N; i++) {
+                newBg.setId(i, background.getId(i));
+            }
+
+            return newBg;
+
+        }/* else if (drawable instanceof StateListDrawable) {
+            StateListDrawable in = (StateListDrawable) drawable;
+            StateListDrawable out = new StateListDrawable();
+            int numStates = in.getStateCount();
+            for (int i = 0; i < numStates; i++) {
+                out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
+            }
+            return out;
+
+        }*/ else if (drawable instanceof BitmapDrawable) {
+            final Bitmap tileBitmap = ((BitmapDrawable) drawable).getBitmap();
+            if (mSampleTile == null) {
+                mSampleTile = tileBitmap;
+            }
+
+            final ShapeDrawable shapeDrawable = new ShapeDrawable(getDrawableShape());
+
+            final BitmapShader bitmapShader = new BitmapShader(tileBitmap,
+                    Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
+            shapeDrawable.getPaint().setShader(bitmapShader);
+
+            return (clip) ? new ClipDrawable(shapeDrawable, Gravity.LEFT,
+                    ClipDrawable.HORIZONTAL) : shapeDrawable;
+        }
+
+        return drawable;
+    }
+
+    Shape getDrawableShape() {
+        final float[] roundedCorners = new float[] { 5, 5, 5, 5, 5, 5, 5, 5 };
+        return new RoundRectShape(roundedCorners, null, null);
+    }
+
+    /**
+     * Convert a AnimationDrawable for use as a barberpole animation.
+     * Each frame of the animation is wrapped in a ClipDrawable and
+     * given a tiling BitmapShader.
+     */
+    private Drawable tileifyIndeterminate(Drawable drawable) {
+        if (drawable instanceof AnimationDrawable) {
+            AnimationDrawable background = (AnimationDrawable) drawable;
+            final int N = background.getNumberOfFrames();
+            AnimationDrawable newBg = new AnimationDrawable();
+            newBg.setOneShot(background.isOneShot());
+
+            for (int i = 0; i < N; i++) {
+                Drawable frame = tileify(background.getFrame(i), true);
+                frame.setLevel(10000);
+                newBg.addFrame(frame, background.getDuration(i));
+            }
+            newBg.setLevel(10000);
+            drawable = newBg;
+        }
+        return drawable;
+    }
+
+    /**
+     * <p>
+     * Initialize the progress bar's default values:
+     * </p>
+     * <ul>
+     * <li>progress = 0</li>
+     * <li>max = 100</li>
+     * <li>animation duration = 4000 ms</li>
+     * <li>indeterminate = false</li>
+     * <li>behavior = repeat</li>
+     * </ul>
+     */
+    private void initProgressBar() {
+        mMax = 100;
+        mProgress = 0;
+        mSecondaryProgress = 0;
+        mIndeterminate = false;
+        mOnlyIndeterminate = false;
+        mDuration = 4000;
+        mBehavior = AlphaAnimation.RESTART;
+        mMinWidth = 24;
+        mMaxWidth = 48;
+        mMinHeight = 24;
+        mMaxHeight = 48;
+    }
+
+    /**
+     * <p>Indicate whether this progress bar is in indeterminate mode.</p>
+     *
+     * @return true if the progress bar is in indeterminate mode
+     */
+    @ViewDebug.ExportedProperty(category = "progress")
+    public synchronized boolean isIndeterminate() {
+        return mIndeterminate;
+    }
+
+    /**
+     * <p>Change the indeterminate mode for this progress bar. In indeterminate
+     * mode, the progress is ignored and the progress bar shows an infinite
+     * animation instead.</p>
+     *
+     * If this progress bar's style only supports indeterminate mode (such as the circular
+     * progress bars), then this will be ignored.
+     *
+     * @param indeterminate true to enable the indeterminate mode
+     */
+    public synchronized void setIndeterminate(boolean indeterminate) {
+        if ((!mOnlyIndeterminate || !mIndeterminate) && indeterminate != mIndeterminate) {
+            mIndeterminate = indeterminate;
+
+            if (indeterminate) {
+                // swap between indeterminate and regular backgrounds
+                mCurrentDrawable = mIndeterminateDrawable;
+                startAnimation();
+            } else {
+                mCurrentDrawable = mProgressDrawable;
+                stopAnimation();
+            }
+        }
+    }
+
+    /**
+     * <p>Get the drawable used to draw the progress bar in
+     * indeterminate mode.</p>
+     *
+     * @return a {@link android.graphics.drawable.Drawable} instance
+     *
+     * @see #setIndeterminateDrawable(android.graphics.drawable.Drawable)
+     * @see #setIndeterminate(boolean)
+     */
+    public Drawable getIndeterminateDrawable() {
+        return mIndeterminateDrawable;
+    }
+
+    /**
+     * <p>Define the drawable used to draw the progress bar in
+     * indeterminate mode.</p>
+     *
+     * @param d the new drawable
+     *
+     * @see #getIndeterminateDrawable()
+     * @see #setIndeterminate(boolean)
+     */
+    public void setIndeterminateDrawable(Drawable d) {
+        if (d != null) {
+            d.setCallback(this);
+        }
+        mIndeterminateDrawable = d;
+        if (mIndeterminate) {
+            mCurrentDrawable = d;
+            postInvalidate();
+        }
+    }
+
+    /**
+     * <p>Get the drawable used to draw the progress bar in
+     * progress mode.</p>
+     *
+     * @return a {@link android.graphics.drawable.Drawable} instance
+     *
+     * @see #setProgressDrawable(android.graphics.drawable.Drawable)
+     * @see #setIndeterminate(boolean)
+     */
+    public Drawable getProgressDrawable() {
+        return mProgressDrawable;
+    }
+
+    /**
+     * <p>Define the drawable used to draw the progress bar in
+     * progress mode.</p>
+     *
+     * @param d the new drawable
+     *
+     * @see #getProgressDrawable()
+     * @see #setIndeterminate(boolean)
+     */
+    public void setProgressDrawable(Drawable d) {
+        boolean needUpdate;
+        if (mProgressDrawable != null && d != mProgressDrawable) {
+            mProgressDrawable.setCallback(null);
+            needUpdate = true;
+        } else {
+            needUpdate = false;
+        }
+
+        if (d != null) {
+            d.setCallback(this);
+
+            // Make sure the ProgressBar is always tall enough
+            int drawableHeight = d.getMinimumHeight();
+            if (mMaxHeight < drawableHeight) {
+                mMaxHeight = drawableHeight;
+                requestLayout();
+            }
+        }
+        mProgressDrawable = d;
+        if (!mIndeterminate) {
+            mCurrentDrawable = d;
+            postInvalidate();
+        }
+
+        if (needUpdate) {
+            updateDrawableBounds(getWidth(), getHeight());
+            updateDrawableState();
+            doRefreshProgress(android.R.id.progress, mProgress, false, false);
+            doRefreshProgress(android.R.id.secondaryProgress, mSecondaryProgress, false, false);
+        }
+    }
+
+    /**
+     * @return The drawable currently used to draw the progress bar
+     */
+    Drawable getCurrentDrawable() {
+        return mCurrentDrawable;
+    }
+
+    @Override
+    protected boolean verifyDrawable(Drawable who) {
+        return who == mProgressDrawable || who == mIndeterminateDrawable
+                || super.verifyDrawable(who);
+    }
+
+    @Override
+    public void jumpDrawablesToCurrentState() {
+        super.jumpDrawablesToCurrentState();
+        if (mProgressDrawable != null) mProgressDrawable.jumpToCurrentState();
+        if (mIndeterminateDrawable != null) mIndeterminateDrawable.jumpToCurrentState();
+    }
+
+    @Override
+    public void postInvalidate() {
+        if (!mNoInvalidate) {
+            super.postInvalidate();
+        }
+    }
+
+    private class RefreshProgressRunnable implements Runnable {
+
+        private int mId;
+        private int mProgress;
+        private boolean mFromUser;
+
+        RefreshProgressRunnable(int id, int progress, boolean fromUser) {
+            mId = id;
+            mProgress = progress;
+            mFromUser = fromUser;
+        }
+
+        public void run() {
+            doRefreshProgress(mId, mProgress, mFromUser, true);
+            // Put ourselves back in the cache when we are done
+            mRefreshProgressRunnable = this;
+        }
+
+        public void setup(int id, int progress, boolean fromUser) {
+            mId = id;
+            mProgress = progress;
+            mFromUser = fromUser;
+        }
+
+    }
+
+    private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
+            boolean callBackToApp) {
+        float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
+        final Drawable d = mCurrentDrawable;
+        if (d != null) {
+            Drawable progressDrawable = null;
+
+            if (d instanceof LayerDrawable) {
+                progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
+            }
+
+            final int level = (int) (scale * MAX_LEVEL);
+            (progressDrawable != null ? progressDrawable : d).setLevel(level);
+        } else {
+            invalidate();
+        }
+
+        if (callBackToApp && id == android.R.id.progress) {
+            onProgressRefresh(scale, fromUser);
+        }
+    }
+
+    void onProgressRefresh(float scale, boolean fromUser) {
+        if (mAccessibilityManager.isEnabled()) {
+            scheduleAccessibilityEventSender();
+        }
+    }
+
+    private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
+        if (mUiThreadId == Thread.currentThread().getId()) {
+            doRefreshProgress(id, progress, fromUser, true);
+        } else {
+            RefreshProgressRunnable r;
+            if (mRefreshProgressRunnable != null) {
+                // Use cached RefreshProgressRunnable if available
+                r = mRefreshProgressRunnable;
+                // Uncache it
+                mRefreshProgressRunnable = null;
+                r.setup(id, progress, fromUser);
+            } else {
+                // Make a new one
+                r = new RefreshProgressRunnable(id, progress, fromUser);
+            }
+            post(r);
+        }
+    }
+
+    /**
+     * <p>Set the current progress to the specified value. Does not do anything
+     * if the progress bar is in indeterminate mode.</p>
+     *
+     * @param progress the new progress, between 0 and {@link #getMax()}
+     *
+     * @see #setIndeterminate(boolean)
+     * @see #isIndeterminate()
+     * @see #getProgress()
+     * @see #incrementProgressBy(int)
+     */
+    public synchronized void setProgress(int progress) {
+        setProgress(progress, false);
+    }
+
+    synchronized void setProgress(int progress, boolean fromUser) {
+        if (mIndeterminate) {
+            return;
+        }
+
+        if (progress < 0) {
+            progress = 0;
+        }
+
+        if (progress > mMax) {
+            progress = mMax;
+        }
+
+        if (progress != mProgress) {
+            mProgress = progress;
+            refreshProgress(android.R.id.progress, mProgress, fromUser);
+        }
+    }
+
+    /**
+     * <p>
+     * Set the current secondary progress to the specified value. Does not do
+     * anything if the progress bar is in indeterminate mode.
+     * </p>
+     *
+     * @param secondaryProgress the new secondary progress, between 0 and {@link #getMax()}
+     * @see #setIndeterminate(boolean)
+     * @see #isIndeterminate()
+     * @see #getSecondaryProgress()
+     * @see #incrementSecondaryProgressBy(int)
+     */
+    public synchronized void setSecondaryProgress(int secondaryProgress) {
+        if (mIndeterminate) {
+            return;
+        }
+
+        if (secondaryProgress < 0) {
+            secondaryProgress = 0;
+        }
+
+        if (secondaryProgress > mMax) {
+            secondaryProgress = mMax;
+        }
+
+        if (secondaryProgress != mSecondaryProgress) {
+            mSecondaryProgress = secondaryProgress;
+            refreshProgress(android.R.id.secondaryProgress, mSecondaryProgress, false);
+        }
+    }
+
+    /**
+     * <p>Get the progress bar's current level of progress. Return 0 when the
+     * progress bar is in indeterminate mode.</p>
+     *
+     * @return the current progress, between 0 and {@link #getMax()}
+     *
+     * @see #setIndeterminate(boolean)
+     * @see #isIndeterminate()
+     * @see #setProgress(int)
+     * @see #setMax(int)
+     * @see #getMax()
+     */
+    @ViewDebug.ExportedProperty(category = "progress")
+    public synchronized int getProgress() {
+        return mIndeterminate ? 0 : mProgress;
+    }
+
+    /**
+     * <p>Get the progress bar's current level of secondary progress. Return 0 when the
+     * progress bar is in indeterminate mode.</p>
+     *
+     * @return the current secondary progress, between 0 and {@link #getMax()}
+     *
+     * @see #setIndeterminate(boolean)
+     * @see #isIndeterminate()
+     * @see #setSecondaryProgress(int)
+     * @see #setMax(int)
+     * @see #getMax()
+     */
+    @ViewDebug.ExportedProperty(category = "progress")
+    public synchronized int getSecondaryProgress() {
+        return mIndeterminate ? 0 : mSecondaryProgress;
+    }
+
+    /**
+     * <p>Return the upper limit of this progress bar's range.</p>
+     *
+     * @return a positive integer
+     *
+     * @see #setMax(int)
+     * @see #getProgress()
+     * @see #getSecondaryProgress()
+     */
+    @ViewDebug.ExportedProperty(category = "progress")
+    public synchronized int getMax() {
+        return mMax;
+    }
+
+    /**
+     * <p>Set the range of the progress bar to 0...<tt>max</tt>.</p>
+     *
+     * @param max the upper range of this progress bar
+     *
+     * @see #getMax()
+     * @see #setProgress(int)
+     * @see #setSecondaryProgress(int)
+     */
+    public synchronized void setMax(int max) {
+        if (max < 0) {
+            max = 0;
+        }
+        if (max != mMax) {
+            mMax = max;
+            postInvalidate();
+
+            if (mProgress > max) {
+                mProgress = max;
+            }
+            refreshProgress(android.R.id.progress, mProgress, false);
+        }
+    }
+
+    /**
+     * <p>Increase the progress bar's progress by the specified amount.</p>
+     *
+     * @param diff the amount by which the progress must be increased
+     *
+     * @see #setProgress(int)
+     */
+    public synchronized final void incrementProgressBy(int diff) {
+        setProgress(mProgress + diff);
+    }
+
+    /**
+     * <p>Increase the progress bar's secondary progress by the specified amount.</p>
+     *
+     * @param diff the amount by which the secondary progress must be increased
+     *
+     * @see #setSecondaryProgress(int)
+     */
+    public synchronized final void incrementSecondaryProgressBy(int diff) {
+        setSecondaryProgress(mSecondaryProgress + diff);
+    }
+
+    /**
+     * <p>Start the indeterminate progress animation.</p>
+     */
+    void startAnimation() {
+        if (getVisibility() != VISIBLE) {
+            return;
+        }
+
+        if (mIndeterminateDrawable instanceof Animatable) {
+            mShouldStartAnimationDrawable = true;
+            mAnimation = null;
+        } else {
+            if (mInterpolator == null) {
+                mInterpolator = new LinearInterpolator();
+            }
+
+            mTransformation = new Transformation();
+            mAnimation = new AlphaAnimation(0.0f, 1.0f);
+            mAnimation.setRepeatMode(mBehavior);
+            mAnimation.setRepeatCount(Animation.INFINITE);
+            mAnimation.setDuration(mDuration);
+            mAnimation.setInterpolator(mInterpolator);
+            mAnimation.setStartTime(Animation.START_ON_FIRST_FRAME);
+        }
+        postInvalidate();
+    }
+
+    /**
+     * <p>Stop the indeterminate progress animation.</p>
+     */
+    void stopAnimation() {
+        mAnimation = null;
+        mTransformation = null;
+        if (mIndeterminateDrawable instanceof Animatable) {
+            ((Animatable) mIndeterminateDrawable).stop();
+            mShouldStartAnimationDrawable = false;
+        }
+        postInvalidate();
+    }
+
+    /**
+     * Sets the acceleration curve for the indeterminate animation.
+     * The interpolator is loaded as a resource from the specified context.
+     *
+     * @param context The application environment
+     * @param resID The resource identifier of the interpolator to load
+     */
+    public void setInterpolator(Context context, int resID) {
+        setInterpolator(AnimationUtils.loadInterpolator(context, resID));
+    }
+
+    /**
+     * Sets the acceleration curve for the indeterminate animation.
+     * Defaults to a linear interpolation.
+     *
+     * @param interpolator The interpolator which defines the acceleration curve
+     */
+    public void setInterpolator(Interpolator interpolator) {
+        mInterpolator = interpolator;
+    }
+
+    /**
+     * Gets the acceleration curve type for the indeterminate animation.
+     *
+     * @return the {@link Interpolator} associated to this animation
+     */
+    public Interpolator getInterpolator() {
+        return mInterpolator;
+    }
+
+    @Override
+    public void setVisibility(int v) {
+        if (getVisibility() != v) {
+            super.setVisibility(v);
+
+            if (mIndeterminate) {
+                // let's be nice with the UI thread
+                if (v == GONE || v == INVISIBLE) {
+                    stopAnimation();
+                } else {
+                    startAnimation();
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void onVisibilityChanged(View changedView, int visibility) {
+        super.onVisibilityChanged(changedView, visibility);
+
+        if (mIndeterminate) {
+            // let's be nice with the UI thread
+            if (visibility == GONE || visibility == INVISIBLE) {
+                stopAnimation();
+            } else {
+                startAnimation();
+            }
+        }
+    }
+
+    @Override
+    public void invalidateDrawable(Drawable dr) {
+        if (!mInDrawing) {
+            if (verifyDrawable(dr)) {
+                final Rect dirty = dr.getBounds();
+                final int scrollX = getScrollX() + getPaddingLeft();
+                final int scrollY = getScrollY() + getPaddingTop();
+
+                invalidate(dirty.left + scrollX, dirty.top + scrollY,
+                        dirty.right + scrollX, dirty.bottom + scrollY);
+            } else {
+                super.invalidateDrawable(dr);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     *
+    @Override
+    public int getResolvedLayoutDirection(Drawable who) {
+        return (who == mProgressDrawable || who == mIndeterminateDrawable) ?
+            getResolvedLayoutDirection() : super.getResolvedLayoutDirection(who);
+    }
+    */
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        updateDrawableBounds(w, h);
+    }
+
+    private void updateDrawableBounds(int w, int h) {
+        // onDraw will translate the canvas so we draw starting at 0,0
+        int right = w - getPaddingRight() - getPaddingLeft();
+        int bottom = h - getPaddingBottom() - getPaddingTop();
+        int top = 0;
+        int left = 0;
+
+        if (mIndeterminateDrawable != null) {
+            // Aspect ratio logic does not apply to AnimationDrawables
+            if (mOnlyIndeterminate && !(mIndeterminateDrawable instanceof AnimationDrawable)) {
+                // Maintain aspect ratio. Certain kinds of animated drawables
+                // get very confused otherwise.
+                final int intrinsicWidth = mIndeterminateDrawable.getIntrinsicWidth();
+                final int intrinsicHeight = mIndeterminateDrawable.getIntrinsicHeight();
+                final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight;
+                final float boundAspect = (float) w / h;
+                if (intrinsicAspect != boundAspect) {
+                    if (boundAspect > intrinsicAspect) {
+                        // New width is larger. Make it smaller to match height.
+                        final int width = (int) (h * intrinsicAspect);
+                        left = (w - width) / 2;
+                        right = left + width;
+                    } else {
+                        // New height is larger. Make it smaller to match width.
+                        final int height = (int) (w * (1 / intrinsicAspect));
+                        top = (h - height) / 2;
+                        bottom = top + height;
+                    }
+                }
+            }
+            mIndeterminateDrawable.setBounds(0, 0, right - left, bottom - top);
+            mIndeterminateRealLeft = left;
+            mIndeterminateRealTop = top;
+        }
+
+        if (mProgressDrawable != null) {
+            mProgressDrawable.setBounds(0, 0, right, bottom);
+        }
+    }
+
+    @Override
+    protected synchronized void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+
+        Drawable d = mCurrentDrawable;
+        if (d != null) {
+            // Translate canvas so a indeterminate circular progress bar with padding
+            // rotates properly in its animation
+            canvas.save();
+            canvas.translate(getPaddingLeft() + mIndeterminateRealLeft, getPaddingTop() + mIndeterminateRealTop);
+            long time = getDrawingTime();
+            if (mAnimation != null) {
+                mAnimation.getTransformation(time, mTransformation);
+                float scale = mTransformation.getAlpha();
+                try {
+                    mInDrawing = true;
+                    d.setLevel((int) (scale * MAX_LEVEL));
+                } finally {
+                    mInDrawing = false;
+                }
+                if (SystemClock.uptimeMillis() - mLastDrawTime >= mAnimationResolution) {
+                    mLastDrawTime = SystemClock.uptimeMillis();
+                    postInvalidateDelayed(mAnimationResolution);
+                }
+            }
+            d.draw(canvas);
+            canvas.restore();
+            if (mShouldStartAnimationDrawable && d instanceof Animatable) {
+                ((Animatable) d).start();
+                mShouldStartAnimationDrawable = false;
+            }
+        }
+    }
+
+    @Override
+    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        Drawable d = mCurrentDrawable;
+
+        int dw = 0;
+        int dh = 0;
+        if (d != null) {
+            dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
+            dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
+        }
+        updateDrawableState();
+        dw += getPaddingLeft() + getPaddingRight();
+        dh += getPaddingTop() + getPaddingBottom();
+
+        if (IS_HONEYCOMB) {
+            setMeasuredDimension(View.resolveSizeAndState(dw, widthMeasureSpec, 0),
+                    View.resolveSizeAndState(dh, heightMeasureSpec, 0));
+        } else {
+            setMeasuredDimension(View.resolveSize(dw, widthMeasureSpec),
+                    View.resolveSize(dh, heightMeasureSpec));
+        }
+    }
+
+    @Override
+    protected void drawableStateChanged() {
+        super.drawableStateChanged();
+        updateDrawableState();
+    }
+
+    private void updateDrawableState() {
+        int[] state = getDrawableState();
+
+        if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
+            mProgressDrawable.setState(state);
+        }
+
+        if (mIndeterminateDrawable != null && mIndeterminateDrawable.isStateful()) {
+            mIndeterminateDrawable.setState(state);
+        }
+    }
+
+    static class SavedState extends BaseSavedState {
+        int progress;
+        int secondaryProgress;
+
+        /**
+         * Constructor called from {@link IcsProgressBar#onSaveInstanceState()}
+         */
+        SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        /**
+         * Constructor called from {@link #CREATOR}
+         */
+        private SavedState(Parcel in) {
+            super(in);
+            progress = in.readInt();
+            secondaryProgress = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+            out.writeInt(progress);
+            out.writeInt(secondaryProgress);
+        }
+
+        public static final Parcelable.Creator<SavedState> CREATOR
+                = new Parcelable.Creator<SavedState>() {
+            public SavedState createFromParcel(Parcel in) {
+                return new SavedState(in);
+            }
+
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        // Force our ancestor class to save its state
+        Parcelable superState = super.onSaveInstanceState();
+        SavedState ss = new SavedState(superState);
+
+        ss.progress = mProgress;
+        ss.secondaryProgress = mSecondaryProgress;
+
+        return ss;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+
+        setProgress(ss.progress);
+        setSecondaryProgress(ss.secondaryProgress);
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (mIndeterminate) {
+            startAnimation();
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        if (mIndeterminate) {
+            stopAnimation();
+        }
+        if(mRefreshProgressRunnable != null) {
+            removeCallbacks(mRefreshProgressRunnable);
+        }
+        if (mAccessibilityEventSender != null) {
+            removeCallbacks(mAccessibilityEventSender);
+        }
+        // This should come after stopAnimation(), otherwise an invalidate message remains in the
+        // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        event.setItemCount(mMax);
+        event.setCurrentItemIndex(mProgress);
+    }
+
+    /**
+     * Schedule a command for sending an accessibility event.
+     * </br>
+     * Note: A command is used to ensure that accessibility events
+     *       are sent at most one in a given time frame to save
+     *       system resources while the progress changes quickly.
+     */
+    private void scheduleAccessibilityEventSender() {
+        if (mAccessibilityEventSender == null) {
+            mAccessibilityEventSender = new AccessibilityEventSender();
+        } else {
+            removeCallbacks(mAccessibilityEventSender);
+        }
+        postDelayed(mAccessibilityEventSender, TIMEOUT_SEND_ACCESSIBILITY_EVENT);
+    }
+
+    /**
+     * Command for sending an accessibility event.
+     */
+    private class AccessibilityEventSender implements Runnable {
+        public void run() {
+            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsSpinner.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsSpinner.java
new file mode 100644 (file)
index 0000000..038d1e0
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.internal.widget;
+
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+import com.actionbarsherlock.R;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.PopupWindow;
+import android.widget.SpinnerAdapter;
+
+
+/**
+ * A view that displays one child at a time and lets the user pick among them.
+ * The items in the Spinner come from the {@link Adapter} associated with
+ * this view.
+ *
+ * <p>See the <a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner
+ * tutorial</a>.</p>
+ *
+ * @attr ref android.R.styleable#Spinner_prompt
+ */
+public class IcsSpinner extends IcsAbsSpinner implements OnClickListener {
+    //private static final String TAG = "Spinner";
+
+    // Only measure this many items to get a decent max width.
+    private static final int MAX_ITEMS_MEASURED = 15;
+
+    /**
+     * Use a dialog window for selecting spinner options.
+     */
+    //public static final int MODE_DIALOG = 0;
+
+    /**
+     * Use a dropdown anchored to the Spinner for selecting spinner options.
+     */
+    public static final int MODE_DROPDOWN = 1;
+
+    /**
+     * Use the theme-supplied value to select the dropdown mode.
+     */
+    //private static final int MODE_THEME = -1;
+
+    private SpinnerPopup mPopup;
+    private DropDownAdapter mTempAdapter;
+    int mDropDownWidth;
+
+    private int mGravity;
+    private boolean mDisableChildrenWhenDisabled;
+
+    private Rect mTempRect = new Rect();
+
+    public IcsSpinner(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.actionDropDownStyle);
+    }
+
+    /**
+     * Construct a new spinner with the given context's theme, the supplied attribute set,
+     * and default style.
+     *
+     * @param context The Context the view is running in, through which it can
+     *        access the current theme, resources, etc.
+     * @param attrs The attributes of the XML tag that is inflating the view.
+     * @param defStyle The default style to apply to this view. If 0, no style
+     *        will be applied (beyond what is included in the theme). This may
+     *        either be an attribute resource, whose value will be retrieved
+     *        from the current theme, or an explicit style resource.
+     */
+    public IcsSpinner(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.SherlockSpinner, defStyle, 0);
+
+
+        DropdownPopup popup = new DropdownPopup(context, attrs, defStyle);
+
+        mDropDownWidth = a.getLayoutDimension(
+                R.styleable.SherlockSpinner_android_dropDownWidth,
+                ViewGroup.LayoutParams.WRAP_CONTENT);
+        popup.setBackgroundDrawable(a.getDrawable(
+                R.styleable.SherlockSpinner_android_popupBackground));
+        final int verticalOffset = a.getDimensionPixelOffset(
+                R.styleable.SherlockSpinner_android_dropDownVerticalOffset, 0);
+        if (verticalOffset != 0) {
+            popup.setVerticalOffset(verticalOffset);
+        }
+
+        final int horizontalOffset = a.getDimensionPixelOffset(
+                R.styleable.SherlockSpinner_android_dropDownHorizontalOffset, 0);
+        if (horizontalOffset != 0) {
+            popup.setHorizontalOffset(horizontalOffset);
+        }
+
+        mPopup = popup;
+
+        mGravity = a.getInt(R.styleable.SherlockSpinner_android_gravity, Gravity.CENTER);
+
+        mPopup.setPromptText(a.getString(R.styleable.SherlockSpinner_android_prompt));
+
+        mDisableChildrenWhenDisabled = true;
+
+        a.recycle();
+
+        // Base constructor can call setAdapter before we initialize mPopup.
+        // Finish setting things up if this happened.
+        if (mTempAdapter != null) {
+            mPopup.setAdapter(mTempAdapter);
+            mTempAdapter = null;
+        }
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        super.setEnabled(enabled);
+        if (mDisableChildrenWhenDisabled) {
+            final int count = getChildCount();
+            for (int i = 0; i < count; i++) {
+                getChildAt(i).setEnabled(enabled);
+            }
+        }
+    }
+
+    /**
+     * Describes how the selected item view is positioned. Currently only the horizontal component
+     * is used. The default is determined by the current theme.
+     *
+     * @param gravity See {@link android.view.Gravity}
+     *
+     * @attr ref android.R.styleable#Spinner_gravity
+     */
+    public void setGravity(int gravity) {
+        if (mGravity != gravity) {
+            if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
+                gravity |= Gravity.LEFT;
+            }
+            mGravity = gravity;
+            requestLayout();
+        }
+    }
+
+    @Override
+    public void setAdapter(SpinnerAdapter adapter) {
+        super.setAdapter(adapter);
+
+        if (mPopup != null) {
+            mPopup.setAdapter(new DropDownAdapter(adapter));
+        } else {
+            mTempAdapter = new DropDownAdapter(adapter);
+        }
+    }
+
+    @Override
+    public int getBaseline() {
+        View child = null;
+
+        if (getChildCount() > 0) {
+            child = getChildAt(0);
+        } else if (mAdapter != null && mAdapter.getCount() > 0) {
+            child = makeAndAddView(0);
+            mRecycler.put(0, child);
+            removeAllViewsInLayout();
+        }
+
+        if (child != null) {
+            final int childBaseline = child.getBaseline();
+            return childBaseline >= 0 ? child.getTop() + childBaseline : -1;
+        } else {
+            return -1;
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+
+        if (mPopup != null && mPopup.isShowing()) {
+            mPopup.dismiss();
+        }
+    }
+
+    /**
+     * <p>A spinner does not support item click events. Calling this method
+     * will raise an exception.</p>
+     *
+     * @param l this listener will be ignored
+     */
+    @Override
+    public void setOnItemClickListener(OnItemClickListener l) {
+        throw new RuntimeException("setOnItemClickListener cannot be used with a spinner.");
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
+            final int measuredWidth = getMeasuredWidth();
+            setMeasuredDimension(Math.min(Math.max(measuredWidth,
+                    measureContentWidth(getAdapter(), getBackground())),
+                    MeasureSpec.getSize(widthMeasureSpec)),
+                    getMeasuredHeight());
+        }
+    }
+
+    /**
+     * @see android.view.View#onLayout(boolean,int,int,int,int)
+     *
+     * Creates and positions all views
+     *
+     */
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        mInLayout = true;
+        layout(0, false);
+        mInLayout = false;
+    }
+
+    /**
+     * Creates and positions all views for this Spinner.
+     *
+     * @param delta Change in the selected position. +1 moves selection is moving to the right,
+     * so views are scrolling to the left. -1 means selection is moving to the left.
+     */
+    @Override
+    void layout(int delta, boolean animate) {
+        int childrenLeft = mSpinnerPadding.left;
+        int childrenWidth = getRight() - getLeft() - mSpinnerPadding.left - mSpinnerPadding.right;
+
+        if (mDataChanged) {
+            handleDataChanged();
+        }
+
+        // Handle the empty set by removing all views
+        if (mItemCount == 0) {
+            resetList();
+            return;
+        }
+
+        if (mNextSelectedPosition >= 0) {
+            setSelectedPositionInt(mNextSelectedPosition);
+        }
+
+        recycleAllViews();
+
+        // Clear out old views
+        removeAllViewsInLayout();
+
+        // Make selected view and position it
+        mFirstPosition = mSelectedPosition;
+        View sel = makeAndAddView(mSelectedPosition);
+        int width = sel.getMeasuredWidth();
+        int selectedOffset = childrenLeft;
+        switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
+            case Gravity.CENTER_HORIZONTAL:
+                selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
+                break;
+            case Gravity.RIGHT:
+                selectedOffset = childrenLeft + childrenWidth - width;
+                break;
+        }
+        sel.offsetLeftAndRight(selectedOffset);
+
+        // Flush any cached views that did not get reused above
+        mRecycler.clear();
+
+        invalidate();
+
+        checkSelectionChanged();
+
+        mDataChanged = false;
+        mNeedSync = false;
+        setNextSelectedPositionInt(mSelectedPosition);
+    }
+
+    /**
+     * Obtain a view, either by pulling an existing view from the recycler or
+     * by getting a new one from the adapter. If we are animating, make sure
+     * there is enough information in the view's layout parameters to animate
+     * from the old to new positions.
+     *
+     * @param position Position in the spinner for the view to obtain
+     * @return A view that has been added to the spinner
+     */
+    private View makeAndAddView(int position) {
+
+        View child;
+
+        if (!mDataChanged) {
+            child = mRecycler.get(position);
+            if (child != null) {
+                // Position the view
+                setUpChild(child);
+
+                return child;
+            }
+        }
+
+        // Nothing found in the recycler -- ask the adapter for a view
+        child = mAdapter.getView(position, null, this);
+
+        // Position the view
+        setUpChild(child);
+
+        return child;
+    }
+
+    /**
+     * Helper for makeAndAddView to set the position of a view
+     * and fill out its layout paramters.
+     *
+     * @param child The view to position
+     */
+    private void setUpChild(View child) {
+
+        // Respect layout params that are already in the view. Otherwise
+        // make some up...
+        ViewGroup.LayoutParams lp = child.getLayoutParams();
+        if (lp == null) {
+            lp = generateDefaultLayoutParams();
+        }
+
+        addViewInLayout(child, 0, lp);
+
+        child.setSelected(hasFocus());
+        if (mDisableChildrenWhenDisabled) {
+            child.setEnabled(isEnabled());
+        }
+
+        // Get measure specs
+        int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,
+                mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height);
+        int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
+                mSpinnerPadding.left + mSpinnerPadding.right, lp.width);
+
+        // Measure child
+        child.measure(childWidthSpec, childHeightSpec);
+
+        int childLeft;
+        int childRight;
+
+        // Position vertically based on gravity setting
+        int childTop = mSpinnerPadding.top
+                + ((getMeasuredHeight() - mSpinnerPadding.bottom -
+                        mSpinnerPadding.top - child.getMeasuredHeight()) / 2);
+        int childBottom = childTop + child.getMeasuredHeight();
+
+        int width = child.getMeasuredWidth();
+        childLeft = 0;
+        childRight = childLeft + width;
+
+        child.layout(childLeft, childTop, childRight, childBottom);
+    }
+
+    @Override
+    public boolean performClick() {
+        boolean handled = super.performClick();
+
+        if (!handled) {
+            handled = true;
+
+            if (!mPopup.isShowing()) {
+                mPopup.show();
+            }
+        }
+
+        return handled;
+    }
+
+    public void onClick(DialogInterface dialog, int which) {
+        setSelection(which);
+        dialog.dismiss();
+    }
+
+    /**
+     * Sets the prompt to display when the dialog is shown.
+     * @param prompt the prompt to set
+     */
+    public void setPrompt(CharSequence prompt) {
+        mPopup.setPromptText(prompt);
+    }
+
+    /**
+     * Sets the prompt to display when the dialog is shown.
+     * @param promptId the resource ID of the prompt to display when the dialog is shown
+     */
+    public void setPromptId(int promptId) {
+        setPrompt(getContext().getText(promptId));
+    }
+
+    /**
+     * @return The prompt to display when the dialog is shown
+     */
+    public CharSequence getPrompt() {
+        return mPopup.getHintText();
+    }
+
+    int measureContentWidth(SpinnerAdapter adapter, Drawable background) {
+        if (adapter == null) {
+            return 0;
+        }
+
+        int width = 0;
+        View itemView = null;
+        int itemType = 0;
+        final int widthMeasureSpec =
+            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec =
+            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+
+        // Make sure the number of items we'll measure is capped. If it's a huge data set
+        // with wildly varying sizes, oh well.
+        int start = Math.max(0, getSelectedItemPosition());
+        final int end = Math.min(adapter.getCount(), start + MAX_ITEMS_MEASURED);
+        final int count = end - start;
+        start = Math.max(0, start - (MAX_ITEMS_MEASURED - count));
+        for (int i = start; i < end; i++) {
+            final int positionType = adapter.getItemViewType(i);
+            if (positionType != itemType) {
+                itemType = positionType;
+                itemView = null;
+            }
+            itemView = adapter.getView(i, itemView, this);
+            if (itemView.getLayoutParams() == null) {
+                itemView.setLayoutParams(new ViewGroup.LayoutParams(
+                        ViewGroup.LayoutParams.WRAP_CONTENT,
+                        ViewGroup.LayoutParams.WRAP_CONTENT));
+            }
+            itemView.measure(widthMeasureSpec, heightMeasureSpec);
+            width = Math.max(width, itemView.getMeasuredWidth());
+        }
+
+        // Add background padding to measured width
+        if (background != null) {
+            background.getPadding(mTempRect);
+            width += mTempRect.left + mTempRect.right;
+        }
+
+        return width;
+    }
+
+    /**
+     * <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance
+     * into a ListAdapter.</p>
+     */
+    private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
+        private SpinnerAdapter mAdapter;
+        private ListAdapter mListAdapter;
+
+        /**
+         * <p>Creates a new ListAdapter wrapper for the specified adapter.</p>
+         *
+         * @param adapter the Adapter to transform into a ListAdapter
+         */
+        public DropDownAdapter(SpinnerAdapter adapter) {
+            this.mAdapter = adapter;
+            if (adapter instanceof ListAdapter) {
+                this.mListAdapter = (ListAdapter) adapter;
+            }
+        }
+
+        public int getCount() {
+            return mAdapter == null ? 0 : mAdapter.getCount();
+        }
+
+        public Object getItem(int position) {
+            return mAdapter == null ? null : mAdapter.getItem(position);
+        }
+
+        public long getItemId(int position) {
+            return mAdapter == null ? -1 : mAdapter.getItemId(position);
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            return getDropDownView(position, convertView, parent);
+        }
+
+        public View getDropDownView(int position, View convertView, ViewGroup parent) {
+            return mAdapter == null ? null :
+                    mAdapter.getDropDownView(position, convertView, parent);
+        }
+
+        public boolean hasStableIds() {
+            return mAdapter != null && mAdapter.hasStableIds();
+        }
+
+        public void registerDataSetObserver(DataSetObserver observer) {
+            if (mAdapter != null) {
+                mAdapter.registerDataSetObserver(observer);
+            }
+        }
+
+        public void unregisterDataSetObserver(DataSetObserver observer) {
+            if (mAdapter != null) {
+                mAdapter.unregisterDataSetObserver(observer);
+            }
+        }
+
+        /**
+         * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
+         * Otherwise, return true.
+         */
+        public boolean areAllItemsEnabled() {
+            final ListAdapter adapter = mListAdapter;
+            if (adapter != null) {
+                return adapter.areAllItemsEnabled();
+            } else {
+                return true;
+            }
+        }
+
+        /**
+         * If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
+         * Otherwise, return true.
+         */
+        public boolean isEnabled(int position) {
+            final ListAdapter adapter = mListAdapter;
+            if (adapter != null) {
+                return adapter.isEnabled(position);
+            } else {
+                return true;
+            }
+        }
+
+        public int getItemViewType(int position) {
+            return 0;
+        }
+
+        public int getViewTypeCount() {
+            return 1;
+        }
+
+        public boolean isEmpty() {
+            return getCount() == 0;
+        }
+    }
+
+    /**
+     * Implements some sort of popup selection interface for selecting a spinner option.
+     * Allows for different spinner modes.
+     */
+    private interface SpinnerPopup {
+        public void setAdapter(ListAdapter adapter);
+
+        /**
+         * Show the popup
+         */
+        public void show();
+
+        /**
+         * Dismiss the popup
+         */
+        public void dismiss();
+
+        /**
+         * @return true if the popup is showing, false otherwise.
+         */
+        public boolean isShowing();
+
+        /**
+         * Set hint text to be displayed to the user. This should provide
+         * a description of the choice being made.
+         * @param hintText Hint text to set.
+         */
+        public void setPromptText(CharSequence hintText);
+        public CharSequence getHintText();
+    }
+
+    /*
+    private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
+        private AlertDialog mPopup;
+        private ListAdapter mListAdapter;
+        private CharSequence mPrompt;
+
+        public void dismiss() {
+            mPopup.dismiss();
+            mPopup = null;
+        }
+
+        public boolean isShowing() {
+            return mPopup != null ? mPopup.isShowing() : false;
+        }
+
+        public void setAdapter(ListAdapter adapter) {
+            mListAdapter = adapter;
+        }
+
+        public void setPromptText(CharSequence hintText) {
+            mPrompt = hintText;
+        }
+
+        public CharSequence getHintText() {
+            return mPrompt;
+        }
+
+        public void show() {
+            AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
+            if (mPrompt != null) {
+                builder.setTitle(mPrompt);
+            }
+            mPopup = builder.setSingleChoiceItems(mListAdapter,
+                    getSelectedItemPosition(), this).show();
+        }
+
+        public void onClick(DialogInterface dialog, int which) {
+            setSelection(which);
+            dismiss();
+        }
+    }
+    */
+
+    private class DropdownPopup extends IcsListPopupWindow implements SpinnerPopup {
+        private CharSequence mHintText;
+        private ListAdapter mAdapter;
+
+        public DropdownPopup(Context context, AttributeSet attrs, int defStyleRes) {
+            super(context, attrs, 0, defStyleRes);
+
+            setAnchorView(IcsSpinner.this);
+            setModal(true);
+            setPromptPosition(POSITION_PROMPT_ABOVE);
+            setOnItemClickListener(new OnItemClickListener() {
+                @SuppressWarnings("rawtypes")
+                public void onItemClick(AdapterView parent, View v, int position, long id) {
+                    IcsSpinner.this.setSelection(position);
+                    dismiss();
+                }
+            });
+        }
+
+        @Override
+        public void setAdapter(ListAdapter adapter) {
+            super.setAdapter(adapter);
+            mAdapter = adapter;
+        }
+
+        public CharSequence getHintText() {
+            return mHintText;
+        }
+
+        public void setPromptText(CharSequence hintText) {
+            // Hint text is ignored for dropdowns, but maintain it here.
+            mHintText = hintText;
+        }
+
+        @Override
+        public void show() {
+            final int spinnerPaddingLeft = IcsSpinner.this.getPaddingLeft();
+            if (mDropDownWidth == WRAP_CONTENT) {
+                final int spinnerWidth = IcsSpinner.this.getWidth();
+                final int spinnerPaddingRight = IcsSpinner.this.getPaddingRight();
+                setContentWidth(Math.max(
+                        measureContentWidth((SpinnerAdapter) mAdapter, getBackground()),
+                        spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight));
+            } else if (mDropDownWidth == MATCH_PARENT) {
+                final int spinnerWidth = IcsSpinner.this.getWidth();
+                final int spinnerPaddingRight = IcsSpinner.this.getPaddingRight();
+                setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight);
+            } else {
+                setContentWidth(mDropDownWidth);
+            }
+            final Drawable background = getBackground();
+            int bgOffset = 0;
+            if (background != null) {
+                background.getPadding(mTempRect);
+                bgOffset = -mTempRect.left;
+            }
+            setHorizontalOffset(bgOffset + spinnerPaddingLeft);
+            setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+            super.show();
+            getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+            setSelection(IcsSpinner.this.getSelectedItemPosition());
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/IcsView.java
new file mode 100644 (file)
index 0000000..a7185d0
--- /dev/null
@@ -0,0 +1,21 @@
+package com.actionbarsherlock.internal.widget;
+
+import android.view.View;
+
+final class IcsView {
+    //No instances
+    private IcsView() {}
+
+    /**
+     * Return only the state bits of {@link #getMeasuredWidthAndState()}
+     * and {@link #getMeasuredHeightAndState()}, combined into one integer.
+     * The width component is in the regular bits {@link #MEASURED_STATE_MASK}
+     * and the height component is at the shifted bits
+     * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}.
+     */
+    public static int getMeasuredStateInt(View child) {
+        return (child.getMeasuredWidth()&View.MEASURED_STATE_MASK)
+                | ((child.getMeasuredHeight()>>View.MEASURED_HEIGHT_STATE_SHIFT)
+                        & (View.MEASURED_STATE_MASK>>View.MEASURED_HEIGHT_STATE_SHIFT));
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/internal/widget/ScrollingTabContainerView.java
new file mode 100644 (file)
index 0000000..1a532e0
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.actionbarsherlock.internal.widget;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils.TruncateAt;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.app.ActionBar;
+import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
+import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
+import com.actionbarsherlock.internal.nineoldandroids.widget.NineHorizontalScrollView;
+
+/**
+ * This widget implements the dynamic action bar tab behavior that can change
+ * across different configurations or circumstances.
+ */
+public class ScrollingTabContainerView extends NineHorizontalScrollView
+        implements IcsAdapterView.OnItemSelectedListener {
+    //UNUSED private static final String TAG = "ScrollingTabContainerView";
+    Runnable mTabSelector;
+    private TabClickListener mTabClickListener;
+
+    private IcsLinearLayout mTabLayout;
+    private IcsSpinner mTabSpinner;
+    private boolean mAllowCollapse;
+
+    private LayoutInflater mInflater;
+
+    int mMaxTabWidth;
+    private int mContentHeight;
+    private int mSelectedTabIndex;
+
+    protected Animator mVisibilityAnim;
+    protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
+
+    private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator();
+
+    private static final int FADE_DURATION = 200;
+
+    public ScrollingTabContainerView(Context context) {
+        super(context);
+        setHorizontalScrollBarEnabled(false);
+
+        TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
+                R.attr.actionBarStyle, 0);
+        setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
+        a.recycle();
+
+        mInflater = LayoutInflater.from(context);
+
+        mTabLayout = createTabLayout();
+        addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+    }
+
+    @Override
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;
+        setFillViewport(lockedExpanded);
+
+        final int childCount = mTabLayout.getChildCount();
+        if (childCount > 1 &&
+                (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
+            if (childCount > 2) {
+                mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f);
+            } else {
+                mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;
+            }
+        } else {
+            mMaxTabWidth = -1;
+        }
+
+        heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY);
+
+        final boolean canCollapse = !lockedExpanded && mAllowCollapse;
+
+        if (canCollapse) {
+            // See if we should expand
+            mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec);
+            if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) {
+                performCollapse();
+            } else {
+                performExpand();
+            }
+        } else {
+            performExpand();
+        }
+
+        final int oldWidth = getMeasuredWidth();
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        final int newWidth = getMeasuredWidth();
+
+        if (lockedExpanded && oldWidth != newWidth) {
+            // Recenter the tab display if we're at a new (scrollable) size.
+            setTabSelected(mSelectedTabIndex);
+        }
+    }
+
+    /**
+     * Indicates whether this view is collapsed into a dropdown menu instead
+     * of traditional tabs.
+     * @return true if showing as a spinner
+     */
+    private boolean isCollapsed() {
+        return mTabSpinner != null && mTabSpinner.getParent() == this;
+    }
+
+    public void setAllowCollapse(boolean allowCollapse) {
+        mAllowCollapse = allowCollapse;
+    }
+
+    private void performCollapse() {
+        if (isCollapsed()) return;
+
+        if (mTabSpinner == null) {
+            mTabSpinner = createSpinner();
+        }
+        removeView(mTabLayout);
+        addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+        if (mTabSpinner.getAdapter() == null) {
+            mTabSpinner.setAdapter(new TabAdapter());
+        }
+        if (mTabSelector != null) {
+            removeCallbacks(mTabSelector);
+            mTabSelector = null;
+        }
+        mTabSpinner.setSelection(mSelectedTabIndex);
+    }
+
+    private boolean performExpand() {
+        if (!isCollapsed()) return false;
+
+        removeView(mTabSpinner);
+        addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+        setTabSelected(mTabSpinner.getSelectedItemPosition());
+        return false;
+    }
+
+    public void setTabSelected(int position) {
+        mSelectedTabIndex = position;
+        final int tabCount = mTabLayout.getChildCount();
+        for (int i = 0; i < tabCount; i++) {
+            final View child = mTabLayout.getChildAt(i);
+            final boolean isSelected = i == position;
+            child.setSelected(isSelected);
+            if (isSelected) {
+                animateToTab(position);
+            }
+        }
+    }
+
+    public void setContentHeight(int contentHeight) {
+        mContentHeight = contentHeight;
+        requestLayout();
+    }
+
+    private IcsLinearLayout createTabLayout() {
+        final IcsLinearLayout tabLayout = (IcsLinearLayout) LayoutInflater.from(getContext())
+                .inflate(R.layout.abs__action_bar_tab_bar_view, null);
+        tabLayout.setLayoutParams(new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
+        return tabLayout;
+    }
+
+    private IcsSpinner createSpinner() {
+        final IcsSpinner spinner = new IcsSpinner(getContext(), null,
+                R.attr.actionDropDownStyle);
+        spinner.setLayoutParams(new LinearLayout.LayoutParams(
+                LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
+        spinner.setOnItemSelectedListener(this);
+        return spinner;
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+
+        // Action bar can change size on configuration changes.
+        // Reread the desired height from the theme-specified style.
+        TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
+                R.attr.actionBarStyle, 0);
+        setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
+        a.recycle();
+    }
+
+    public void animateToVisibility(int visibility) {
+        if (mVisibilityAnim != null) {
+            mVisibilityAnim.cancel();
+        }
+        if (visibility == VISIBLE) {
+            if (getVisibility() != VISIBLE) {
+                setAlpha(0);
+            }
+            ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
+            anim.setDuration(FADE_DURATION);
+            anim.setInterpolator(sAlphaInterpolator);
+
+            anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+            anim.start();
+        } else {
+            ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
+            anim.setDuration(FADE_DURATION);
+            anim.setInterpolator(sAlphaInterpolator);
+
+            anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+            anim.start();
+        }
+    }
+
+    public void animateToTab(final int position) {
+        final View tabView = mTabLayout.getChildAt(position);
+        if (mTabSelector != null) {
+            removeCallbacks(mTabSelector);
+        }
+        mTabSelector = new Runnable() {
+            public void run() {
+                final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;
+                smoothScrollTo(scrollPos, 0);
+                mTabSelector = null;
+            }
+        };
+        post(mTabSelector);
+    }
+
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        if (mTabSelector != null) {
+            // Re-post the selector we saved
+            post(mTabSelector);
+        }
+    }
+
+    @Override
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (mTabSelector != null) {
+            removeCallbacks(mTabSelector);
+        }
+    }
+
+    private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) {
+        //Workaround for not being able to pass a defStyle on pre-3.0
+        final TabView tabView = (TabView)mInflater.inflate(R.layout.abs__action_bar_tab, null);
+        tabView.init(this, tab, forAdapter);
+
+        if (forAdapter) {
+            tabView.setBackgroundDrawable(null);
+            tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT,
+                    mContentHeight));
+        } else {
+            tabView.setFocusable(true);
+
+            if (mTabClickListener == null) {
+                mTabClickListener = new TabClickListener();
+            }
+            tabView.setOnClickListener(mTabClickListener);
+        }
+        return tabView;
+    }
+
+    public void addTab(ActionBar.Tab tab, boolean setSelected) {
+        TabView tabView = createTabView(tab, false);
+        mTabLayout.addView(tabView, new IcsLinearLayout.LayoutParams(0,
+                LayoutParams.MATCH_PARENT, 1));
+        if (mTabSpinner != null) {
+            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
+        }
+        if (setSelected) {
+            tabView.setSelected(true);
+        }
+        if (mAllowCollapse) {
+            requestLayout();
+        }
+    }
+
+    public void addTab(ActionBar.Tab tab, int position, boolean setSelected) {
+        final TabView tabView = createTabView(tab, false);
+        mTabLayout.addView(tabView, position, new IcsLinearLayout.LayoutParams(
+                0, LayoutParams.MATCH_PARENT, 1));
+        if (mTabSpinner != null) {
+            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
+        }
+        if (setSelected) {
+            tabView.setSelected(true);
+        }
+        if (mAllowCollapse) {
+            requestLayout();
+        }
+    }
+
+    public void updateTab(int position) {
+        ((TabView) mTabLayout.getChildAt(position)).update();
+        if (mTabSpinner != null) {
+            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
+        }
+        if (mAllowCollapse) {
+            requestLayout();
+        }
+    }
+
+    public void removeTabAt(int position) {
+        mTabLayout.removeViewAt(position);
+        if (mTabSpinner != null) {
+            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
+        }
+        if (mAllowCollapse) {
+            requestLayout();
+        }
+    }
+
+    public void removeAllTabs() {
+        mTabLayout.removeAllViews();
+        if (mTabSpinner != null) {
+            ((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
+        }
+        if (mAllowCollapse) {
+            requestLayout();
+        }
+    }
+
+    @Override
+    public void onItemSelected(IcsAdapterView<?> parent, View view, int position, long id) {
+        TabView tabView = (TabView) view;
+        tabView.getTab().select();
+    }
+
+    @Override
+    public void onNothingSelected(IcsAdapterView<?> parent) {
+    }
+
+    public static class TabView extends LinearLayout {
+        private ScrollingTabContainerView mParent;
+        private ActionBar.Tab mTab;
+        private CapitalizingTextView mTextView;
+        private ImageView mIconView;
+        private View mCustomView;
+
+        public TabView(Context context, AttributeSet attrs) {
+            //TODO super(context, null, R.attr.actionBarTabStyle);
+            super(context, attrs);
+        }
+
+        public void init(ScrollingTabContainerView parent, ActionBar.Tab tab, boolean forList) {
+            mParent = parent;
+            mTab = tab;
+
+            if (forList) {
+                setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
+            }
+
+            update();
+        }
+
+        public void bindTab(ActionBar.Tab tab) {
+            mTab = tab;
+            update();
+        }
+
+        @Override
+        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+            // Re-measure if we went beyond our maximum size.
+            if (mParent.mMaxTabWidth > 0 && getMeasuredWidth() > mParent.mMaxTabWidth) {
+                super.onMeasure(MeasureSpec.makeMeasureSpec(mParent.mMaxTabWidth, MeasureSpec.EXACTLY),
+                        heightMeasureSpec);
+            }
+        }
+
+        public void update() {
+            final ActionBar.Tab tab = mTab;
+            final View custom = tab.getCustomView();
+            if (custom != null) {
+                final ViewParent customParent = custom.getParent();
+                if (customParent != this) {
+                    if (customParent != null) ((ViewGroup) customParent).removeView(custom);
+                    addView(custom);
+                }
+                mCustomView = custom;
+                if (mTextView != null) mTextView.setVisibility(GONE);
+                if (mIconView != null) {
+                    mIconView.setVisibility(GONE);
+                    mIconView.setImageDrawable(null);
+                }
+            } else {
+                if (mCustomView != null) {
+                    removeView(mCustomView);
+                    mCustomView = null;
+                }
+
+                final Drawable icon = tab.getIcon();
+                final CharSequence text = tab.getText();
+
+                if (icon != null) {
+                    if (mIconView == null) {
+                        ImageView iconView = new ImageView(getContext());
+                        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                                LayoutParams.WRAP_CONTENT);
+                        lp.gravity = Gravity.CENTER_VERTICAL;
+                        iconView.setLayoutParams(lp);
+                        addView(iconView, 0);
+                        mIconView = iconView;
+                    }
+                    mIconView.setImageDrawable(icon);
+                    mIconView.setVisibility(VISIBLE);
+                } else if (mIconView != null) {
+                    mIconView.setVisibility(GONE);
+                    mIconView.setImageDrawable(null);
+                }
+
+                if (text != null) {
+                    if (mTextView == null) {
+                        CapitalizingTextView textView = new CapitalizingTextView(getContext(), null,
+                                R.attr.actionBarTabTextStyle);
+                        textView.setEllipsize(TruncateAt.END);
+                        LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                                LayoutParams.WRAP_CONTENT);
+                        lp.gravity = Gravity.CENTER_VERTICAL;
+                        textView.setLayoutParams(lp);
+                        addView(textView);
+                        mTextView = textView;
+                    }
+                    mTextView.setTextCompat(text);
+                    mTextView.setVisibility(VISIBLE);
+                } else if (mTextView != null) {
+                    mTextView.setVisibility(GONE);
+                    mTextView.setText(null);
+                }
+
+                if (mIconView != null) {
+                    mIconView.setContentDescription(tab.getContentDescription());
+                }
+            }
+        }
+
+        public ActionBar.Tab getTab() {
+            return mTab;
+        }
+    }
+
+    private class TabAdapter extends BaseAdapter {
+        @Override
+        public int getCount() {
+            return mTabLayout.getChildCount();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return ((TabView) mTabLayout.getChildAt(position)).getTab();
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = createTabView((ActionBar.Tab) getItem(position), true);
+            } else {
+                ((TabView) convertView).bindTab((ActionBar.Tab) getItem(position));
+            }
+            return convertView;
+        }
+    }
+
+    private class TabClickListener implements OnClickListener {
+        public void onClick(View view) {
+            TabView tabView = (TabView) view;
+            tabView.getTab().select();
+            final int tabCount = mTabLayout.getChildCount();
+            for (int i = 0; i < tabCount; i++) {
+                final View child = mTabLayout.getChildAt(i);
+                child.setSelected(child == view);
+            }
+        }
+    }
+
+    protected class VisibilityAnimListener implements Animator.AnimatorListener {
+        private boolean mCanceled = false;
+        private int mFinalVisibility;
+
+        public VisibilityAnimListener withFinalVisibility(int visibility) {
+            mFinalVisibility = visibility;
+            return this;
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            setVisibility(VISIBLE);
+            mVisibilityAnim = animation;
+            mCanceled = false;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            if (mCanceled) return;
+
+            mVisibilityAnim = null;
+            setVisibility(mFinalVisibility);
+        }
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mCanceled = true;
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/ActionMode.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/ActionMode.java
new file mode 100644 (file)
index 0000000..81b4cd4
--- /dev/null
@@ -0,0 +1,224 @@
+/*\r
+ * Copyright (C) 2010 The Android Open Source Project\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.actionbarsherlock.view;\r
+\r
+import android.view.View;\r
+\r
+\r
+/**\r
+ * Represents a contextual mode of the user interface. Action modes can be used for\r
+ * modal interactions with content and replace parts of the normal UI until finished.\r
+ * Examples of good action modes include selection modes, search, content editing, etc.\r
+ */\r
+public abstract class ActionMode {\r
+    private Object mTag;\r
+\r
+    /**\r
+     * Set a tag object associated with this ActionMode.\r
+     *\r
+     * <p>Like the tag available to views, this allows applications to associate arbitrary\r
+     * data with an ActionMode for later reference.\r
+     *\r
+     * @param tag Tag to associate with this ActionMode\r
+     *\r
+     * @see #getTag()\r
+     */\r
+    public void setTag(Object tag) {\r
+        mTag = tag;\r
+    }\r
+\r
+    /**\r
+     * Retrieve the tag object associated with this ActionMode.\r
+     *\r
+     * <p>Like the tag available to views, this allows applications to associate arbitrary\r
+     * data with an ActionMode for later reference.\r
+     *\r
+     * @return Tag associated with this ActionMode\r
+     *\r
+     * @see #setTag(Object)\r
+     */\r
+    public Object getTag() {\r
+        return mTag;\r
+    }\r
+\r
+    /**\r
+     * Set the title of the action mode. This method will have no visible effect if\r
+     * a custom view has been set.\r
+     *\r
+     * @param title Title string to set\r
+     *\r
+     * @see #setTitle(int)\r
+     * @see #setCustomView(View)\r
+     */\r
+    public abstract void setTitle(CharSequence title);\r
+\r
+    /**\r
+     * Set the title of the action mode. This method will have no visible effect if\r
+     * a custom view has been set.\r
+     *\r
+     * @param resId Resource ID of a string to set as the title\r
+     *\r
+     * @see #setTitle(CharSequence)\r
+     * @see #setCustomView(View)\r
+     */\r
+    public abstract void setTitle(int resId);\r
+\r
+    /**\r
+     * Set the subtitle of the action mode. This method will have no visible effect if\r
+     * a custom view has been set.\r
+     *\r
+     * @param subtitle Subtitle string to set\r
+     *\r
+     * @see #setSubtitle(int)\r
+     * @see #setCustomView(View)\r
+     */\r
+    public abstract void setSubtitle(CharSequence subtitle);\r
+\r
+    /**\r
+     * Set the subtitle of the action mode. This method will have no visible effect if\r
+     * a custom view has been set.\r
+     *\r
+     * @param resId Resource ID of a string to set as the subtitle\r
+     *\r
+     * @see #setSubtitle(CharSequence)\r
+     * @see #setCustomView(View)\r
+     */\r
+    public abstract void setSubtitle(int resId);\r
+\r
+    /**\r
+     * Set a custom view for this action mode. The custom view will take the place of\r
+     * the title and subtitle. Useful for things like search boxes.\r
+     *\r
+     * @param view Custom view to use in place of the title/subtitle.\r
+     *\r
+     * @see #setTitle(CharSequence)\r
+     * @see #setSubtitle(CharSequence)\r
+     */\r
+    public abstract void setCustomView(View view);\r
+\r
+    /**\r
+     * Invalidate the action mode and refresh menu content. The mode's\r
+     * {@link ActionMode.Callback} will have its\r
+     * {@link Callback#onPrepareActionMode(ActionMode, Menu)} method called.\r
+     * If it returns true the menu will be scanned for updated content and any relevant changes\r
+     * will be reflected to the user.\r
+     */\r
+    public abstract void invalidate();\r
+\r
+    /**\r
+     * Finish and close this action mode. The action mode's {@link ActionMode.Callback} will\r
+     * have its {@link Callback#onDestroyActionMode(ActionMode)} method called.\r
+     */\r
+    public abstract void finish();\r
+\r
+    /**\r
+     * Returns the menu of actions that this action mode presents.\r
+     * @return The action mode's menu.\r
+     */\r
+    public abstract Menu getMenu();\r
+\r
+    /**\r
+     * Returns the current title of this action mode.\r
+     * @return Title text\r
+     */\r
+    public abstract CharSequence getTitle();\r
+\r
+    /**\r
+     * Returns the current subtitle of this action mode.\r
+     * @return Subtitle text\r
+     */\r
+    public abstract CharSequence getSubtitle();\r
+\r
+    /**\r
+     * Returns the current custom view for this action mode.\r
+     * @return The current custom view\r
+     */\r
+    public abstract View getCustomView();\r
+\r
+    /**\r
+     * Returns a {@link MenuInflater} with the ActionMode's context.\r
+     */\r
+    public abstract MenuInflater getMenuInflater();\r
+\r
+    /**\r
+     * Returns whether the UI presenting this action mode can take focus or not.\r
+     * This is used by internal components within the framework that would otherwise\r
+     * present an action mode UI that requires focus, such as an EditText as a custom view.\r
+     *\r
+     * @return true if the UI used to show this action mode can take focus\r
+     * @hide Internal use only\r
+     */\r
+    public boolean isUiFocusable() {\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * Callback interface for action modes. Supplied to\r
+     * {@link View#startActionMode(Callback)}, a Callback\r
+     * configures and handles events raised by a user's interaction with an action mode.\r
+     *\r
+     * <p>An action mode's lifecycle is as follows:\r
+     * <ul>\r
+     * <li>{@link Callback#onCreateActionMode(ActionMode, Menu)} once on initial\r
+     * creation</li>\r
+     * <li>{@link Callback#onPrepareActionMode(ActionMode, Menu)} after creation\r
+     * and any time the {@link ActionMode} is invalidated</li>\r
+     * <li>{@link Callback#onActionItemClicked(ActionMode, MenuItem)} any time a\r
+     * contextual action button is clicked</li>\r
+     * <li>{@link Callback#onDestroyActionMode(ActionMode)} when the action mode\r
+     * is closed</li>\r
+     * </ul>\r
+     */\r
+    public interface Callback {\r
+        /**\r
+         * Called when action mode is first created. The menu supplied will be used to\r
+         * generate action buttons for the action mode.\r
+         *\r
+         * @param mode ActionMode being created\r
+         * @param menu Menu used to populate action buttons\r
+         * @return true if the action mode should be created, false if entering this\r
+         *              mode should be aborted.\r
+         */\r
+        public boolean onCreateActionMode(ActionMode mode, Menu menu);\r
+\r
+        /**\r
+         * Called to refresh an action mode's action menu whenever it is invalidated.\r
+         *\r
+         * @param mode ActionMode being prepared\r
+         * @param menu Menu used to populate action buttons\r
+         * @return true if the menu or action mode was updated, false otherwise.\r
+         */\r
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu);\r
+\r
+        /**\r
+         * Called to report a user click on an action button.\r
+         *\r
+         * @param mode The current ActionMode\r
+         * @param item The item that was clicked\r
+         * @return true if this callback handled the event, false if the standard MenuItem\r
+         *          invocation should continue.\r
+         */\r
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item);\r
+\r
+        /**\r
+         * Called when an action mode is about to be exited and destroyed.\r
+         *\r
+         * @param mode The current ActionMode being destroyed\r
+         */\r
+        public void onDestroyActionMode(ActionMode mode);\r
+    }\r
+}
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/ActionProvider.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/ActionProvider.java
new file mode 100644 (file)
index 0000000..ae7cb1f
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.view;
+
+import android.content.Context;
+import android.view.View;
+
+/**
+ * This class is a mediator for accomplishing a given task, for example sharing a file.
+ * It is responsible for creating a view that performs an action that accomplishes the task.
+ * This class also implements other functions such a performing a default action.
+ * <p>
+ * An ActionProvider can be optionally specified for a {@link MenuItem} and in such a
+ * case it will be responsible for creating the action view that appears in the
+ * {@link android.app.ActionBar} as a substitute for the menu item when the item is
+ * displayed as an action item. Also the provider is responsible for performing a
+ * default action if a menu item placed on the overflow menu of the ActionBar is
+ * selected and none of the menu item callbacks has handled the selection. For this
+ * case the provider can also optionally provide a sub-menu for accomplishing the
+ * task at hand.
+ * </p>
+ * <p>
+ * There are two ways for using an action provider for creating and handling of action views:
+ * <ul>
+ * <li>
+ * Setting the action provider on a {@link MenuItem} directly by calling
+ * {@link MenuItem#setActionProvider(ActionProvider)}.
+ * </li>
+ * <li>
+ * Declaring the action provider in the menu XML resource. For example:
+ * <pre>
+ * <code>
+ *   &lt;item android:id="@+id/my_menu_item"
+ *     android:title="Title"
+ *     android:icon="@drawable/my_menu_item_icon"
+ *     android:showAsAction="ifRoom"
+ *     android:actionProviderClass="foo.bar.SomeActionProvider" /&gt;
+ * </code>
+ * </pre>
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * @see MenuItem#setActionProvider(ActionProvider)
+ * @see MenuItem#getActionProvider()
+ */
+public abstract class ActionProvider {
+    private SubUiVisibilityListener mSubUiVisibilityListener;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context Context for accessing resources.
+     */
+    public ActionProvider(Context context) {
+    }
+
+    /**
+     * Factory method for creating new action views.
+     *
+     * @return A new action view.
+     */
+    public abstract View onCreateActionView();
+
+    /**
+     * Performs an optional default action.
+     * <p>
+     * For the case of an action provider placed in a menu item not shown as an action this
+     * method is invoked if previous callbacks for processing menu selection has handled
+     * the event.
+     * </p>
+     * <p>
+     * A menu item selection is processed in the following order:
+     * <ul>
+     * <li>
+     * Receiving a call to {@link MenuItem.OnMenuItemClickListener#onMenuItemClick
+     *  MenuItem.OnMenuItemClickListener.onMenuItemClick}.
+     * </li>
+     * <li>
+     * Receiving a call to {@link android.app.Activity#onOptionsItemSelected(MenuItem)
+     *  Activity.onOptionsItemSelected(MenuItem)}
+     * </li>
+     * <li>
+     * Receiving a call to {@link android.app.Fragment#onOptionsItemSelected(MenuItem)
+     *  Fragment.onOptionsItemSelected(MenuItem)}
+     * </li>
+     * <li>
+     * Launching the {@link android.content.Intent} set via
+     * {@link MenuItem#setIntent(android.content.Intent) MenuItem.setIntent(android.content.Intent)}
+     * </li>
+     * <li>
+     * Invoking this method.
+     * </li>
+     * </ul>
+     * </p>
+     * <p>
+     * The default implementation does not perform any action and returns false.
+     * </p>
+     */
+    public boolean onPerformDefaultAction() {
+        return false;
+    }
+
+    /**
+     * Determines if this ActionProvider has a submenu associated with it.
+     *
+     * <p>Associated submenus will be shown when an action view is not. This
+     * provider instance will receive a call to {@link #onPrepareSubMenu(SubMenu)}
+     * after the call to {@link #onPerformDefaultAction()} and before a submenu is
+     * displayed to the user.
+     *
+     * @return true if the item backed by this provider should have an associated submenu
+     */
+    public boolean hasSubMenu() {
+        return false;
+    }
+
+    /**
+     * Called to prepare an associated submenu for the menu item backed by this ActionProvider.
+     *
+     * <p>if {@link #hasSubMenu()} returns true, this method will be called when the
+     * menu item is selected to prepare the submenu for presentation to the user. Apps
+     * may use this to create or alter submenu content right before display.
+     *
+     * @param subMenu Submenu that will be displayed
+     */
+    public void onPrepareSubMenu(SubMenu subMenu) {
+    }
+
+    /**
+     * Notify the system that the visibility of an action view's sub-UI such as
+     * an anchored popup has changed. This will affect how other system
+     * visibility notifications occur.
+     *
+     * @hide Pending future API approval
+     */
+    public void subUiVisibilityChanged(boolean isVisible) {
+        if (mSubUiVisibilityListener != null) {
+            mSubUiVisibilityListener.onSubUiVisibilityChanged(isVisible);
+        }
+    }
+
+    /**
+     * @hide Internal use only
+     */
+    public void setSubUiVisibilityListener(SubUiVisibilityListener listener) {
+        mSubUiVisibilityListener = listener;
+    }
+
+    /**
+     * @hide Internal use only
+     */
+    public interface SubUiVisibilityListener {
+        public void onSubUiVisibilityChanged(boolean isVisible);
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/CollapsibleActionView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/CollapsibleActionView.java
new file mode 100644 (file)
index 0000000..43281b0
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.view;
+
+/**
+ * When a {@link View} implements this interface it will receive callbacks
+ * when expanded or collapsed as an action view alongside the optional,
+ * app-specified callbacks to {@link OnActionExpandListener}.
+ *
+ * <p>See {@link MenuItem} for more information about action views.
+ * See {@link android.app.ActionBar} for more information about the action bar.
+ */
+public interface CollapsibleActionView {
+    /**
+     * Called when this view is expanded as an action view.
+     * See {@link MenuItem#expandActionView()}.
+     */
+    public void onActionViewExpanded();
+
+    /**
+     * Called when this view is collapsed as an action view.
+     * See {@link MenuItem#collapseActionView()}.
+     */
+    public void onActionViewCollapsed();
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/Menu.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/Menu.java
new file mode 100644 (file)
index 0000000..951f4cc
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.view;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.view.KeyEvent;
+
+/**
+ * Interface for managing the items in a menu.
+ * <p>
+ * By default, every Activity supports an options menu of actions or options.
+ * You can add items to this menu and handle clicks on your additions. The
+ * easiest way of adding menu items is inflating an XML file into the
+ * {@link Menu} via {@link MenuInflater}. The easiest way of attaching code to
+ * clicks is via {@link Activity#onOptionsItemSelected(MenuItem)} and
+ * {@link Activity#onContextItemSelected(MenuItem)}.
+ * <p>
+ * Different menu types support different features:
+ * <ol>
+ * <li><b>Context menus</b>: Do not support item shortcuts and item icons.
+ * <li><b>Options menus</b>: The <b>icon menus</b> do not support item check
+ * marks and only show the item's
+ * {@link MenuItem#setTitleCondensed(CharSequence) condensed title}. The
+ * <b>expanded menus</b> (only available if six or more menu items are visible,
+ * reached via the 'More' item in the icon menu) do not show item icons, and
+ * item check marks are discouraged.
+ * <li><b>Sub menus</b>: Do not support item icons, or nested sub menus.
+ * </ol>
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For more information about creating menus, read the
+ * <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
+ * </div>
+ */
+public interface Menu {
+
+    /**
+     * This is the part of an order integer that the user can provide.
+     * @hide
+     */
+    static final int USER_MASK = 0x0000ffff;
+    /**
+     * Bit shift of the user portion of the order integer.
+     * @hide
+     */
+    static final int USER_SHIFT = 0;
+
+    /**
+     * This is the part of an order integer that supplies the category of the
+     * item.
+     * @hide
+     */
+    static final int CATEGORY_MASK = 0xffff0000;
+    /**
+     * Bit shift of the category portion of the order integer.
+     * @hide
+     */
+    static final int CATEGORY_SHIFT = 16;
+
+    /**
+     * Value to use for group and item identifier integers when you don't care
+     * about them.
+     */
+    static final int NONE = 0;
+
+    /**
+     * First value for group and item identifier integers.
+     */
+    static final int FIRST = 1;
+
+    // Implementation note: Keep these CATEGORY_* in sync with the category enum
+    // in attrs.xml
+
+    /**
+     * Category code for the order integer for items/groups that are part of a
+     * container -- or/add this with your base value.
+     */
+    static final int CATEGORY_CONTAINER = 0x00010000;
+
+    /**
+     * Category code for the order integer for items/groups that are provided by
+     * the system -- or/add this with your base value.
+     */
+    static final int CATEGORY_SYSTEM = 0x00020000;
+
+    /**
+     * Category code for the order integer for items/groups that are
+     * user-supplied secondary (infrequently used) options -- or/add this with
+     * your base value.
+     */
+    static final int CATEGORY_SECONDARY = 0x00030000;
+
+    /**
+     * Category code for the order integer for items/groups that are
+     * alternative actions on the data that is currently displayed -- or/add
+     * this with your base value.
+     */
+    static final int CATEGORY_ALTERNATIVE = 0x00040000;
+
+    /**
+     * Flag for {@link #addIntentOptions}: if set, do not automatically remove
+     * any existing menu items in the same group.
+     */
+    static final int FLAG_APPEND_TO_GROUP = 0x0001;
+
+    /**
+     * Flag for {@link #performShortcut}: if set, do not close the menu after
+     * executing the shortcut.
+     */
+    static final int FLAG_PERFORM_NO_CLOSE = 0x0001;
+
+    /**
+     * Flag for {@link #performShortcut(int, KeyEvent, int)}: if set, always
+     * close the menu after executing the shortcut. Closing the menu also resets
+     * the prepared state.
+     */
+    static final int FLAG_ALWAYS_PERFORM_CLOSE = 0x0002;
+
+    /**
+     * Add a new item to the menu. This item displays the given title for its
+     * label.
+     *
+     * @param title The text to display for the item.
+     * @return The newly added menu item.
+     */
+    public MenuItem add(CharSequence title);
+
+    /**
+     * Add a new item to the menu. This item displays the given title for its
+     * label.
+     *
+     * @param titleRes Resource identifier of title string.
+     * @return The newly added menu item.
+     */
+    public MenuItem add(int titleRes);
+
+    /**
+     * Add a new item to the menu. This item displays the given title for its
+     * label.
+     *
+     * @param groupId The group identifier that this item should be part of.
+     *        This can be used to define groups of items for batch state
+     *        changes. Normally use {@link #NONE} if an item should not be in a
+     *        group.
+     * @param itemId Unique item ID. Use {@link #NONE} if you do not need a
+     *        unique ID.
+     * @param order The order for the item. Use {@link #NONE} if you do not care
+     *        about the order. See {@link MenuItem#getOrder()}.
+     * @param title The text to display for the item.
+     * @return The newly added menu item.
+     */
+    public MenuItem add(int groupId, int itemId, int order, CharSequence title);
+
+    /**
+     * Variation on {@link #add(int, int, int, CharSequence)} that takes a
+     * string resource identifier instead of the string itself.
+     *
+     * @param groupId The group identifier that this item should be part of.
+     *        This can also be used to define groups of items for batch state
+     *        changes. Normally use {@link #NONE} if an item should not be in a
+     *        group.
+     * @param itemId Unique item ID. Use {@link #NONE} if you do not need a
+     *        unique ID.
+     * @param order The order for the item. Use {@link #NONE} if you do not care
+     *        about the order. See {@link MenuItem#getOrder()}.
+     * @param titleRes Resource identifier of title string.
+     * @return The newly added menu item.
+     */
+    public MenuItem add(int groupId, int itemId, int order, int titleRes);
+
+    /**
+     * Add a new sub-menu to the menu. This item displays the given title for
+     * its label. To modify other attributes on the submenu's menu item, use
+     * {@link SubMenu#getItem()}.
+     *
+     * @param title The text to display for the item.
+     * @return The newly added sub-menu
+     */
+    SubMenu addSubMenu(final CharSequence title);
+
+    /**
+     * Add a new sub-menu to the menu. This item displays the given title for
+     * its label. To modify other attributes on the submenu's menu item, use
+     * {@link SubMenu#getItem()}.
+     *
+     * @param titleRes Resource identifier of title string.
+     * @return The newly added sub-menu
+     */
+    SubMenu addSubMenu(final int titleRes);
+
+    /**
+     * Add a new sub-menu to the menu. This item displays the given
+     * <var>title</var> for its label. To modify other attributes on the
+     * submenu's menu item, use {@link SubMenu#getItem()}.
+     *<p>
+     * Note that you can only have one level of sub-menus, i.e. you cannnot add
+     * a subMenu to a subMenu: An {@link UnsupportedOperationException} will be
+     * thrown if you try.
+     *
+     * @param groupId The group identifier that this item should be part of.
+     *        This can also be used to define groups of items for batch state
+     *        changes. Normally use {@link #NONE} if an item should not be in a
+     *        group.
+     * @param itemId Unique item ID. Use {@link #NONE} if you do not need a
+     *        unique ID.
+     * @param order The order for the item. Use {@link #NONE} if you do not care
+     *        about the order. See {@link MenuItem#getOrder()}.
+     * @param title The text to display for the item.
+     * @return The newly added sub-menu
+     */
+    SubMenu addSubMenu(final int groupId, final int itemId, int order, final CharSequence title);
+
+    /**
+     * Variation on {@link #addSubMenu(int, int, int, CharSequence)} that takes
+     * a string resource identifier for the title instead of the string itself.
+     *
+     * @param groupId The group identifier that this item should be part of.
+     *        This can also be used to define groups of items for batch state
+     *        changes. Normally use {@link #NONE} if an item should not be in a group.
+     * @param itemId Unique item ID. Use {@link #NONE} if you do not need a unique ID.
+     * @param order The order for the item. Use {@link #NONE} if you do not care about the
+     *        order. See {@link MenuItem#getOrder()}.
+     * @param titleRes Resource identifier of title string.
+     * @return The newly added sub-menu
+     */
+    SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes);
+
+    /**
+     * Add a group of menu items corresponding to actions that can be performed
+     * for a particular Intent. The Intent is most often configured with a null
+     * action, the data that the current activity is working with, and includes
+     * either the {@link Intent#CATEGORY_ALTERNATIVE} or
+     * {@link Intent#CATEGORY_SELECTED_ALTERNATIVE} to find activities that have
+     * said they would like to be included as optional action. You can, however,
+     * use any Intent you want.
+     *
+     * <p>
+     * See {@link android.content.pm.PackageManager#queryIntentActivityOptions}
+     * for more * details on the <var>caller</var>, <var>specifics</var>, and
+     * <var>intent</var> arguments. The list returned by that function is used
+     * to populate the resulting menu items.
+     *
+     * <p>
+     * All of the menu items of possible options for the intent will be added
+     * with the given group and id. You can use the group to control ordering of
+     * the items in relation to other items in the menu. Normally this function
+     * will automatically remove any existing items in the menu in the same
+     * group and place a divider above and below the added items; this behavior
+     * can be modified with the <var>flags</var> parameter. For each of the
+     * generated items {@link MenuItem#setIntent} is called to associate the
+     * appropriate Intent with the item; this means the activity will
+     * automatically be started for you without having to do anything else.
+     *
+     * @param groupId The group identifier that the items should be part of.
+     *        This can also be used to define groups of items for batch state
+     *        changes. Normally use {@link #NONE} if the items should not be in
+     *        a group.
+     * @param itemId Unique item ID. Use {@link #NONE} if you do not need a
+     *        unique ID.
+     * @param order The order for the items. Use {@link #NONE} if you do not
+     *        care about the order. See {@link MenuItem#getOrder()}.
+     * @param caller The current activity component name as defined by
+     *        queryIntentActivityOptions().
+     * @param specifics Specific items to place first as defined by
+     *        queryIntentActivityOptions().
+     * @param intent Intent describing the kinds of items to populate in the
+     *        list as defined by queryIntentActivityOptions().
+     * @param flags Additional options controlling how the items are added.
+     * @param outSpecificItems Optional array in which to place the menu items
+     *        that were generated for each of the <var>specifics</var> that were
+     *        requested. Entries may be null if no activity was found for that
+     *        specific action.
+     * @return The number of menu items that were added.
+     *
+     * @see #FLAG_APPEND_TO_GROUP
+     * @see MenuItem#setIntent
+     * @see android.content.pm.PackageManager#queryIntentActivityOptions
+     */
+    public int addIntentOptions(int groupId, int itemId, int order,
+                                ComponentName caller, Intent[] specifics,
+                                Intent intent, int flags, MenuItem[] outSpecificItems);
+
+    /**
+     * Remove the item with the given identifier.
+     *
+     * @param id The item to be removed.  If there is no item with this
+     *           identifier, nothing happens.
+     */
+    public void removeItem(int id);
+
+    /**
+     * Remove all items in the given group.
+     *
+     * @param groupId The group to be removed.  If there are no items in this
+     *           group, nothing happens.
+     */
+    public void removeGroup(int groupId);
+
+    /**
+     * Remove all existing items from the menu, leaving it empty as if it had
+     * just been created.
+     */
+    public void clear();
+
+    /**
+     * Control whether a particular group of items can show a check mark.  This
+     * is similar to calling {@link MenuItem#setCheckable} on all of the menu items
+     * with the given group identifier, but in addition you can control whether
+     * this group contains a mutually-exclusive set items.  This should be called
+     * after the items of the group have been added to the menu.
+     *
+     * @param group The group of items to operate on.
+     * @param checkable Set to true to allow a check mark, false to
+     *                  disallow.  The default is false.
+     * @param exclusive If set to true, only one item in this group can be
+     *                  checked at a time; checking an item will automatically
+     *                  uncheck all others in the group.  If set to false, each
+     *                  item can be checked independently of the others.
+     *
+     * @see MenuItem#setCheckable
+     * @see MenuItem#setChecked
+     */
+    public void setGroupCheckable(int group, boolean checkable, boolean exclusive);
+
+    /**
+     * Show or hide all menu items that are in the given group.
+     *
+     * @param group The group of items to operate on.
+     * @param visible If true the items are visible, else they are hidden.
+     *
+     * @see MenuItem#setVisible
+     */
+    public void setGroupVisible(int group, boolean visible);
+
+    /**
+     * Enable or disable all menu items that are in the given group.
+     *
+     * @param group The group of items to operate on.
+     * @param enabled If true the items will be enabled, else they will be disabled.
+     *
+     * @see MenuItem#setEnabled
+     */
+    public void setGroupEnabled(int group, boolean enabled);
+
+    /**
+     * Return whether the menu currently has item items that are visible.
+     *
+     * @return True if there is one or more item visible,
+     *         else false.
+     */
+    public boolean hasVisibleItems();
+
+    /**
+     * Return the menu item with a particular identifier.
+     *
+     * @param id The identifier to find.
+     *
+     * @return The menu item object, or null if there is no item with
+     *         this identifier.
+     */
+    public MenuItem findItem(int id);
+
+    /**
+     * Get the number of items in the menu.  Note that this will change any
+     * times items are added or removed from the menu.
+     *
+     * @return The item count.
+     */
+    public int size();
+
+    /**
+     * Gets the menu item at the given index.
+     *
+     * @param index The index of the menu item to return.
+     * @return The menu item.
+     * @exception IndexOutOfBoundsException
+     *                when {@code index < 0 || >= size()}
+     */
+    public MenuItem getItem(int index);
+
+    /**
+     * Closes the menu, if open.
+     */
+    public void close();
+
+    /**
+     * Execute the menu item action associated with the given shortcut
+     * character.
+     *
+     * @param keyCode The keycode of the shortcut key.
+     * @param event Key event message.
+     * @param flags Additional option flags or 0.
+     *
+     * @return If the given shortcut exists and is shown, returns
+     *         true; else returns false.
+     *
+     * @see #FLAG_PERFORM_NO_CLOSE
+     */
+    public boolean performShortcut(int keyCode, KeyEvent event, int flags);
+
+    /**
+     * Is a keypress one of the defined shortcut keys for this window.
+     * @param keyCode the key code from {@link KeyEvent} to check.
+     * @param event the {@link KeyEvent} to use to help check.
+     */
+    boolean isShortcutKey(int keyCode, KeyEvent event);
+
+    /**
+     * Execute the menu item action associated with the given menu identifier.
+     *
+     * @param id Identifier associated with the menu item.
+     * @param flags Additional option flags or 0.
+     *
+     * @return If the given identifier exists and is shown, returns
+     *         true; else returns false.
+     *
+     * @see #FLAG_PERFORM_NO_CLOSE
+     */
+    public boolean performIdentifierAction(int id, int flags);
+
+
+    /**
+     * Control whether the menu should be running in qwerty mode (alphabetic
+     * shortcuts) or 12-key mode (numeric shortcuts).
+     *
+     * @param isQwerty If true the menu will use alphabetic shortcuts; else it
+     *                 will use numeric shortcuts.
+     */
+    public void setQwertyMode(boolean isQwerty);
+}
+
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/MenuInflater.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/MenuInflater.java
new file mode 100644 (file)
index 0000000..9694597
--- /dev/null
@@ -0,0 +1,472 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ *               2011 Jake Wharton\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.actionbarsherlock.view;\r
+\r
+import java.io.IOException;\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Method;\r
+import org.xmlpull.v1.XmlPullParser;\r
+import org.xmlpull.v1.XmlPullParserException;\r
+import android.content.Context;\r
+import android.content.res.TypedArray;\r
+import android.content.res.XmlResourceParser;\r
+import android.util.AttributeSet;\r
+import android.util.Log;\r
+import android.util.TypedValue;\r
+import android.util.Xml;\r
+import android.view.InflateException;\r
+import android.view.View;\r
+\r
+import com.actionbarsherlock.R;\r
+import com.actionbarsherlock.internal.view.menu.MenuItemImpl;\r
+\r
+/**\r
+ * This class is used to instantiate menu XML files into Menu objects.\r
+ * <p>\r
+ * For performance reasons, menu inflation relies heavily on pre-processing of\r
+ * XML files that is done at build time. Therefore, it is not currently possible\r
+ * to use MenuInflater with an XmlPullParser over a plain XML file at runtime;\r
+ * it only works with an XmlPullParser returned from a compiled resource (R.\r
+ * <em>something</em> file.)\r
+ */\r
+public class MenuInflater {\r
+    private static final String LOG_TAG = "MenuInflater";\r
+\r
+    /** Menu tag name in XML. */\r
+    private static final String XML_MENU = "menu";\r
+\r
+    /** Group tag name in XML. */\r
+    private static final String XML_GROUP = "group";\r
+\r
+    /** Item tag name in XML. */\r
+    private static final String XML_ITEM = "item";\r
+\r
+    private static final int NO_ID = 0;\r
+\r
+    private static final Class<?>[] ACTION_VIEW_CONSTRUCTOR_SIGNATURE = new Class[] {Context.class};\r
+\r
+    private static final Class<?>[] ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE = ACTION_VIEW_CONSTRUCTOR_SIGNATURE;\r
+\r
+    private final Object[] mActionViewConstructorArguments;\r
+\r
+    private final Object[] mActionProviderConstructorArguments;\r
+\r
+    private Context mContext;\r
+\r
+    /**\r
+     * Constructs a menu inflater.\r
+     *\r
+     * @see Activity#getMenuInflater()\r
+     */\r
+    public MenuInflater(Context context) {\r
+        mContext = context;\r
+        mActionViewConstructorArguments = new Object[] {context};\r
+        mActionProviderConstructorArguments = mActionViewConstructorArguments;\r
+    }\r
+\r
+    /**\r
+     * Inflate a menu hierarchy from the specified XML resource. Throws\r
+     * {@link InflateException} if there is an error.\r
+     *\r
+     * @param menuRes Resource ID for an XML layout resource to load (e.g.,\r
+     *            <code>R.menu.main_activity</code>)\r
+     * @param menu The Menu to inflate into. The items and submenus will be\r
+     *            added to this Menu.\r
+     */\r
+    public void inflate(int menuRes, Menu menu) {\r
+        XmlResourceParser parser = null;\r
+        try {\r
+            parser = mContext.getResources().getLayout(menuRes);\r
+            AttributeSet attrs = Xml.asAttributeSet(parser);\r
+\r
+            parseMenu(parser, attrs, menu);\r
+        } catch (XmlPullParserException e) {\r
+            throw new InflateException("Error inflating menu XML", e);\r
+        } catch (IOException e) {\r
+            throw new InflateException("Error inflating menu XML", e);\r
+        } finally {\r
+            if (parser != null) parser.close();\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Called internally to fill the given menu. If a sub menu is seen, it will\r
+     * call this recursively.\r
+     */\r
+    private void parseMenu(XmlPullParser parser, AttributeSet attrs, Menu menu)\r
+            throws XmlPullParserException, IOException {\r
+        MenuState menuState = new MenuState(menu);\r
+\r
+        int eventType = parser.getEventType();\r
+        String tagName;\r
+        boolean lookingForEndOfUnknownTag = false;\r
+        String unknownTagName = null;\r
+\r
+        // This loop will skip to the menu start tag\r
+        do {\r
+            if (eventType == XmlPullParser.START_TAG) {\r
+                tagName = parser.getName();\r
+                if (tagName.equals(XML_MENU)) {\r
+                    // Go to next tag\r
+                    eventType = parser.next();\r
+                    break;\r
+                }\r
+\r
+                throw new RuntimeException("Expecting menu, got " + tagName);\r
+            }\r
+            eventType = parser.next();\r
+        } while (eventType != XmlPullParser.END_DOCUMENT);\r
+\r
+        boolean reachedEndOfMenu = false;\r
+        while (!reachedEndOfMenu) {\r
+            switch (eventType) {\r
+                case XmlPullParser.START_TAG:\r
+                    if (lookingForEndOfUnknownTag) {\r
+                        break;\r
+                    }\r
+\r
+                    tagName = parser.getName();\r
+                    if (tagName.equals(XML_GROUP)) {\r
+                        menuState.readGroup(attrs);\r
+                    } else if (tagName.equals(XML_ITEM)) {\r
+                        menuState.readItem(attrs);\r
+                    } else if (tagName.equals(XML_MENU)) {\r
+                        // A menu start tag denotes a submenu for an item\r
+                        SubMenu subMenu = menuState.addSubMenuItem();\r
+\r
+                        // Parse the submenu into returned SubMenu\r
+                        parseMenu(parser, attrs, subMenu);\r
+                    } else {\r
+                        lookingForEndOfUnknownTag = true;\r
+                        unknownTagName = tagName;\r
+                    }\r
+                    break;\r
+\r
+                case XmlPullParser.END_TAG:\r
+                    tagName = parser.getName();\r
+                    if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {\r
+                        lookingForEndOfUnknownTag = false;\r
+                        unknownTagName = null;\r
+                    } else if (tagName.equals(XML_GROUP)) {\r
+                        menuState.resetGroup();\r
+                    } else if (tagName.equals(XML_ITEM)) {\r
+                        // Add the item if it hasn't been added (if the item was\r
+                        // a submenu, it would have been added already)\r
+                        if (!menuState.hasAddedItem()) {\r
+                            if (menuState.itemActionProvider != null &&\r
+                                    menuState.itemActionProvider.hasSubMenu()) {\r
+                                menuState.addSubMenuItem();\r
+                            } else {\r
+                                menuState.addItem();\r
+                            }\r
+                        }\r
+                    } else if (tagName.equals(XML_MENU)) {\r
+                        reachedEndOfMenu = true;\r
+                    }\r
+                    break;\r
+\r
+                case XmlPullParser.END_DOCUMENT:\r
+                    throw new RuntimeException("Unexpected end of document");\r
+            }\r
+\r
+            eventType = parser.next();\r
+        }\r
+    }\r
+\r
+    private static class InflatedOnMenuItemClickListener\r
+            implements MenuItem.OnMenuItemClickListener {\r
+        private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };\r
+\r
+        private Context mContext;\r
+        private Method mMethod;\r
+\r
+        public InflatedOnMenuItemClickListener(Context context, String methodName) {\r
+            mContext = context;\r
+            Class<?> c = context.getClass();\r
+            try {\r
+                mMethod = c.getMethod(methodName, PARAM_TYPES);\r
+            } catch (Exception e) {\r
+                InflateException ex = new InflateException(\r
+                        "Couldn't resolve menu item onClick handler " + methodName +\r
+                        " in class " + c.getName());\r
+                ex.initCause(e);\r
+                throw ex;\r
+            }\r
+        }\r
+\r
+        public boolean onMenuItemClick(MenuItem item) {\r
+            try {\r
+                if (mMethod.getReturnType() == Boolean.TYPE) {\r
+                    return (Boolean) mMethod.invoke(mContext, item);\r
+                } else {\r
+                    mMethod.invoke(mContext, item);\r
+                    return true;\r
+                }\r
+            } catch (Exception e) {\r
+                throw new RuntimeException(e);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * State for the current menu.\r
+     * <p>\r
+     * Groups can not be nested unless there is another menu (which will have\r
+     * its state class).\r
+     */\r
+    private class MenuState {\r
+        private Menu menu;\r
+\r
+        /*\r
+         * Group state is set on items as they are added, allowing an item to\r
+         * override its group state. (As opposed to set on items at the group end tag.)\r
+         */\r
+        private int groupId;\r
+        private int groupCategory;\r
+        private int groupOrder;\r
+        private int groupCheckable;\r
+        private boolean groupVisible;\r
+        private boolean groupEnabled;\r
+\r
+        private boolean itemAdded;\r
+        private int itemId;\r
+        private int itemCategoryOrder;\r
+        private CharSequence itemTitle;\r
+        private CharSequence itemTitleCondensed;\r
+        private int itemIconResId;\r
+        private char itemAlphabeticShortcut;\r
+        private char itemNumericShortcut;\r
+        /**\r
+         * Sync to attrs.xml enum:\r
+         * - 0: none\r
+         * - 1: all\r
+         * - 2: exclusive\r
+         */\r
+        private int itemCheckable;\r
+        private boolean itemChecked;\r
+        private boolean itemVisible;\r
+        private boolean itemEnabled;\r
+\r
+        /**\r
+         * Sync to attrs.xml enum, values in MenuItem:\r
+         * - 0: never\r
+         * - 1: ifRoom\r
+         * - 2: always\r
+         * - -1: Safe sentinel for "no value".\r
+         */\r
+        private int itemShowAsAction;\r
+\r
+        private int itemActionViewLayout;\r
+        private String itemActionViewClassName;\r
+        private String itemActionProviderClassName;\r
+\r
+        private String itemListenerMethodName;\r
+\r
+        private ActionProvider itemActionProvider;\r
+\r
+        private static final int defaultGroupId = NO_ID;\r
+        private static final int defaultItemId = NO_ID;\r
+        private static final int defaultItemCategory = 0;\r
+        private static final int defaultItemOrder = 0;\r
+        private static final int defaultItemCheckable = 0;\r
+        private static final boolean defaultItemChecked = false;\r
+        private static final boolean defaultItemVisible = true;\r
+        private static final boolean defaultItemEnabled = true;\r
+\r
+        public MenuState(final Menu menu) {\r
+            this.menu = menu;\r
+\r
+            resetGroup();\r
+        }\r
+\r
+        public void resetGroup() {\r
+            groupId = defaultGroupId;\r
+            groupCategory = defaultItemCategory;\r
+            groupOrder = defaultItemOrder;\r
+            groupCheckable = defaultItemCheckable;\r
+            groupVisible = defaultItemVisible;\r
+            groupEnabled = defaultItemEnabled;\r
+        }\r
+\r
+        /**\r
+         * Called when the parser is pointing to a group tag.\r
+         */\r
+        public void readGroup(AttributeSet attrs) {\r
+            TypedArray a = mContext.obtainStyledAttributes(attrs,\r
+                    R.styleable.SherlockMenuGroup);\r
+\r
+            groupId = a.getResourceId(R.styleable.SherlockMenuGroup_android_id, defaultGroupId);\r
+            groupCategory = a.getInt(R.styleable.SherlockMenuGroup_android_menuCategory, defaultItemCategory);\r
+            groupOrder = a.getInt(R.styleable.SherlockMenuGroup_android_orderInCategory, defaultItemOrder);\r
+            groupCheckable = a.getInt(R.styleable.SherlockMenuGroup_android_checkableBehavior, defaultItemCheckable);\r
+            groupVisible = a.getBoolean(R.styleable.SherlockMenuGroup_android_visible, defaultItemVisible);\r
+            groupEnabled = a.getBoolean(R.styleable.SherlockMenuGroup_android_enabled, defaultItemEnabled);\r
+\r
+            a.recycle();\r
+        }\r
+\r
+        /**\r
+         * Called when the parser is pointing to an item tag.\r
+         */\r
+        public void readItem(AttributeSet attrs) {\r
+            TypedArray a = mContext.obtainStyledAttributes(attrs,\r
+                    R.styleable.SherlockMenuItem);\r
+\r
+            // Inherit attributes from the group as default value\r
+            itemId = a.getResourceId(R.styleable.SherlockMenuItem_android_id, defaultItemId);\r
+            final int category = a.getInt(R.styleable.SherlockMenuItem_android_menuCategory, groupCategory);\r
+            final int order = a.getInt(R.styleable.SherlockMenuItem_android_orderInCategory, groupOrder);\r
+            itemCategoryOrder = (category & Menu.CATEGORY_MASK) | (order & Menu.USER_MASK);\r
+            itemTitle = a.getText(R.styleable.SherlockMenuItem_android_title);\r
+            itemTitleCondensed = a.getText(R.styleable.SherlockMenuItem_android_titleCondensed);\r
+            itemIconResId = a.getResourceId(R.styleable.SherlockMenuItem_android_icon, 0);\r
+            itemAlphabeticShortcut =\r
+                    getShortcut(a.getString(R.styleable.SherlockMenuItem_android_alphabeticShortcut));\r
+            itemNumericShortcut =\r
+                    getShortcut(a.getString(R.styleable.SherlockMenuItem_android_numericShortcut));\r
+            if (a.hasValue(R.styleable.SherlockMenuItem_android_checkable)) {\r
+                // Item has attribute checkable, use it\r
+                itemCheckable = a.getBoolean(R.styleable.SherlockMenuItem_android_checkable, false) ? 1 : 0;\r
+            } else {\r
+                // Item does not have attribute, use the group's (group can have one more state\r
+                // for checkable that represents the exclusive checkable)\r
+                itemCheckable = groupCheckable;\r
+            }\r
+\r
+            itemChecked = a.getBoolean(R.styleable.SherlockMenuItem_android_checked, defaultItemChecked);\r
+            itemVisible = a.getBoolean(R.styleable.SherlockMenuItem_android_visible, groupVisible);\r
+            itemEnabled = a.getBoolean(R.styleable.SherlockMenuItem_android_enabled, groupEnabled);\r
+\r
+            TypedValue value = new TypedValue();\r
+            a.getValue(R.styleable.SherlockMenuItem_android_showAsAction, value);\r
+            itemShowAsAction = value.type == TypedValue.TYPE_INT_HEX ? value.data : -1;\r
+\r
+            itemListenerMethodName = a.getString(R.styleable.SherlockMenuItem_android_onClick);\r
+            itemActionViewLayout = a.getResourceId(R.styleable.SherlockMenuItem_android_actionLayout, 0);\r
+            itemActionViewClassName = a.getString(R.styleable.SherlockMenuItem_android_actionViewClass);\r
+            itemActionProviderClassName = a.getString(R.styleable.SherlockMenuItem_android_actionProviderClass);\r
+\r
+            final boolean hasActionProvider = itemActionProviderClassName != null;\r
+            if (hasActionProvider && itemActionViewLayout == 0 && itemActionViewClassName == null) {\r
+                itemActionProvider = newInstance(itemActionProviderClassName,\r
+                            ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE,\r
+                            mActionProviderConstructorArguments);\r
+            } else {\r
+                if (hasActionProvider) {\r
+                    Log.w(LOG_TAG, "Ignoring attribute 'actionProviderClass'."\r
+                            + " Action view already specified.");\r
+                }\r
+                itemActionProvider = null;\r
+            }\r
+\r
+            a.recycle();\r
+\r
+            itemAdded = false;\r
+        }\r
+\r
+        private char getShortcut(String shortcutString) {\r
+            if (shortcutString == null) {\r
+                return 0;\r
+            } else {\r
+                return shortcutString.charAt(0);\r
+            }\r
+        }\r
+\r
+        private void setItem(MenuItem item) {\r
+            item.setChecked(itemChecked)\r
+                .setVisible(itemVisible)\r
+                .setEnabled(itemEnabled)\r
+                .setCheckable(itemCheckable >= 1)\r
+                .setTitleCondensed(itemTitleCondensed)\r
+                .setIcon(itemIconResId)\r
+                .setAlphabeticShortcut(itemAlphabeticShortcut)\r
+                .setNumericShortcut(itemNumericShortcut);\r
+\r
+            if (itemShowAsAction >= 0) {\r
+                item.setShowAsAction(itemShowAsAction);\r
+            }\r
+\r
+            if (itemListenerMethodName != null) {\r
+                if (mContext.isRestricted()) {\r
+                    throw new IllegalStateException("The android:onClick attribute cannot "\r
+                            + "be used within a restricted context");\r
+                }\r
+                item.setOnMenuItemClickListener(\r
+                        new InflatedOnMenuItemClickListener(mContext, itemListenerMethodName));\r
+            }\r
+\r
+            if (itemCheckable >= 2) {\r
+                if (item instanceof MenuItemImpl) {\r
+                    MenuItemImpl impl = (MenuItemImpl) item;\r
+                    impl.setExclusiveCheckable(true);\r
+                } else {\r
+                    menu.setGroupCheckable(groupId, true, true);\r
+                }\r
+            }\r
+\r
+            boolean actionViewSpecified = false;\r
+            if (itemActionViewClassName != null) {\r
+                View actionView = (View) newInstance(itemActionViewClassName,\r
+                        ACTION_VIEW_CONSTRUCTOR_SIGNATURE, mActionViewConstructorArguments);\r
+                item.setActionView(actionView);\r
+                actionViewSpecified = true;\r
+            }\r
+            if (itemActionViewLayout > 0) {\r
+                if (!actionViewSpecified) {\r
+                    item.setActionView(itemActionViewLayout);\r
+                    actionViewSpecified = true;\r
+                } else {\r
+                    Log.w(LOG_TAG, "Ignoring attribute 'itemActionViewLayout'."\r
+                            + " Action view already specified.");\r
+                }\r
+            }\r
+            if (itemActionProvider != null) {\r
+                item.setActionProvider(itemActionProvider);\r
+            }\r
+        }\r
+\r
+        public void addItem() {\r
+            itemAdded = true;\r
+            setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle));\r
+        }\r
+\r
+        public SubMenu addSubMenuItem() {\r
+            itemAdded = true;\r
+            SubMenu subMenu = menu.addSubMenu(groupId, itemId, itemCategoryOrder, itemTitle);\r
+            setItem(subMenu.getItem());\r
+            return subMenu;\r
+        }\r
+\r
+        public boolean hasAddedItem() {\r
+            return itemAdded;\r
+        }\r
+\r
+        @SuppressWarnings("unchecked")\r
+        private <T> T newInstance(String className, Class<?>[] constructorSignature,\r
+                Object[] arguments) {\r
+            try {\r
+                Class<?> clazz = mContext.getClassLoader().loadClass(className);\r
+                Constructor<?> constructor = clazz.getConstructor(constructorSignature);\r
+                return (T) constructor.newInstance(arguments);\r
+            } catch (Exception e) {\r
+                Log.w(LOG_TAG, "Cannot instantiate class: " + className, e);\r
+            }\r
+            return null;\r
+        }\r
+    }\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/MenuItem.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/MenuItem.java
new file mode 100644 (file)
index 0000000..7fc3aa4
--- /dev/null
@@ -0,0 +1,598 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.view;
+
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View;
+
+/**
+ * Interface for direct access to a previously created menu item.
+ * <p>
+ * An Item is returned by calling one of the {@link android.view.Menu#add}
+ * methods.
+ * <p>
+ * For a feature set of specific menu types, see {@link Menu}.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about creating menus, read the
+ * <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
+ * </div>
+ */
+public interface MenuItem {
+    /*
+     * These should be kept in sync with attrs.xml enum constants for showAsAction
+     */
+    /** Never show this item as a button in an Action Bar. */
+    public static final int SHOW_AS_ACTION_NEVER = android.view.MenuItem.SHOW_AS_ACTION_NEVER;
+    /** Show this item as a button in an Action Bar if the system decides there is room for it. */
+    public static final int SHOW_AS_ACTION_IF_ROOM = android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM;
+    /**
+     * Always show this item as a button in an Action Bar.
+     * Use sparingly! If too many items are set to always show in the Action Bar it can
+     * crowd the Action Bar and degrade the user experience on devices with smaller screens.
+     * A good rule of thumb is to have no more than 2 items set to always show at a time.
+     */
+    public static final int SHOW_AS_ACTION_ALWAYS = android.view.MenuItem.SHOW_AS_ACTION_ALWAYS;
+
+    /**
+     * When this item is in the action bar, always show it with a text label even if
+     * it also has an icon specified.
+     */
+    public static final int SHOW_AS_ACTION_WITH_TEXT = android.view.MenuItem.SHOW_AS_ACTION_WITH_TEXT;
+
+    /**
+     * This item's action view collapses to a normal menu item.
+     * When expanded, the action view temporarily takes over
+     * a larger segment of its container.
+     */
+    public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = android.view.MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW;
+
+    /**
+     * Interface definition for a callback to be invoked when a menu item is
+     * clicked.
+     *
+     * @see Activity#onContextItemSelected(MenuItem)
+     * @see Activity#onOptionsItemSelected(MenuItem)
+     */
+    public interface OnMenuItemClickListener {
+        /**
+         * Called when a menu item has been invoked.  This is the first code
+         * that is executed; if it returns true, no other callbacks will be
+         * executed.
+         *
+         * @param item The menu item that was invoked.
+         *
+         * @return Return true to consume this click and prevent others from
+         *         executing.
+         */
+        public boolean onMenuItemClick(MenuItem item);
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when a menu item
+     * marked with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW} is
+     * expanded or collapsed.
+     *
+     * @see MenuItem#expandActionView()
+     * @see MenuItem#collapseActionView()
+     * @see MenuItem#setShowAsActionFlags(int)
+     */
+    public interface OnActionExpandListener {
+        /**
+         * Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}
+         * is expanded.
+         * @param item Item that was expanded
+         * @return true if the item should expand, false if expansion should be suppressed.
+         */
+        public boolean onMenuItemActionExpand(MenuItem item);
+
+        /**
+         * Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}
+         * is collapsed.
+         * @param item Item that was collapsed
+         * @return true if the item should collapse, false if collapsing should be suppressed.
+         */
+        public boolean onMenuItemActionCollapse(MenuItem item);
+    }
+
+    /**
+     * Return the identifier for this menu item.  The identifier can not
+     * be changed after the menu is created.
+     *
+     * @return The menu item's identifier.
+     */
+    public int getItemId();
+
+    /**
+     * Return the group identifier that this menu item is part of. The group
+     * identifier can not be changed after the menu is created.
+     *
+     * @return The menu item's group identifier.
+     */
+    public int getGroupId();
+
+    /**
+     * Return the category and order within the category of this item. This
+     * item will be shown before all items (within its category) that have
+     * order greater than this value.
+     * <p>
+     * An order integer contains the item's category (the upper bits of the
+     * integer; set by or/add the category with the order within the
+     * category) and the ordering of the item within that category (the
+     * lower bits). Example categories are {@link Menu#CATEGORY_SYSTEM},
+     * {@link Menu#CATEGORY_SECONDARY}, {@link Menu#CATEGORY_ALTERNATIVE},
+     * {@link Menu#CATEGORY_CONTAINER}. See {@link Menu} for a full list.
+     *
+     * @return The order of this item.
+     */
+    public int getOrder();
+
+    /**
+     * Change the title associated with this item.
+     *
+     * @param title The new text to be displayed.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setTitle(CharSequence title);
+
+    /**
+     * Change the title associated with this item.
+     * <p>
+     * Some menu types do not sufficient space to show the full title, and
+     * instead a condensed title is preferred. See {@link Menu} for more
+     * information.
+     *
+     * @param title The resource id of the new text to be displayed.
+     * @return This Item so additional setters can be called.
+     * @see #setTitleCondensed(CharSequence)
+     */
+
+    public MenuItem setTitle(int title);
+
+    /**
+     * Retrieve the current title of the item.
+     *
+     * @return The title.
+     */
+    public CharSequence getTitle();
+
+    /**
+     * Change the condensed title associated with this item. The condensed
+     * title is used in situations where the normal title may be too long to
+     * be displayed.
+     *
+     * @param title The new text to be displayed as the condensed title.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setTitleCondensed(CharSequence title);
+
+    /**
+     * Retrieve the current condensed title of the item. If a condensed
+     * title was never set, it will return the normal title.
+     *
+     * @return The condensed title, if it exists.
+     *         Otherwise the normal title.
+     */
+    public CharSequence getTitleCondensed();
+
+    /**
+     * Change the icon associated with this item. This icon will not always be
+     * shown, so the title should be sufficient in describing this item. See
+     * {@link Menu} for the menu types that support icons.
+     *
+     * @param icon The new icon (as a Drawable) to be displayed.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setIcon(Drawable icon);
+
+    /**
+     * Change the icon associated with this item. This icon will not always be
+     * shown, so the title should be sufficient in describing this item. See
+     * {@link Menu} for the menu types that support icons.
+     * <p>
+     * This method will set the resource ID of the icon which will be used to
+     * lazily get the Drawable when this item is being shown.
+     *
+     * @param iconRes The new icon (as a resource ID) to be displayed.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setIcon(int iconRes);
+
+    /**
+     * Returns the icon for this item as a Drawable (getting it from resources if it hasn't been
+     * loaded before).
+     *
+     * @return The icon as a Drawable.
+     */
+    public Drawable getIcon();
+
+    /**
+     * Change the Intent associated with this item.  By default there is no
+     * Intent associated with a menu item.  If you set one, and nothing
+     * else handles the item, then the default behavior will be to call
+     * {@link android.content.Context#startActivity} with the given Intent.
+     *
+     * <p>Note that setIntent() can not be used with the versions of
+     * {@link Menu#add} that take a Runnable, because {@link Runnable#run}
+     * does not return a value so there is no way to tell if it handled the
+     * item.  In this case it is assumed that the Runnable always handles
+     * the item, and the intent will never be started.
+     *
+     * @see #getIntent
+     * @param intent The Intent to associated with the item.  This Intent
+     *               object is <em>not</em> copied, so be careful not to
+     *               modify it later.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setIntent(Intent intent);
+
+    /**
+     * Return the Intent associated with this item.  This returns a
+     * reference to the Intent which you can change as desired to modify
+     * what the Item is holding.
+     *
+     * @see #setIntent
+     * @return Returns the last value supplied to {@link #setIntent}, or
+     *         null.
+     */
+    public Intent getIntent();
+
+    /**
+     * Change both the numeric and alphabetic shortcut associated with this
+     * item. Note that the shortcut will be triggered when the key that
+     * generates the given character is pressed alone or along with with the alt
+     * key. Also note that case is not significant and that alphabetic shortcut
+     * characters will be displayed in lower case.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key. This is the shortcut when
+     *        using a numeric (e.g., 12-key) keyboard.
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setShortcut(char numericChar, char alphaChar);
+
+    /**
+     * Change the numeric shortcut associated with this item.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param numericChar The numeric shortcut key.  This is the shortcut when
+     *                 using a 12-key (numeric) keyboard.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setNumericShortcut(char numericChar);
+
+    /**
+     * Return the char for this menu item's numeric (12-key) shortcut.
+     *
+     * @return Numeric character to use as a shortcut.
+     */
+    public char getNumericShortcut();
+
+    /**
+     * Change the alphabetic shortcut associated with this item. The shortcut
+     * will be triggered when the key that generates the given character is
+     * pressed alone or along with with the alt key. Case is not significant and
+     * shortcut characters will be displayed in lower case. Note that menu items
+     * with the characters '\b' or '\n' as shortcuts will get triggered by the
+     * Delete key or Carriage Return key, respectively.
+     * <p>
+     * See {@link Menu} for the menu types that support shortcuts.
+     *
+     * @param alphaChar The alphabetic shortcut key. This is the shortcut when
+     *        using a keyboard with alphabetic keys.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setAlphabeticShortcut(char alphaChar);
+
+    /**
+     * Return the char for this menu item's alphabetic shortcut.
+     *
+     * @return Alphabetic character to use as a shortcut.
+     */
+    public char getAlphabeticShortcut();
+
+    /**
+     * Control whether this item can display a check mark. Setting this does
+     * not actually display a check mark (see {@link #setChecked} for that);
+     * rather, it ensures there is room in the item in which to display a
+     * check mark.
+     * <p>
+     * See {@link Menu} for the menu types that support check marks.
+     *
+     * @param checkable Set to true to allow a check mark, false to
+     *            disallow. The default is false.
+     * @see #setChecked
+     * @see #isCheckable
+     * @see Menu#setGroupCheckable
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setCheckable(boolean checkable);
+
+    /**
+     * Return whether the item can currently display a check mark.
+     *
+     * @return If a check mark can be displayed, returns true.
+     *
+     * @see #setCheckable
+     */
+    public boolean isCheckable();
+
+    /**
+     * Control whether this item is shown with a check mark.  Note that you
+     * must first have enabled checking with {@link #setCheckable} or else
+     * the check mark will not appear.  If this item is a member of a group that contains
+     * mutually-exclusive items (set via {@link Menu#setGroupCheckable(int, boolean, boolean)},
+     * the other items in the group will be unchecked.
+     * <p>
+     * See {@link Menu} for the menu types that support check marks.
+     *
+     * @see #setCheckable
+     * @see #isChecked
+     * @see Menu#setGroupCheckable
+     * @param checked Set to true to display a check mark, false to hide
+     *                it.  The default value is false.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setChecked(boolean checked);
+
+    /**
+     * Return whether the item is currently displaying a check mark.
+     *
+     * @return If a check mark is displayed, returns true.
+     *
+     * @see #setChecked
+     */
+    public boolean isChecked();
+
+    /**
+     * Sets the visibility of the menu item. Even if a menu item is not visible,
+     * it may still be invoked via its shortcut (to completely disable an item,
+     * set it to invisible and {@link #setEnabled(boolean) disabled}).
+     *
+     * @param visible If true then the item will be visible; if false it is
+     *        hidden.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setVisible(boolean visible);
+
+    /**
+     * Return the visibility of the menu item.
+     *
+     * @return If true the item is visible; else it is hidden.
+     */
+    public boolean isVisible();
+
+    /**
+     * Sets whether the menu item is enabled. Disabling a menu item will not
+     * allow it to be invoked via its shortcut. The menu item will still be
+     * visible.
+     *
+     * @param enabled If true then the item will be invokable; if false it is
+     *        won't be invokable.
+     * @return This Item so additional setters can be called.
+     */
+    public MenuItem setEnabled(boolean enabled);
+
+    /**
+     * Return the enabled state of the menu item.
+     *
+     * @return If true the item is enabled and hence invokable; else it is not.
+     */
+    public boolean isEnabled();
+
+    /**
+     * Check whether this item has an associated sub-menu.  I.e. it is a
+     * sub-menu of another menu.
+     *
+     * @return If true this item has a menu; else it is a
+     *         normal item.
+     */
+    public boolean hasSubMenu();
+
+    /**
+     * Get the sub-menu to be invoked when this item is selected, if it has
+     * one. See {@link #hasSubMenu()}.
+     *
+     * @return The associated menu if there is one, else null
+     */
+    public SubMenu getSubMenu();
+
+    /**
+     * Set a custom listener for invocation of this menu item. In most
+     * situations, it is more efficient and easier to use
+     * {@link Activity#onOptionsItemSelected(MenuItem)} or
+     * {@link Activity#onContextItemSelected(MenuItem)}.
+     *
+     * @param menuItemClickListener The object to receive invokations.
+     * @return This Item so additional setters can be called.
+     * @see Activity#onOptionsItemSelected(MenuItem)
+     * @see Activity#onContextItemSelected(MenuItem)
+     */
+    public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener menuItemClickListener);
+
+    /**
+     * Gets the extra information linked to this menu item.  This extra
+     * information is set by the View that added this menu item to the
+     * menu.
+     *
+     * @see OnCreateContextMenuListener
+     * @return The extra information linked to the View that added this
+     *         menu item to the menu. This can be null.
+     */
+    public ContextMenuInfo getMenuInfo();
+
+    /**
+     * Sets how this item should display in the presence of an Action Bar.
+     * The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS},
+     * {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should
+     * be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}.
+     * SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action,
+     * it should be shown with a text label.
+     *
+     * @param actionEnum How the item should display. One of
+     * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or
+     * {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default.
+     *
+     * @see android.app.ActionBar
+     * @see #setActionView(View)
+     */
+    public void setShowAsAction(int actionEnum);
+
+    /**
+     * Sets how this item should display in the presence of an Action Bar.
+     * The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS},
+     * {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should
+     * be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}.
+     * SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action,
+     * it should be shown with a text label.
+     *
+     * <p>Note: This method differs from {@link #setShowAsAction(int)} only in that it
+     * returns the current MenuItem instance for call chaining.
+     *
+     * @param actionEnum How the item should display. One of
+     * {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or
+     * {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default.
+     *
+     * @see android.app.ActionBar
+     * @see #setActionView(View)
+     * @return This MenuItem instance for call chaining.
+     */
+    public MenuItem setShowAsActionFlags(int actionEnum);
+
+    /**
+     * Set an action view for this menu item. An action view will be displayed in place
+     * of an automatically generated menu item element in the UI when this item is shown
+     * as an action within a parent.
+     * <p>
+     *   <strong>Note:</strong> Setting an action view overrides the action provider
+     *           set via {@link #setActionProvider(ActionProvider)}.
+     * </p>
+     *
+     * @param view View to use for presenting this item to the user.
+     * @return This Item so additional setters can be called.
+     *
+     * @see #setShowAsAction(int)
+     */
+    public MenuItem setActionView(View view);
+
+    /**
+     * Set an action view for this menu item. An action view will be displayed in place
+     * of an automatically generated menu item element in the UI when this item is shown
+     * as an action within a parent.
+     * <p>
+     *   <strong>Note:</strong> Setting an action view overrides the action provider
+     *           set via {@link #setActionProvider(ActionProvider)}.
+     * </p>
+     *
+     * @param resId Layout resource to use for presenting this item to the user.
+     * @return This Item so additional setters can be called.
+     *
+     * @see #setShowAsAction(int)
+     */
+    public MenuItem setActionView(int resId);
+
+    /**
+     * Returns the currently set action view for this menu item.
+     *
+     * @return This item's action view
+     *
+     * @see #setActionView(View)
+     * @see #setShowAsAction(int)
+     */
+    public View getActionView();
+
+    /**
+     * Sets the {@link ActionProvider} responsible for creating an action view if
+     * the item is placed on the action bar. The provider also provides a default
+     * action invoked if the item is placed in the overflow menu.
+     * <p>
+     *   <strong>Note:</strong> Setting an action provider overrides the action view
+     *           set via {@link #setActionView(int)} or {@link #setActionView(View)}.
+     * </p>
+     *
+     * @param actionProvider The action provider.
+     * @return This Item so additional setters can be called.
+     *
+     * @see ActionProvider
+     */
+    public MenuItem setActionProvider(ActionProvider actionProvider);
+
+    /**
+     * Gets the {@link ActionProvider}.
+     *
+     * @return The action provider.
+     *
+     * @see ActionProvider
+     * @see #setActionProvider(ActionProvider)
+     */
+    public ActionProvider getActionProvider();
+
+    /**
+     * Expand the action view associated with this menu item.
+     * The menu item must have an action view set, as well as
+     * the showAsAction flag {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}.
+     * If a listener has been set using {@link #setOnActionExpandListener(OnActionExpandListener)}
+     * it will have its {@link OnActionExpandListener#onMenuItemActionExpand(MenuItem)}
+     * method invoked. The listener may return false from this method to prevent expanding
+     * the action view.
+     *
+     * @return true if the action view was expanded, false otherwise.
+     */
+    public boolean expandActionView();
+
+    /**
+     * Collapse the action view associated with this menu item.
+     * The menu item must have an action view set, as well as the showAsAction flag
+     * {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}. If a listener has been set using
+     * {@link #setOnActionExpandListener(OnActionExpandListener)} it will have its
+     * {@link OnActionExpandListener#onMenuItemActionCollapse(MenuItem)} method invoked.
+     * The listener may return false from this method to prevent collapsing the action view.
+     *
+     * @return true if the action view was collapsed, false otherwise.
+     */
+    public boolean collapseActionView();
+
+    /**
+     * Returns true if this menu item's action view has been expanded.
+     *
+     * @return true if the item's action view is expanded, false otherwise.
+     *
+     * @see #expandActionView()
+     * @see #collapseActionView()
+     * @see #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
+     * @see OnActionExpandListener
+     */
+    public boolean isActionViewExpanded();
+
+    /**
+     * Set an {@link OnActionExpandListener} on this menu item to be notified when
+     * the associated action view is expanded or collapsed. The menu item must
+     * be configured to expand or collapse its action view using the flag
+     * {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}.
+     *
+     * @param listener Listener that will respond to expand/collapse events
+     * @return This menu item instance for call chaining
+     */
+    public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
+}
\ No newline at end of file
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/SubMenu.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/SubMenu.java
new file mode 100644 (file)
index 0000000..397fd1c
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.view;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+/**
+ * Subclass of {@link Menu} for sub menus.
+ * <p>
+ * Sub menus do not support item icons, or nested sub menus.
+ *
+ * <div class="special reference">
+ * <h3>Developer Guides</h3>
+ * <p>For information about creating menus, read the
+ * <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
+ * </div>
+ */
+
+public interface SubMenu extends Menu {
+    /**
+     * Sets the submenu header's title to the title given in <var>titleRes</var>
+     * resource identifier.
+     *
+     * @param titleRes The string resource identifier used for the title.
+     * @return This SubMenu so additional setters can be called.
+     */
+    public SubMenu setHeaderTitle(int titleRes);
+
+    /**
+     * Sets the submenu header's title to the title given in <var>title</var>.
+     *
+     * @param title The character sequence used for the title.
+     * @return This SubMenu so additional setters can be called.
+     */
+    public SubMenu setHeaderTitle(CharSequence title);
+
+    /**
+     * Sets the submenu header's icon to the icon given in <var>iconRes</var>
+     * resource id.
+     *
+     * @param iconRes The resource identifier used for the icon.
+     * @return This SubMenu so additional setters can be called.
+     */
+    public SubMenu setHeaderIcon(int iconRes);
+
+    /**
+     * Sets the submenu header's icon to the icon given in <var>icon</var>
+     * {@link Drawable}.
+     *
+     * @param icon The {@link Drawable} used for the icon.
+     * @return This SubMenu so additional setters can be called.
+     */
+    public SubMenu setHeaderIcon(Drawable icon);
+
+    /**
+     * Sets the header of the submenu to the {@link View} given in
+     * <var>view</var>. This replaces the header title and icon (and those
+     * replace this).
+     *
+     * @param view The {@link View} used for the header.
+     * @return This SubMenu so additional setters can be called.
+     */
+    public SubMenu setHeaderView(View view);
+
+    /**
+     * Clears the header of the submenu.
+     */
+    public void clearHeader();
+
+    /**
+     * Change the icon associated with this submenu's item in its parent menu.
+     *
+     * @see MenuItem#setIcon(int)
+     * @param iconRes The new icon (as a resource ID) to be displayed.
+     * @return This SubMenu so additional setters can be called.
+     */
+    public SubMenu setIcon(int iconRes);
+
+    /**
+     * Change the icon associated with this submenu's item in its parent menu.
+     *
+     * @see MenuItem#setIcon(Drawable)
+     * @param icon The new icon (as a Drawable) to be displayed.
+     * @return This SubMenu so additional setters can be called.
+     */
+    public SubMenu setIcon(Drawable icon);
+
+    /**
+     * Gets the {@link MenuItem} that represents this submenu in the parent
+     * menu.  Use this for setting additional item attributes.
+     *
+     * @return The {@link MenuItem} that launches the submenu when invoked.
+     */
+    public MenuItem getItem();
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/Window.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/view/Window.java
new file mode 100644 (file)
index 0000000..a340a42
--- /dev/null
@@ -0,0 +1,65 @@
+/*\r
+ * Copyright (C) 2006 The Android Open Source Project\r
+ * Copyright (C) 2011 Jake Wharton\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.actionbarsherlock.view;\r
+\r
+import android.content.Context;\r
+\r
+/**\r
+ * <p>Abstract base class for a top-level window look and behavior policy. An\r
+ * instance of this class should be used as the top-level view added to the\r
+ * window manager. It provides standard UI policies such as a background, title\r
+ * area, default key processing, etc.</p>\r
+ *\r
+ * <p>The only existing implementation of this abstract class is\r
+ * android.policy.PhoneWindow, which you should instantiate when needing a\r
+ * Window. Eventually that class will be refactored and a factory method added\r
+ * for creating Window instances without knowing about a particular\r
+ * implementation.</p>\r
+ */\r
+public abstract class Window extends android.view.Window {\r
+    public static final long FEATURE_ACTION_BAR = android.view.Window.FEATURE_ACTION_BAR;\r
+    public static final long FEATURE_ACTION_BAR_OVERLAY = android.view.Window.FEATURE_ACTION_BAR_OVERLAY;\r
+    public static final long FEATURE_ACTION_MODE_OVERLAY = android.view.Window.FEATURE_ACTION_MODE_OVERLAY;\r
+    public static final long FEATURE_NO_TITLE = android.view.Window.FEATURE_NO_TITLE;\r
+    public static final long FEATURE_PROGRESS = android.view.Window.FEATURE_PROGRESS;\r
+    public static final long FEATURE_INDETERMINATE_PROGRESS = android.view.Window.FEATURE_INDETERMINATE_PROGRESS;\r
+\r
+    /**\r
+     * Create a new instance for a context.\r
+     *\r
+     * @param context Context.\r
+     */\r
+    private Window(Context context) {\r
+        super(context);\r
+    }\r
+\r
+\r
+    public interface Callback {\r
+        /**\r
+         * Called when a panel's menu item has been selected by the user.\r
+         *\r
+         * @param featureId The panel that the menu is in.\r
+         * @param item The menu item that was selected.\r
+         *\r
+         * @return boolean Return true to finish processing of selection, or\r
+         *         false to perform the normal menu handling (calling its\r
+         *         Runnable or sending a Message to its target Handler).\r
+         */\r
+        public boolean onMenuItemSelected(int featureId, MenuItem item);\r
+    }\r
+}\r
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ActivityChooserModel.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ActivityChooserModel.java
new file mode 100644 (file)
index 0000000..3792074
--- /dev/null
@@ -0,0 +1,1131 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.widget;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.database.DataSetObservable;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+
+/**
+ * <p>
+ * This class represents a data model for choosing a component for handing a
+ * given {@link Intent}. The model is responsible for querying the system for
+ * activities that can handle the given intent and order found activities
+ * based on historical data of previous choices. The historical data is stored
+ * in an application private file. If a client does not want to have persistent
+ * choice history the file can be omitted, thus the activities will be ordered
+ * based on historical usage for the current session.
+ * <p>
+ * </p>
+ * For each backing history file there is a singleton instance of this class. Thus,
+ * several clients that specify the same history file will share the same model. Note
+ * that if multiple clients are sharing the same model they should implement semantically
+ * equivalent functionality since setting the model intent will change the found
+ * activities and they may be inconsistent with the functionality of some of the clients.
+ * For example, choosing a share activity can be implemented by a single backing
+ * model and two different views for performing the selection. If however, one of the
+ * views is used for sharing but the other for importing, for example, then each
+ * view should be backed by a separate model.
+ * </p>
+ * <p>
+ * The way clients interact with this class is as follows:
+ * </p>
+ * <p>
+ * <pre>
+ * <code>
+ *  // Get a model and set it to a couple of clients with semantically similar function.
+ *  ActivityChooserModel dataModel =
+ *      ActivityChooserModel.get(context, "task_specific_history_file_name.xml");
+ *
+ *  ActivityChooserModelClient modelClient1 = getActivityChooserModelClient1();
+ *  modelClient1.setActivityChooserModel(dataModel);
+ *
+ *  ActivityChooserModelClient modelClient2 = getActivityChooserModelClient2();
+ *  modelClient2.setActivityChooserModel(dataModel);
+ *
+ *  // Set an intent to choose a an activity for.
+ *  dataModel.setIntent(intent);
+ * <pre>
+ * <code>
+ * </p>
+ * <p>
+ * <strong>Note:</strong> This class is thread safe.
+ * </p>
+ *
+ * @hide
+ */
+class ActivityChooserModel extends DataSetObservable {
+
+    /**
+     * Client that utilizes an {@link ActivityChooserModel}.
+     */
+    public interface ActivityChooserModelClient {
+
+        /**
+         * Sets the {@link ActivityChooserModel}.
+         *
+         * @param dataModel The model.
+         */
+        public void setActivityChooserModel(ActivityChooserModel dataModel);
+    }
+
+    /**
+     * Defines a sorter that is responsible for sorting the activities
+     * based on the provided historical choices and an intent.
+     */
+    public interface ActivitySorter {
+
+        /**
+         * Sorts the <code>activities</code> in descending order of relevance
+         * based on previous history and an intent.
+         *
+         * @param intent The {@link Intent}.
+         * @param activities Activities to be sorted.
+         * @param historicalRecords Historical records.
+         */
+        // This cannot be done by a simple comparator since an Activity weight
+        // is computed from history. Note that Activity implements Comparable.
+        public void sort(Intent intent, List<ActivityResolveInfo> activities,
+                List<HistoricalRecord> historicalRecords);
+    }
+
+    /**
+     * Listener for choosing an activity.
+     */
+    public interface OnChooseActivityListener {
+
+        /**
+         * Called when an activity has been chosen. The client can decide whether
+         * an activity can be chosen and if so the caller of
+         * {@link ActivityChooserModel#chooseActivity(int)} will receive and {@link Intent}
+         * for launching it.
+         * <p>
+         * <strong>Note:</strong> Modifying the intent is not permitted and
+         *     any changes to the latter will be ignored.
+         * </p>
+         *
+         * @param host The listener's host model.
+         * @param intent The intent for launching the chosen activity.
+         * @return Whether the intent is handled and should not be delivered to clients.
+         *
+         * @see ActivityChooserModel#chooseActivity(int)
+         */
+        public boolean onChooseActivity(ActivityChooserModel host, Intent intent);
+    }
+
+    /**
+     * Flag for selecting debug mode.
+     */
+    private static final boolean DEBUG = false;
+
+    /**
+     * Tag used for logging.
+     */
+    private static final String LOG_TAG = ActivityChooserModel.class.getSimpleName();
+
+    /**
+     * The root tag in the history file.
+     */
+    private static final String TAG_HISTORICAL_RECORDS = "historical-records";
+
+    /**
+     * The tag for a record in the history file.
+     */
+    private static final String TAG_HISTORICAL_RECORD = "historical-record";
+
+    /**
+     * Attribute for the activity.
+     */
+    private static final String ATTRIBUTE_ACTIVITY = "activity";
+
+    /**
+     * Attribute for the choice time.
+     */
+    private static final String ATTRIBUTE_TIME = "time";
+
+    /**
+     * Attribute for the choice weight.
+     */
+    private static final String ATTRIBUTE_WEIGHT = "weight";
+
+    /**
+     * The default name of the choice history file.
+     */
+    public static final String DEFAULT_HISTORY_FILE_NAME =
+        "activity_choser_model_history.xml";
+
+    /**
+     * The default maximal length of the choice history.
+     */
+    public static final int DEFAULT_HISTORY_MAX_LENGTH = 50;
+
+    /**
+     * The amount with which to inflate a chosen activity when set as default.
+     */
+    private static final int DEFAULT_ACTIVITY_INFLATION = 5;
+
+    /**
+     * Default weight for a choice record.
+     */
+    private static final float DEFAULT_HISTORICAL_RECORD_WEIGHT = 1.0f;
+
+    /**
+     * The extension of the history file.
+     */
+    private static final String HISTORY_FILE_EXTENSION = ".xml";
+
+    /**
+     * An invalid item index.
+     */
+    private static final int INVALID_INDEX = -1;
+
+    /**
+     * Lock to guard the model registry.
+     */
+    private static final Object sRegistryLock = new Object();
+
+    /**
+     * This the registry for data models.
+     */
+    private static final Map<String, ActivityChooserModel> sDataModelRegistry =
+        new HashMap<String, ActivityChooserModel>();
+
+    /**
+     * Lock for synchronizing on this instance.
+     */
+    private final Object mInstanceLock = new Object();
+
+    /**
+     * List of activities that can handle the current intent.
+     */
+    private final List<ActivityResolveInfo> mActivites = new ArrayList<ActivityResolveInfo>();
+
+    /**
+     * List with historical choice records.
+     */
+    private final List<HistoricalRecord> mHistoricalRecords = new ArrayList<HistoricalRecord>();
+
+    /**
+     * Context for accessing resources.
+     */
+    private final Context mContext;
+
+    /**
+     * The name of the history file that backs this model.
+     */
+    private final String mHistoryFileName;
+
+    /**
+     * The intent for which a activity is being chosen.
+     */
+    private Intent mIntent;
+
+    /**
+     * The sorter for ordering activities based on intent and past choices.
+     */
+    private ActivitySorter mActivitySorter = new DefaultSorter();
+
+    /**
+     * The maximal length of the choice history.
+     */
+    private int mHistoryMaxSize = DEFAULT_HISTORY_MAX_LENGTH;
+
+    /**
+     * Flag whether choice history can be read. In general many clients can
+     * share the same data model and {@link #readHistoricalData()} may be called
+     * by arbitrary of them any number of times. Therefore, this class guarantees
+     * that the very first read succeeds and subsequent reads can be performed
+     * only after a call to {@link #persistHistoricalData()} followed by change
+     * of the share records.
+     */
+    private boolean mCanReadHistoricalData = true;
+
+    /**
+     * Flag whether the choice history was read. This is used to enforce that
+     * before calling {@link #persistHistoricalData()} a call to
+     * {@link #persistHistoricalData()} has been made. This aims to avoid a
+     * scenario in which a choice history file exits, it is not read yet and
+     * it is overwritten. Note that always all historical records are read in
+     * full and the file is rewritten. This is necessary since we need to
+     * purge old records that are outside of the sliding window of past choices.
+     */
+    private boolean mReadShareHistoryCalled = false;
+
+    /**
+     * Flag whether the choice records have changed. In general many clients can
+     * share the same data model and {@link #persistHistoricalData()} may be called
+     * by arbitrary of them any number of times. Therefore, this class guarantees
+     * that choice history will be persisted only if it has changed.
+     */
+    private boolean mHistoricalRecordsChanged = true;
+
+    /**
+     * Hander for scheduling work on client tread.
+     */
+    private final Handler mHandler = new Handler();
+
+    /**
+     * Policy for controlling how the model handles chosen activities.
+     */
+    private OnChooseActivityListener mActivityChoserModelPolicy;
+
+    /**
+     * Gets the data model backed by the contents of the provided file with historical data.
+     * Note that only one data model is backed by a given file, thus multiple calls with
+     * the same file name will return the same model instance. If no such instance is present
+     * it is created.
+     * <p>
+     * <strong>Note:</strong> To use the default historical data file clients should explicitly
+     * pass as file name {@link #DEFAULT_HISTORY_FILE_NAME}. If no persistence of the choice
+     * history is desired clients should pass <code>null</code> for the file name. In such
+     * case a new model is returned for each invocation.
+     * </p>
+     *
+     * <p>
+     * <strong>Always use difference historical data files for semantically different actions.
+     * For example, sharing is different from importing.</strong>
+     * </p>
+     *
+     * @param context Context for loading resources.
+     * @param historyFileName File name with choice history, <code>null</code>
+     *        if the model should not be backed by a file. In this case the activities
+     *        will be ordered only by data from the current session.
+     *
+     * @return The model.
+     */
+    public static ActivityChooserModel get(Context context, String historyFileName) {
+        synchronized (sRegistryLock) {
+            ActivityChooserModel dataModel = sDataModelRegistry.get(historyFileName);
+            if (dataModel == null) {
+                dataModel = new ActivityChooserModel(context, historyFileName);
+                sDataModelRegistry.put(historyFileName, dataModel);
+            }
+            dataModel.readHistoricalData();
+            return dataModel;
+        }
+    }
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context Context for loading resources.
+     * @param historyFileName The history XML file.
+     */
+    private ActivityChooserModel(Context context, String historyFileName) {
+        mContext = context.getApplicationContext();
+        if (!TextUtils.isEmpty(historyFileName)
+                && !historyFileName.endsWith(HISTORY_FILE_EXTENSION)) {
+            mHistoryFileName = historyFileName + HISTORY_FILE_EXTENSION;
+        } else {
+            mHistoryFileName = historyFileName;
+        }
+    }
+
+    /**
+     * Sets an intent for which to choose a activity.
+     * <p>
+     * <strong>Note:</strong> Clients must set only semantically similar
+     * intents for each data model.
+     * <p>
+     *
+     * @param intent The intent.
+     */
+    public void setIntent(Intent intent) {
+        synchronized (mInstanceLock) {
+            if (mIntent == intent) {
+                return;
+            }
+            mIntent = intent;
+            loadActivitiesLocked();
+        }
+    }
+
+    /**
+     * Gets the intent for which a activity is being chosen.
+     *
+     * @return The intent.
+     */
+    public Intent getIntent() {
+        synchronized (mInstanceLock) {
+            return mIntent;
+        }
+    }
+
+    /**
+     * Gets the number of activities that can handle the intent.
+     *
+     * @return The activity count.
+     *
+     * @see #setIntent(Intent)
+     */
+    public int getActivityCount() {
+        synchronized (mInstanceLock) {
+            return mActivites.size();
+        }
+    }
+
+    /**
+     * Gets an activity at a given index.
+     *
+     * @return The activity.
+     *
+     * @see ActivityResolveInfo
+     * @see #setIntent(Intent)
+     */
+    public ResolveInfo getActivity(int index) {
+        synchronized (mInstanceLock) {
+            return mActivites.get(index).resolveInfo;
+        }
+    }
+
+    /**
+     * Gets the index of a the given activity.
+     *
+     * @param activity The activity index.
+     *
+     * @return The index if found, -1 otherwise.
+     */
+    public int getActivityIndex(ResolveInfo activity) {
+        List<ActivityResolveInfo> activities = mActivites;
+        final int activityCount = activities.size();
+        for (int i = 0; i < activityCount; i++) {
+            ActivityResolveInfo currentActivity = activities.get(i);
+            if (currentActivity.resolveInfo == activity) {
+                return i;
+            }
+        }
+        return INVALID_INDEX;
+    }
+
+    /**
+     * Chooses a activity to handle the current intent. This will result in
+     * adding a historical record for that action and construct intent with
+     * its component name set such that it can be immediately started by the
+     * client.
+     * <p>
+     * <strong>Note:</strong> By calling this method the client guarantees
+     * that the returned intent will be started. This intent is returned to
+     * the client solely to let additional customization before the start.
+     * </p>
+     *
+     * @return An {@link Intent} for launching the activity or null if the
+     *         policy has consumed the intent.
+     *
+     * @see HistoricalRecord
+     * @see OnChooseActivityListener
+     */
+    public Intent chooseActivity(int index) {
+        ActivityResolveInfo chosenActivity = mActivites.get(index);
+
+        ComponentName chosenName = new ComponentName(
+                chosenActivity.resolveInfo.activityInfo.packageName,
+                chosenActivity.resolveInfo.activityInfo.name);
+
+        Intent choiceIntent = new Intent(mIntent);
+        choiceIntent.setComponent(chosenName);
+
+        if (mActivityChoserModelPolicy != null) {
+            // Do not allow the policy to change the intent.
+            Intent choiceIntentCopy = new Intent(choiceIntent);
+            final boolean handled = mActivityChoserModelPolicy.onChooseActivity(this,
+                    choiceIntentCopy);
+            if (handled) {
+                return null;
+            }
+        }
+
+        HistoricalRecord historicalRecord = new HistoricalRecord(chosenName,
+                System.currentTimeMillis(), DEFAULT_HISTORICAL_RECORD_WEIGHT);
+        addHisoricalRecord(historicalRecord);
+
+        return choiceIntent;
+    }
+
+    /**
+     * Sets the listener for choosing an activity.
+     *
+     * @param listener The listener.
+     */
+    public void setOnChooseActivityListener(OnChooseActivityListener listener) {
+        mActivityChoserModelPolicy = listener;
+    }
+
+    /**
+     * Gets the default activity, The default activity is defined as the one
+     * with highest rank i.e. the first one in the list of activities that can
+     * handle the intent.
+     *
+     * @return The default activity, <code>null</code> id not activities.
+     *
+     * @see #getActivity(int)
+     */
+    public ResolveInfo getDefaultActivity() {
+        synchronized (mInstanceLock) {
+            if (!mActivites.isEmpty()) {
+                return mActivites.get(0).resolveInfo;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sets the default activity. The default activity is set by adding a
+     * historical record with weight high enough that this activity will
+     * become the highest ranked. Such a strategy guarantees that the default
+     * will eventually change if not used. Also the weight of the record for
+     * setting a default is inflated with a constant amount to guarantee that
+     * it will stay as default for awhile.
+     *
+     * @param index The index of the activity to set as default.
+     */
+    public void setDefaultActivity(int index) {
+        ActivityResolveInfo newDefaultActivity = mActivites.get(index);
+        ActivityResolveInfo oldDefaultActivity = mActivites.get(0);
+
+        final float weight;
+        if (oldDefaultActivity != null) {
+            // Add a record with weight enough to boost the chosen at the top.
+            weight = oldDefaultActivity.weight - newDefaultActivity.weight
+                + DEFAULT_ACTIVITY_INFLATION;
+        } else {
+            weight = DEFAULT_HISTORICAL_RECORD_WEIGHT;
+        }
+
+        ComponentName defaultName = new ComponentName(
+                newDefaultActivity.resolveInfo.activityInfo.packageName,
+                newDefaultActivity.resolveInfo.activityInfo.name);
+        HistoricalRecord historicalRecord = new HistoricalRecord(defaultName,
+                System.currentTimeMillis(), weight);
+        addHisoricalRecord(historicalRecord);
+    }
+
+    /**
+     * Reads the history data from the backing file if the latter
+     * was provided. Calling this method more than once before a call
+     * to {@link #persistHistoricalData()} has been made has no effect.
+     * <p>
+     * <strong>Note:</strong> Historical data is read asynchronously and
+     *       as soon as the reading is completed any registered
+     *       {@link DataSetObserver}s will be notified. Also no historical
+     *       data is read until this method is invoked.
+     * <p>
+     */
+    private void readHistoricalData() {
+        synchronized (mInstanceLock) {
+            if (!mCanReadHistoricalData || !mHistoricalRecordsChanged) {
+                return;
+            }
+            mCanReadHistoricalData = false;
+            mReadShareHistoryCalled = true;
+            if (!TextUtils.isEmpty(mHistoryFileName)) {
+                /*AsyncTask.*/SERIAL_EXECUTOR.execute(new HistoryLoader());
+            }
+        }
+    }
+
+    private static final SerialExecutor SERIAL_EXECUTOR = new SerialExecutor();
+
+    private static class SerialExecutor implements Executor {
+        final LinkedList<Runnable> mTasks = new LinkedList<Runnable>();
+        Runnable mActive;
+
+        public synchronized void execute(final Runnable r) {
+            mTasks.offer(new Runnable() {
+                public void run() {
+                    try {
+                        r.run();
+                    } finally {
+                        scheduleNext();
+                    }
+                }
+            });
+            if (mActive == null) {
+                scheduleNext();
+            }
+        }
+
+        protected synchronized void scheduleNext() {
+            if ((mActive = mTasks.poll()) != null) {
+                mActive.run();
+            }
+        }
+    }
+
+    /**
+     * Persists the history data to the backing file if the latter
+     * was provided. Calling this method before a call to {@link #readHistoricalData()}
+     * throws an exception. Calling this method more than one without choosing an
+     * activity has not effect.
+     *
+     * @throws IllegalStateException If this method is called before a call to
+     *         {@link #readHistoricalData()}.
+     */
+    private void persistHistoricalData() {
+        synchronized (mInstanceLock) {
+            if (!mReadShareHistoryCalled) {
+                throw new IllegalStateException("No preceding call to #readHistoricalData");
+            }
+            if (!mHistoricalRecordsChanged) {
+                return;
+            }
+            mHistoricalRecordsChanged = false;
+            mCanReadHistoricalData = true;
+            if (!TextUtils.isEmpty(mHistoryFileName)) {
+                /*AsyncTask.*/SERIAL_EXECUTOR.execute(new HistoryPersister());
+            }
+        }
+    }
+
+    /**
+     * Sets the sorter for ordering activities based on historical data and an intent.
+     *
+     * @param activitySorter The sorter.
+     *
+     * @see ActivitySorter
+     */
+    public void setActivitySorter(ActivitySorter activitySorter) {
+        synchronized (mInstanceLock) {
+            if (mActivitySorter == activitySorter) {
+                return;
+            }
+            mActivitySorter = activitySorter;
+            sortActivities();
+        }
+    }
+
+    /**
+     * Sorts the activities based on history and an intent. If
+     * a sorter is not specified this a default implementation is used.
+     *
+     * @see #setActivitySorter(ActivitySorter)
+     */
+    private void sortActivities() {
+        synchronized (mInstanceLock) {
+            if (mActivitySorter != null && !mActivites.isEmpty()) {
+                mActivitySorter.sort(mIntent, mActivites,
+                        Collections.unmodifiableList(mHistoricalRecords));
+                notifyChanged();
+            }
+        }
+    }
+
+    /**
+     * Sets the maximal size of the historical data. Defaults to
+     * {@link #DEFAULT_HISTORY_MAX_LENGTH}
+     * <p>
+     *   <strong>Note:</strong> Setting this property will immediately
+     *   enforce the specified max history size by dropping enough old
+     *   historical records to enforce the desired size. Thus, any
+     *   records that exceed the history size will be discarded and
+     *   irreversibly lost.
+     * </p>
+     *
+     * @param historyMaxSize The max history size.
+     */
+    public void setHistoryMaxSize(int historyMaxSize) {
+        synchronized (mInstanceLock) {
+            if (mHistoryMaxSize == historyMaxSize) {
+                return;
+            }
+            mHistoryMaxSize = historyMaxSize;
+            pruneExcessiveHistoricalRecordsLocked();
+            sortActivities();
+        }
+    }
+
+    /**
+     * Gets the history max size.
+     *
+     * @return The history max size.
+     */
+    public int getHistoryMaxSize() {
+        synchronized (mInstanceLock) {
+            return mHistoryMaxSize;
+        }
+    }
+
+    /**
+     * Gets the history size.
+     *
+     * @return The history size.
+     */
+    public int getHistorySize() {
+        synchronized (mInstanceLock) {
+            return mHistoricalRecords.size();
+        }
+    }
+
+    /**
+     * Adds a historical record.
+     *
+     * @param historicalRecord The record to add.
+     * @return True if the record was added.
+     */
+    private boolean addHisoricalRecord(HistoricalRecord historicalRecord) {
+        synchronized (mInstanceLock) {
+            final boolean added = mHistoricalRecords.add(historicalRecord);
+            if (added) {
+                mHistoricalRecordsChanged = true;
+                pruneExcessiveHistoricalRecordsLocked();
+                persistHistoricalData();
+                sortActivities();
+            }
+            return added;
+        }
+    }
+
+    /**
+     * Prunes older excessive records to guarantee {@link #mHistoryMaxSize}.
+     */
+    private void pruneExcessiveHistoricalRecordsLocked() {
+        List<HistoricalRecord> choiceRecords = mHistoricalRecords;
+        final int pruneCount = choiceRecords.size() - mHistoryMaxSize;
+        if (pruneCount <= 0) {
+            return;
+        }
+        mHistoricalRecordsChanged = true;
+        for (int i = 0; i < pruneCount; i++) {
+            HistoricalRecord prunedRecord = choiceRecords.remove(0);
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Pruned: " + prunedRecord);
+            }
+        }
+    }
+
+    /**
+     * Loads the activities.
+     */
+    private void loadActivitiesLocked() {
+        mActivites.clear();
+        if (mIntent != null) {
+            List<ResolveInfo> resolveInfos =
+                mContext.getPackageManager().queryIntentActivities(mIntent, 0);
+            final int resolveInfoCount = resolveInfos.size();
+            for (int i = 0; i < resolveInfoCount; i++) {
+                ResolveInfo resolveInfo = resolveInfos.get(i);
+                mActivites.add(new ActivityResolveInfo(resolveInfo));
+            }
+            sortActivities();
+        } else {
+            notifyChanged();
+        }
+    }
+
+    /**
+     * Represents a record in the history.
+     */
+    public final static class HistoricalRecord {
+
+        /**
+         * The activity name.
+         */
+        public final ComponentName activity;
+
+        /**
+         * The choice time.
+         */
+        public final long time;
+
+        /**
+         * The record weight.
+         */
+        public final float weight;
+
+        /**
+         * Creates a new instance.
+         *
+         * @param activityName The activity component name flattened to string.
+         * @param time The time the activity was chosen.
+         * @param weight The weight of the record.
+         */
+        public HistoricalRecord(String activityName, long time, float weight) {
+            this(ComponentName.unflattenFromString(activityName), time, weight);
+        }
+
+        /**
+         * Creates a new instance.
+         *
+         * @param activityName The activity name.
+         * @param time The time the activity was chosen.
+         * @param weight The weight of the record.
+         */
+        public HistoricalRecord(ComponentName activityName, long time, float weight) {
+            this.activity = activityName;
+            this.time = time;
+            this.weight = weight;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((activity == null) ? 0 : activity.hashCode());
+            result = prime * result + (int) (time ^ (time >>> 32));
+            result = prime * result + Float.floatToIntBits(weight);
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            HistoricalRecord other = (HistoricalRecord) obj;
+            if (activity == null) {
+                if (other.activity != null) {
+                    return false;
+                }
+            } else if (!activity.equals(other.activity)) {
+                return false;
+            }
+            if (time != other.time) {
+                return false;
+            }
+            if (Float.floatToIntBits(weight) != Float.floatToIntBits(other.weight)) {
+                return false;
+            }
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("[");
+            builder.append("; activity:").append(activity);
+            builder.append("; time:").append(time);
+            builder.append("; weight:").append(new BigDecimal(weight));
+            builder.append("]");
+            return builder.toString();
+        }
+    }
+
+    /**
+     * Represents an activity.
+     */
+    public final class ActivityResolveInfo implements Comparable<ActivityResolveInfo> {
+
+        /**
+         * The {@link ResolveInfo} of the activity.
+         */
+        public final ResolveInfo resolveInfo;
+
+        /**
+         * Weight of the activity. Useful for sorting.
+         */
+        public float weight;
+
+        /**
+         * Creates a new instance.
+         *
+         * @param resolveInfo activity {@link ResolveInfo}.
+         */
+        public ActivityResolveInfo(ResolveInfo resolveInfo) {
+            this.resolveInfo = resolveInfo;
+        }
+
+        @Override
+        public int hashCode() {
+            return 31 + Float.floatToIntBits(weight);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ActivityResolveInfo other = (ActivityResolveInfo) obj;
+            if (Float.floatToIntBits(weight) != Float.floatToIntBits(other.weight)) {
+                return false;
+            }
+            return true;
+        }
+
+        public int compareTo(ActivityResolveInfo another) {
+             return  Float.floatToIntBits(another.weight) - Float.floatToIntBits(weight);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("[");
+            builder.append("resolveInfo:").append(resolveInfo.toString());
+            builder.append("; weight:").append(new BigDecimal(weight));
+            builder.append("]");
+            return builder.toString();
+        }
+    }
+
+    /**
+     * Default activity sorter implementation.
+     */
+    private final class DefaultSorter implements ActivitySorter {
+        private static final float WEIGHT_DECAY_COEFFICIENT = 0.95f;
+
+        private final Map<String, ActivityResolveInfo> mPackageNameToActivityMap =
+            new HashMap<String, ActivityResolveInfo>();
+
+        public void sort(Intent intent, List<ActivityResolveInfo> activities,
+                List<HistoricalRecord> historicalRecords) {
+            Map<String, ActivityResolveInfo> packageNameToActivityMap =
+                mPackageNameToActivityMap;
+            packageNameToActivityMap.clear();
+
+            final int activityCount = activities.size();
+            for (int i = 0; i < activityCount; i++) {
+                ActivityResolveInfo activity = activities.get(i);
+                activity.weight = 0.0f;
+                String packageName = activity.resolveInfo.activityInfo.packageName;
+                packageNameToActivityMap.put(packageName, activity);
+            }
+
+            final int lastShareIndex = historicalRecords.size() - 1;
+            float nextRecordWeight = 1;
+            for (int i = lastShareIndex; i >= 0; i--) {
+                HistoricalRecord historicalRecord = historicalRecords.get(i);
+                String packageName = historicalRecord.activity.getPackageName();
+                ActivityResolveInfo activity = packageNameToActivityMap.get(packageName);
+                if (activity != null) {
+                    activity.weight += historicalRecord.weight * nextRecordWeight;
+                    nextRecordWeight = nextRecordWeight * WEIGHT_DECAY_COEFFICIENT;
+                }
+            }
+
+            Collections.sort(activities);
+
+            if (DEBUG) {
+                for (int i = 0; i < activityCount; i++) {
+                    Log.i(LOG_TAG, "Sorted: " + activities.get(i));
+                }
+            }
+        }
+    }
+
+    /**
+     * Command for reading the historical records from a file off the UI thread.
+     */
+    private final class HistoryLoader implements Runnable {
+
+       public void run() {
+            FileInputStream fis = null;
+            try {
+                fis = mContext.openFileInput(mHistoryFileName);
+            } catch (FileNotFoundException fnfe) {
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Could not open historical records file: " + mHistoryFileName);
+                }
+                return;
+            }
+            try {
+                XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(fis, null);
+
+                int type = XmlPullParser.START_DOCUMENT;
+                while (type != XmlPullParser.END_DOCUMENT && type != XmlPullParser.START_TAG) {
+                    type = parser.next();
+                }
+
+                if (!TAG_HISTORICAL_RECORDS.equals(parser.getName())) {
+                    throw new XmlPullParserException("Share records file does not start with "
+                            + TAG_HISTORICAL_RECORDS + " tag.");
+                }
+
+                List<HistoricalRecord> readRecords = new ArrayList<HistoricalRecord>();
+
+                while (true) {
+                    type = parser.next();
+                    if (type == XmlPullParser.END_DOCUMENT) {
+                        break;
+                    }
+                    if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                        continue;
+                    }
+                    String nodeName = parser.getName();
+                    if (!TAG_HISTORICAL_RECORD.equals(nodeName)) {
+                        throw new XmlPullParserException("Share records file not well-formed.");
+                    }
+
+                    String activity = parser.getAttributeValue(null, ATTRIBUTE_ACTIVITY);
+                    final long time =
+                        Long.parseLong(parser.getAttributeValue(null, ATTRIBUTE_TIME));
+                    final float weight =
+                        Float.parseFloat(parser.getAttributeValue(null, ATTRIBUTE_WEIGHT));
+
+                    HistoricalRecord readRecord = new HistoricalRecord(activity, time,
+                            weight);
+                    readRecords.add(readRecord);
+
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Read " + readRecord.toString());
+                    }
+                }
+
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Read " + readRecords.size() + " historical records.");
+                }
+
+                synchronized (mInstanceLock) {
+                    Set<HistoricalRecord> uniqueShareRecords =
+                        new LinkedHashSet<HistoricalRecord>(readRecords);
+
+                    // Make sure no duplicates. Example: Read a file with
+                    // one record, add one record, persist the two records,
+                    // add a record, read the persisted records - the
+                    // read two records should not be added again.
+                    List<HistoricalRecord> historicalRecords = mHistoricalRecords;
+                    final int historicalRecordsCount = historicalRecords.size();
+                    for (int i = historicalRecordsCount - 1; i >= 0; i--) {
+                        HistoricalRecord historicalRecord = historicalRecords.get(i);
+                        uniqueShareRecords.add(historicalRecord);
+                    }
+
+                    if (historicalRecords.size() == uniqueShareRecords.size()) {
+                        return;
+                    }
+
+                    // Make sure the oldest records go to the end.
+                    historicalRecords.clear();
+                    historicalRecords.addAll(uniqueShareRecords);
+
+                    mHistoricalRecordsChanged = true;
+
+                    // Do this on the client thread since the client may be on the UI
+                    // thread, wait for data changes which happen during sorting, and
+                    // perform UI modification based on the data change.
+                    mHandler.post(new Runnable() {
+                        public void run() {
+                            pruneExcessiveHistoricalRecordsLocked();
+                            sortActivities();
+                        }
+                    });
+                }
+            } catch (XmlPullParserException xppe) {
+                Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, xppe);
+            } catch (IOException ioe) {
+                Log.e(LOG_TAG, "Error reading historical recrod file: " + mHistoryFileName, ioe);
+            } finally {
+                if (fis != null) {
+                    try {
+                        fis.close();
+                    } catch (IOException ioe) {
+                        /* ignore */
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Command for persisting the historical records to a file off the UI thread.
+     */
+    private final class HistoryPersister implements Runnable {
+
+        public void run() {
+            FileOutputStream fos = null;
+            List<HistoricalRecord> records = null;
+
+            synchronized (mInstanceLock) {
+                records = new ArrayList<HistoricalRecord>(mHistoricalRecords);
+            }
+
+            try {
+                fos = mContext.openFileOutput(mHistoryFileName, Context.MODE_PRIVATE);
+            } catch (FileNotFoundException fnfe) {
+                Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, fnfe);
+                return;
+            }
+
+            XmlSerializer serializer = Xml.newSerializer();
+
+            try {
+                serializer.setOutput(fos, null);
+                serializer.startDocument("UTF-8", true);
+                serializer.startTag(null, TAG_HISTORICAL_RECORDS);
+
+                final int recordCount = records.size();
+                for (int i = 0; i < recordCount; i++) {
+                    HistoricalRecord record = records.remove(0);
+                    serializer.startTag(null, TAG_HISTORICAL_RECORD);
+                    serializer.attribute(null, ATTRIBUTE_ACTIVITY, record.activity.flattenToString());
+                    serializer.attribute(null, ATTRIBUTE_TIME, String.valueOf(record.time));
+                    serializer.attribute(null, ATTRIBUTE_WEIGHT, String.valueOf(record.weight));
+                    serializer.endTag(null, TAG_HISTORICAL_RECORD);
+                    if (DEBUG) {
+                        Log.i(LOG_TAG, "Wrote " + record.toString());
+                    }
+                }
+
+                serializer.endTag(null, TAG_HISTORICAL_RECORDS);
+                serializer.endDocument();
+
+                if (DEBUG) {
+                    Log.i(LOG_TAG, "Wrote " + recordCount + " historical records.");
+                }
+            } catch (IllegalArgumentException iae) {
+                Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, iae);
+            } catch (IllegalStateException ise) {
+                Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ise);
+            } catch (IOException ioe) {
+                Log.e(LOG_TAG, "Error writing historical recrod file: " + mHistoryFileName, ioe);
+            } finally {
+                if (fos != null) {
+                    try {
+                        fos.close();
+                    } catch (IOException e) {
+                        /* ignore */
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ActivityChooserView.java
new file mode 100644 (file)
index 0000000..da13bc9
--- /dev/null
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.widget;
+
+import android.os.Build;
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.internal.widget.IcsLinearLayout;
+import com.actionbarsherlock.internal.widget.IcsListPopupWindow;
+import com.actionbarsherlock.view.ActionProvider;
+import com.actionbarsherlock.widget.ActivityChooserModel.ActivityChooserModelClient;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.PopupWindow;
+import android.widget.TextView;
+
+/**
+ * This class is a view for choosing an activity for handling a given {@link Intent}.
+ * <p>
+ * The view is composed of two adjacent buttons:
+ * <ul>
+ * <li>
+ * The left button is an immediate action and allows one click activity choosing.
+ * Tapping this button immediately executes the intent without requiring any further
+ * user input. Long press on this button shows a popup for changing the default
+ * activity.
+ * </li>
+ * <li>
+ * The right button is an overflow action and provides an optimized menu
+ * of additional activities. Tapping this button shows a popup anchored to this
+ * view, listing the most frequently used activities. This list is initially
+ * limited to a small number of items in frequency used order. The last item,
+ * "Show all..." serves as an affordance to display all available activities.
+ * </li>
+ * </ul>
+ * </p>
+ *
+ * @hide
+ */
+class ActivityChooserView extends ViewGroup implements ActivityChooserModelClient {
+
+    /**
+     * An adapter for displaying the activities in an {@link AdapterView}.
+     */
+    private final ActivityChooserViewAdapter mAdapter;
+
+    /**
+     * Implementation of various interfaces to avoid publishing them in the APIs.
+     */
+    private final Callbacks mCallbacks;
+
+    /**
+     * The content of this view.
+     */
+    private final IcsLinearLayout mActivityChooserContent;
+
+    /**
+     * Stores the background drawable to allow hiding and latter showing.
+     */
+    private final Drawable mActivityChooserContentBackground;
+
+    /**
+     * The expand activities action button;
+     */
+    private final FrameLayout mExpandActivityOverflowButton;
+
+    /**
+     * The image for the expand activities action button;
+     */
+    private final ImageView mExpandActivityOverflowButtonImage;
+
+    /**
+     * The default activities action button;
+     */
+    private final FrameLayout mDefaultActivityButton;
+
+    /**
+     * The image for the default activities action button;
+     */
+    private final ImageView mDefaultActivityButtonImage;
+
+    /**
+     * The maximal width of the list popup.
+     */
+    private final int mListPopupMaxWidth;
+
+    /**
+     * The ActionProvider hosting this view, if applicable.
+     */
+    ActionProvider mProvider;
+
+    /**
+     * Observer for the model data.
+     */
+    private final DataSetObserver mModelDataSetOberver = new DataSetObserver() {
+
+        @Override
+        public void onChanged() {
+            super.onChanged();
+            mAdapter.notifyDataSetChanged();
+        }
+        @Override
+        public void onInvalidated() {
+            super.onInvalidated();
+            mAdapter.notifyDataSetInvalidated();
+        }
+    };
+
+    private final OnGlobalLayoutListener mOnGlobalLayoutListener = new OnGlobalLayoutListener() {
+        @Override
+        public void onGlobalLayout() {
+            if (isShowingPopup()) {
+                if (!isShown()) {
+                    getListPopupWindow().dismiss();
+                } else {
+                    getListPopupWindow().show();
+                    if (mProvider != null) {
+                        mProvider.subUiVisibilityChanged(true);
+                    }
+                }
+            }
+        }
+    };
+
+    /**
+     * Popup window for showing the activity overflow list.
+     */
+    private IcsListPopupWindow mListPopupWindow;
+
+    /**
+     * Listener for the dismissal of the popup/alert.
+     */
+    private PopupWindow.OnDismissListener mOnDismissListener;
+
+    /**
+     * Flag whether a default activity currently being selected.
+     */
+    private boolean mIsSelectingDefaultActivity;
+
+    /**
+     * The count of activities in the popup.
+     */
+    private int mInitialActivityCount = ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT;
+
+    /**
+     * Flag whether this view is attached to a window.
+     */
+    private boolean mIsAttachedToWindow;
+
+    /**
+     * String resource for formatting content description of the default target.
+     */
+    private int mDefaultActionButtonContentDescription;
+
+    private final Context mContext;
+
+    /**
+     * Create a new instance.
+     *
+     * @param context The application environment.
+     */
+    public ActivityChooserView(Context context) {
+        this(context, null);
+    }
+
+    /**
+     * Create a new instance.
+     *
+     * @param context The application environment.
+     * @param attrs A collection of attributes.
+     */
+    public ActivityChooserView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    /**
+     * Create a new instance.
+     *
+     * @param context The application environment.
+     * @param attrs A collection of attributes.
+     * @param defStyle The default style to apply to this view.
+     */
+    public ActivityChooserView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        mContext = context;
+
+        TypedArray attributesArray = context.obtainStyledAttributes(attrs,
+                R.styleable.SherlockActivityChooserView, defStyle, 0);
+
+        mInitialActivityCount = attributesArray.getInt(
+                R.styleable.SherlockActivityChooserView_initialActivityCount,
+                ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_DEFAULT);
+
+        Drawable expandActivityOverflowButtonDrawable = attributesArray.getDrawable(
+                R.styleable.SherlockActivityChooserView_expandActivityOverflowButtonDrawable);
+
+        attributesArray.recycle();
+
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        inflater.inflate(R.layout.abs__activity_chooser_view, this, true);
+
+        mCallbacks = new Callbacks();
+
+        mActivityChooserContent = (IcsLinearLayout) findViewById(R.id.abs__activity_chooser_view_content);
+        mActivityChooserContentBackground = mActivityChooserContent.getBackground();
+
+        mDefaultActivityButton = (FrameLayout) findViewById(R.id.abs__default_activity_button);
+        mDefaultActivityButton.setOnClickListener(mCallbacks);
+        mDefaultActivityButton.setOnLongClickListener(mCallbacks);
+        mDefaultActivityButtonImage = (ImageView) mDefaultActivityButton.findViewById(R.id.abs__image);
+
+        mExpandActivityOverflowButton = (FrameLayout) findViewById(R.id.abs__expand_activities_button);
+        mExpandActivityOverflowButton.setOnClickListener(mCallbacks);
+        mExpandActivityOverflowButtonImage =
+            (ImageView) mExpandActivityOverflowButton.findViewById(R.id.abs__image);
+        mExpandActivityOverflowButtonImage.setImageDrawable(expandActivityOverflowButtonDrawable);
+
+        mAdapter = new ActivityChooserViewAdapter();
+        mAdapter.registerDataSetObserver(new DataSetObserver() {
+            @Override
+            public void onChanged() {
+                super.onChanged();
+                updateAppearance();
+            }
+        });
+
+        Resources resources = context.getResources();
+        mListPopupMaxWidth = Math.max(resources.getDisplayMetrics().widthPixels / 2,
+              resources.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void setActivityChooserModel(ActivityChooserModel dataModel) {
+        mAdapter.setDataModel(dataModel);
+        if (isShowingPopup()) {
+            dismissPopup();
+            showPopup();
+        }
+    }
+
+    /**
+     * Sets the background for the button that expands the activity
+     * overflow list.
+     *
+     * <strong>Note:</strong> Clients would like to set this drawable
+     * as a clue about the action the chosen activity will perform. For
+     * example, if a share activity is to be chosen the drawable should
+     * give a clue that sharing is to be performed.
+     *
+     * @param drawable The drawable.
+     */
+    public void setExpandActivityOverflowButtonDrawable(Drawable drawable) {
+        mExpandActivityOverflowButtonImage.setImageDrawable(drawable);
+    }
+
+    /**
+     * Sets the content description for the button that expands the activity
+     * overflow list.
+     *
+     * description as a clue about the action performed by the button.
+     * For example, if a share activity is to be chosen the content
+     * description should be something like "Share with".
+     *
+     * @param resourceId The content description resource id.
+     */
+    public void setExpandActivityOverflowButtonContentDescription(int resourceId) {
+        CharSequence contentDescription = mContext.getString(resourceId);
+        mExpandActivityOverflowButtonImage.setContentDescription(contentDescription);
+    }
+
+    /**
+     * Set the provider hosting this view, if applicable.
+     * @hide Internal use only
+     */
+    public void setProvider(ActionProvider provider) {
+        mProvider = provider;
+    }
+
+    /**
+     * Shows the popup window with activities.
+     *
+     * @return True if the popup was shown, false if already showing.
+     */
+    public boolean showPopup() {
+        if (isShowingPopup() || !mIsAttachedToWindow) {
+            return false;
+        }
+        mIsSelectingDefaultActivity = false;
+        showPopupUnchecked(mInitialActivityCount);
+        return true;
+    }
+
+    /**
+     * Shows the popup no matter if it was already showing.
+     *
+     * @param maxActivityCount The max number of activities to display.
+     */
+    private void showPopupUnchecked(int maxActivityCount) {
+        if (mAdapter.getDataModel() == null) {
+            throw new IllegalStateException("No data model. Did you call #setDataModel?");
+        }
+
+        getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
+
+        final boolean defaultActivityButtonShown =
+            mDefaultActivityButton.getVisibility() == VISIBLE;
+
+        final int activityCount = mAdapter.getActivityCount();
+        final int maxActivityCountOffset = defaultActivityButtonShown ? 1 : 0;
+        if (maxActivityCount != ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED
+                && activityCount > maxActivityCount + maxActivityCountOffset) {
+            mAdapter.setShowFooterView(true);
+            mAdapter.setMaxActivityCount(maxActivityCount - 1);
+        } else {
+            mAdapter.setShowFooterView(false);
+            mAdapter.setMaxActivityCount(maxActivityCount);
+        }
+
+        IcsListPopupWindow popupWindow = getListPopupWindow();
+        if (!popupWindow.isShowing()) {
+            if (mIsSelectingDefaultActivity || !defaultActivityButtonShown) {
+                mAdapter.setShowDefaultActivity(true, defaultActivityButtonShown);
+            } else {
+                mAdapter.setShowDefaultActivity(false, false);
+            }
+            final int contentWidth = Math.min(mAdapter.measureContentWidth(), mListPopupMaxWidth);
+            popupWindow.setContentWidth(contentWidth);
+            popupWindow.show();
+            if (mProvider != null) {
+                mProvider.subUiVisibilityChanged(true);
+            }
+            popupWindow.getListView().setContentDescription(mContext.getString(
+                    R.string.abs__activitychooserview_choose_application));
+        }
+    }
+
+    /**
+     * Dismisses the popup window with activities.
+     *
+     * @return True if dismissed, false if already dismissed.
+     */
+    public boolean dismissPopup() {
+        if (isShowingPopup()) {
+            getListPopupWindow().dismiss();
+            ViewTreeObserver viewTreeObserver = getViewTreeObserver();
+            if (viewTreeObserver.isAlive()) {
+                viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Gets whether the popup window with activities is shown.
+     *
+     * @return True if the popup is shown.
+     */
+    public boolean isShowingPopup() {
+        return getListPopupWindow().isShowing();
+    }
+
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        ActivityChooserModel dataModel = mAdapter.getDataModel();
+        if (dataModel != null) {
+            dataModel.registerObserver(mModelDataSetOberver);
+        }
+        mIsAttachedToWindow = true;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        ActivityChooserModel dataModel = mAdapter.getDataModel();
+        if (dataModel != null) {
+            dataModel.unregisterObserver(mModelDataSetOberver);
+        }
+        ViewTreeObserver viewTreeObserver = getViewTreeObserver();
+        if (viewTreeObserver.isAlive()) {
+            viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
+        }
+        mIsAttachedToWindow = false;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        View child = mActivityChooserContent;
+        // If the default action is not visible we want to be as tall as the
+        // ActionBar so if this widget is used in the latter it will look as
+        // a normal action button.
+        if (mDefaultActivityButton.getVisibility() != VISIBLE) {
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+                    MeasureSpec.EXACTLY);
+        }
+        measureChild(child, widthMeasureSpec, heightMeasureSpec);
+        setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        mActivityChooserContent.layout(0, 0, right - left, bottom - top);
+        if (getListPopupWindow().isShowing()) {
+            showPopupUnchecked(mAdapter.getMaxActivityCount());
+        } else {
+            dismissPopup();
+        }
+    }
+
+    public ActivityChooserModel getDataModel() {
+        return mAdapter.getDataModel();
+    }
+
+    /**
+     * Sets a listener to receive a callback when the popup is dismissed.
+     *
+     * @param listener The listener to be notified.
+     */
+    public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
+        mOnDismissListener = listener;
+    }
+
+    /**
+     * Sets the initial count of items shown in the activities popup
+     * i.e. the items before the popup is expanded. This is an upper
+     * bound since it is not guaranteed that such number of intent
+     * handlers exist.
+     *
+     * @param itemCount The initial popup item count.
+     */
+    public void setInitialActivityCount(int itemCount) {
+        mInitialActivityCount = itemCount;
+    }
+
+    /**
+     * Sets a content description of the default action button. This
+     * resource should be a string taking one formatting argument and
+     * will be used for formatting the content description of the button
+     * dynamically as the default target changes. For example, a resource
+     * pointing to the string "share with %1$s" will result in a content
+     * description "share with Bluetooth" for the Bluetooth activity.
+     *
+     * @param resourceId The resource id.
+     */
+    public void setDefaultActionButtonContentDescription(int resourceId) {
+        mDefaultActionButtonContentDescription = resourceId;
+    }
+
+    /**
+     * Gets the list popup window which is lazily initialized.
+     *
+     * @return The popup.
+     */
+    private IcsListPopupWindow getListPopupWindow() {
+        if (mListPopupWindow == null) {
+            mListPopupWindow = new IcsListPopupWindow(getContext());
+            mListPopupWindow.setAdapter(mAdapter);
+            mListPopupWindow.setAnchorView(ActivityChooserView.this);
+            mListPopupWindow.setModal(true);
+            mListPopupWindow.setOnItemClickListener(mCallbacks);
+            mListPopupWindow.setOnDismissListener(mCallbacks);
+        }
+        return mListPopupWindow;
+    }
+
+    /**
+     * Updates the buttons state.
+     */
+    private void updateAppearance() {
+        // Expand overflow button.
+        if (mAdapter.getCount() > 0) {
+            mExpandActivityOverflowButton.setEnabled(true);
+        } else {
+            mExpandActivityOverflowButton.setEnabled(false);
+        }
+        // Default activity button.
+        final int activityCount = mAdapter.getActivityCount();
+        final int historySize = mAdapter.getHistorySize();
+        if (activityCount > 0 && historySize > 0) {
+            mDefaultActivityButton.setVisibility(VISIBLE);
+            ResolveInfo activity = mAdapter.getDefaultActivity();
+            PackageManager packageManager = mContext.getPackageManager();
+            mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
+            if (mDefaultActionButtonContentDescription != 0) {
+                CharSequence label = activity.loadLabel(packageManager);
+                String contentDescription = mContext.getString(
+                        mDefaultActionButtonContentDescription, label);
+                mDefaultActivityButton.setContentDescription(contentDescription);
+            }
+        } else {
+            mDefaultActivityButton.setVisibility(View.GONE);
+        }
+        // Activity chooser content.
+        if (mDefaultActivityButton.getVisibility() == VISIBLE) {
+            mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
+        } else {
+            mActivityChooserContent.setBackgroundDrawable(null);
+        }
+    }
+
+    /**
+     * Interface implementation to avoid publishing them in the APIs.
+     */
+    private class Callbacks implements AdapterView.OnItemClickListener,
+            View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener {
+
+        // AdapterView#OnItemClickListener
+        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+            ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter();
+            final int itemViewType = adapter.getItemViewType(position);
+            switch (itemViewType) {
+                case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: {
+                    showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED);
+                } break;
+                case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: {
+                    dismissPopup();
+                    if (mIsSelectingDefaultActivity) {
+                        // The item at position zero is the default already.
+                        if (position > 0) {
+                            mAdapter.getDataModel().setDefaultActivity(position);
+                        }
+                    } else {
+                        // If the default target is not shown in the list, the first
+                        // item in the model is default action => adjust index
+                        position = mAdapter.getShowDefaultActivity() ? position : position + 1;
+                        Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
+                        if (launchIntent != null) {
+                            mContext.startActivity(launchIntent);
+                        }
+                    }
+                } break;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        // View.OnClickListener
+        public void onClick(View view) {
+            if (view == mDefaultActivityButton) {
+                dismissPopup();
+                ResolveInfo defaultActivity = mAdapter.getDefaultActivity();
+                final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
+                Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
+                if (launchIntent != null) {
+                    mContext.startActivity(launchIntent);
+                }
+            } else if (view == mExpandActivityOverflowButton) {
+                mIsSelectingDefaultActivity = false;
+                showPopupUnchecked(mInitialActivityCount);
+            } else {
+                throw new IllegalArgumentException();
+            }
+        }
+
+        // OnLongClickListener#onLongClick
+        @Override
+        public boolean onLongClick(View view) {
+            if (view == mDefaultActivityButton) {
+                if (mAdapter.getCount() > 0) {
+                    mIsSelectingDefaultActivity = true;
+                    showPopupUnchecked(mInitialActivityCount);
+                }
+            } else {
+                throw new IllegalArgumentException();
+            }
+            return true;
+        }
+
+        // PopUpWindow.OnDismissListener#onDismiss
+        public void onDismiss() {
+            notifyOnDismissListener();
+            if (mProvider != null) {
+                mProvider.subUiVisibilityChanged(false);
+            }
+        }
+
+        private void notifyOnDismissListener() {
+            if (mOnDismissListener != null) {
+                mOnDismissListener.onDismiss();
+            }
+        }
+    }
+
+    private static class SetActivated {
+        public static void invoke(View view, boolean activated) {
+            view.setActivated(activated);
+        }
+    }
+
+    private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
+
+    /**
+     * Adapter for backing the list of activities shown in the popup.
+     */
+    private class ActivityChooserViewAdapter extends BaseAdapter {
+
+        public static final int MAX_ACTIVITY_COUNT_UNLIMITED = Integer.MAX_VALUE;
+
+        public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4;
+
+        private static final int ITEM_VIEW_TYPE_ACTIVITY = 0;
+
+        private static final int ITEM_VIEW_TYPE_FOOTER = 1;
+
+        private static final int ITEM_VIEW_TYPE_COUNT = 3;
+
+        private ActivityChooserModel mDataModel;
+
+        private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT;
+
+        private boolean mShowDefaultActivity;
+
+        private boolean mHighlightDefaultActivity;
+
+        private boolean mShowFooterView;
+
+        public void setDataModel(ActivityChooserModel dataModel) {
+            ActivityChooserModel oldDataModel = mAdapter.getDataModel();
+            if (oldDataModel != null && isShown()) {
+                oldDataModel.unregisterObserver(mModelDataSetOberver);
+            }
+            mDataModel = dataModel;
+            if (dataModel != null && isShown()) {
+                dataModel.registerObserver(mModelDataSetOberver);
+            }
+            notifyDataSetChanged();
+        }
+
+        @Override
+        public int getItemViewType(int position) {
+            if (mShowFooterView && position == getCount() - 1) {
+                return ITEM_VIEW_TYPE_FOOTER;
+            } else {
+                return ITEM_VIEW_TYPE_ACTIVITY;
+            }
+        }
+
+        @Override
+        public int getViewTypeCount() {
+            return ITEM_VIEW_TYPE_COUNT;
+        }
+
+        public int getCount() {
+            int count = 0;
+            int activityCount = mDataModel.getActivityCount();
+            if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
+                activityCount--;
+            }
+            count = Math.min(activityCount, mMaxActivityCount);
+            if (mShowFooterView) {
+                count++;
+            }
+            return count;
+        }
+
+        public Object getItem(int position) {
+            final int itemViewType = getItemViewType(position);
+            switch (itemViewType) {
+                case ITEM_VIEW_TYPE_FOOTER:
+                    return null;
+                case ITEM_VIEW_TYPE_ACTIVITY:
+                    if (!mShowDefaultActivity && mDataModel.getDefaultActivity() != null) {
+                        position++;
+                    }
+                    return mDataModel.getActivity(position);
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        public long getItemId(int position) {
+            return position;
+        }
+
+        public View getView(int position, View convertView, ViewGroup parent) {
+            final int itemViewType = getItemViewType(position);
+            switch (itemViewType) {
+                case ITEM_VIEW_TYPE_FOOTER:
+                    if (convertView == null || convertView.getId() != ITEM_VIEW_TYPE_FOOTER) {
+                        convertView = LayoutInflater.from(getContext()).inflate(
+                                R.layout.abs__activity_chooser_view_list_item, parent, false);
+                        convertView.setId(ITEM_VIEW_TYPE_FOOTER);
+                        TextView titleView = (TextView) convertView.findViewById(R.id.abs__title);
+                        titleView.setText(mContext.getString(
+                                R.string.abs__activity_chooser_view_see_all));
+                    }
+                    return convertView;
+                case ITEM_VIEW_TYPE_ACTIVITY:
+                    if (convertView == null || convertView.getId() != R.id.abs__list_item) {
+                        convertView = LayoutInflater.from(getContext()).inflate(
+                                R.layout.abs__activity_chooser_view_list_item, parent, false);
+                    }
+                    PackageManager packageManager = mContext.getPackageManager();
+                    // Set the icon
+                    ImageView iconView = (ImageView) convertView.findViewById(R.id.abs__icon);
+                    ResolveInfo activity = (ResolveInfo) getItem(position);
+                    iconView.setImageDrawable(activity.loadIcon(packageManager));
+                    // Set the title.
+                    TextView titleView = (TextView) convertView.findViewById(R.id.abs__title);
+                    titleView.setText(activity.loadLabel(packageManager));
+                    if (IS_HONEYCOMB) {
+                        // Highlight the default.
+                        if (mShowDefaultActivity && position == 0 && mHighlightDefaultActivity) {
+                            SetActivated.invoke(convertView, true);
+                        } else {
+                            SetActivated.invoke(convertView, false);
+                        }
+                    }
+                    return convertView;
+                default:
+                    throw new IllegalArgumentException();
+            }
+        }
+
+        public int measureContentWidth() {
+            // The user may have specified some of the target not to be shown but we
+            // want to measure all of them since after expansion they should fit.
+            final int oldMaxActivityCount = mMaxActivityCount;
+            mMaxActivityCount = MAX_ACTIVITY_COUNT_UNLIMITED;
+
+            int contentWidth = 0;
+            View itemView = null;
+
+            final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+            final int count = getCount();
+
+            for (int i = 0; i < count; i++) {
+                itemView = getView(i, itemView, null);
+                itemView.measure(widthMeasureSpec, heightMeasureSpec);
+                contentWidth = Math.max(contentWidth, itemView.getMeasuredWidth());
+            }
+
+            mMaxActivityCount = oldMaxActivityCount;
+
+            return contentWidth;
+        }
+
+        public void setMaxActivityCount(int maxActivityCount) {
+            if (mMaxActivityCount != maxActivityCount) {
+                mMaxActivityCount = maxActivityCount;
+                notifyDataSetChanged();
+            }
+        }
+
+        public ResolveInfo getDefaultActivity() {
+            return mDataModel.getDefaultActivity();
+        }
+
+        public void setShowFooterView(boolean showFooterView) {
+            if (mShowFooterView != showFooterView) {
+                mShowFooterView = showFooterView;
+                notifyDataSetChanged();
+            }
+        }
+
+        public int getActivityCount() {
+            return mDataModel.getActivityCount();
+        }
+
+        public int getHistorySize() {
+            return mDataModel.getHistorySize();
+        }
+
+        public int getMaxActivityCount() {
+            return mMaxActivityCount;
+        }
+
+        public ActivityChooserModel getDataModel() {
+            return mDataModel;
+        }
+
+        public void setShowDefaultActivity(boolean showDefaultActivity,
+                boolean highlightDefaultActivity) {
+            if (mShowDefaultActivity != showDefaultActivity
+                    || mHighlightDefaultActivity != highlightDefaultActivity) {
+                mShowDefaultActivity = showDefaultActivity;
+                mHighlightDefaultActivity = highlightDefaultActivity;
+                notifyDataSetChanged();
+            }
+        }
+
+        public boolean getShowDefaultActivity() {
+            return mShowDefaultActivity;
+        }
+    }
+}
diff --git a/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ShareActionProvider.java b/android-libraries/ActionBarSherlock/src/com/actionbarsherlock/widget/ShareActionProvider.java
new file mode 100644 (file)
index 0000000..83e9f0c
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.actionbarsherlock.widget;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.drawable.Drawable;
+import android.util.TypedValue;
+import android.view.View;
+
+import com.actionbarsherlock.R;
+import com.actionbarsherlock.view.ActionProvider;
+import com.actionbarsherlock.view.Menu;
+import com.actionbarsherlock.view.MenuItem;
+import com.actionbarsherlock.view.MenuItem.OnMenuItemClickListener;
+import com.actionbarsherlock.view.SubMenu;
+import com.actionbarsherlock.widget.ActivityChooserModel.OnChooseActivityListener;
+
+/**
+ * This is a provider for a share action. It is responsible for creating views
+ * that enable data sharing and also to show a sub menu with sharing activities
+ * if the hosting item is placed on the overflow menu.
+ * <p>
+ * Here is how to use the action provider with custom backing file in a {@link MenuItem}:
+ * </p>
+ * <p>
+ * <pre>
+ * <code>
+ *  // In Activity#onCreateOptionsMenu
+ *  public boolean onCreateOptionsMenu(Menu menu) {
+ *      // Get the menu item.
+ *      MenuItem menuItem = menu.findItem(R.id.my_menu_item);
+ *      // Get the provider and hold onto it to set/change the share intent.
+ *      mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
+ *      // Set history different from the default before getting the action
+ *      // view since a call to {@link MenuItem#getActionView() MenuItem.getActionView()} calls
+ *      // {@link ActionProvider#onCreateActionView()} which uses the backing file name. Omit this
+ *      // line if using the default share history file is desired.
+ *      mShareActionProvider.setShareHistoryFileName("custom_share_history.xml");
+ *      . . .
+ *  }
+ *
+ *  // Somewhere in the application.
+ *  public void doShare(Intent shareIntent) {
+ *      // When you want to share set the share intent.
+ *      mShareActionProvider.setShareIntent(shareIntent);
+ *  }
+ * </pre>
+ * </code>
+ * </p>
+ * <p>
+ * <strong>Note:</strong> While the sample snippet demonstrates how to use this provider
+ * in the context of a menu item, the use of the provider is not limited to menu items.
+ * </p>
+ *
+ * @see ActionProvider
+ */
+public class ShareActionProvider extends ActionProvider {
+
+    /**
+     * Listener for the event of selecting a share target.
+     */
+    public interface OnShareTargetSelectedListener {
+
+        /**
+         * Called when a share target has been selected. The client can
+         * decide whether to handle the intent or rely on the default
+         * behavior which is launching it.
+         * <p>
+         * <strong>Note:</strong> Modifying the intent is not permitted and
+         *     any changes to the latter will be ignored.
+         * </p>
+         *
+         * @param source The source of the notification.
+         * @param intent The intent for launching the chosen share target.
+         * @return Whether the client has handled the intent.
+         */
+        public boolean onShareTargetSelected(ShareActionProvider source, Intent intent);
+    }
+
+    /**
+     * The default for the maximal number of activities shown in the sub-menu.
+     */
+    private static final int DEFAULT_INITIAL_ACTIVITY_COUNT = 4;
+
+    /**
+     * The the maximum number activities shown in the sub-menu.
+     */
+    private int mMaxShownActivityCount = DEFAULT_INITIAL_ACTIVITY_COUNT;
+
+    /**
+     * Listener for handling menu item clicks.
+     */
+    private final ShareMenuItemOnMenuItemClickListener mOnMenuItemClickListener =
+        new ShareMenuItemOnMenuItemClickListener();
+
+    /**
+     * The default name for storing share history.
+     */
+    public static final String DEFAULT_SHARE_HISTORY_FILE_NAME = "share_history.xml";
+
+    /**
+     * Context for accessing resources.
+     */
+    private final Context mContext;
+
+    /**
+     * The name of the file with share history data.
+     */
+    private String mShareHistoryFileName = DEFAULT_SHARE_HISTORY_FILE_NAME;
+
+    private OnShareTargetSelectedListener mOnShareTargetSelectedListener;
+
+    private OnChooseActivityListener mOnChooseActivityListener;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param context Context for accessing resources.
+     */
+    public ShareActionProvider(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    /**
+     * Sets a listener to be notified when a share target has been selected.
+     * The listener can optionally decide to handle the selection and
+     * not rely on the default behavior which is to launch the activity.
+     * <p>
+     * <strong>Note:</strong> If you choose the backing share history file
+     *     you will still be notified in this callback.
+     * </p>
+     * @param listener The listener.
+     */
+    public void setOnShareTargetSelectedListener(OnShareTargetSelectedListener listener) {
+        mOnShareTargetSelectedListener = listener;
+        setActivityChooserPolicyIfNeeded();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public View onCreateActionView() {
+        // Create the view and set its data model.
+        ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
+        ActivityChooserView activityChooserView = new ActivityChooserView(mContext);
+        activityChooserView.setActivityChooserModel(dataModel);
+
+        // Lookup and set the expand action icon.
+        TypedValue outTypedValue = new TypedValue();
+        mContext.getTheme().resolveAttribute(R.attr.actionModeShareDrawable, outTypedValue, true);
+        Drawable drawable = mContext.getResources().getDrawable(outTypedValue.resourceId);
+        activityChooserView.setExpandActivityOverflowButtonDrawable(drawable);
+        activityChooserView.setProvider(this);
+
+        // Set content description.
+        activityChooserView.setDefaultActionButtonContentDescription(
+                R.string.abs__shareactionprovider_share_with_application);
+        activityChooserView.setExpandActivityOverflowButtonContentDescription(
+                R.string.abs__shareactionprovider_share_with);
+
+        return activityChooserView;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasSubMenu() {
+        return true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onPrepareSubMenu(SubMenu subMenu) {
+        // Clear since the order of items may change.
+        subMenu.clear();
+
+        ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
+        PackageManager packageManager = mContext.getPackageManager();
+
+        final int expandedActivityCount = dataModel.getActivityCount();
+        final int collapsedActivityCount = Math.min(expandedActivityCount, mMaxShownActivityCount);
+
+        // Populate the sub-menu with a sub set of the activities.
+        for (int i = 0; i < collapsedActivityCount; i++) {
+            ResolveInfo activity = dataModel.getActivity(i);
+            subMenu.add(0, i, i, activity.loadLabel(packageManager))
+                .setIcon(activity.loadIcon(packageManager))
+                .setOnMenuItemClickListener(mOnMenuItemClickListener);
+        }
+
+        if (collapsedActivityCount < expandedActivityCount) {
+            // Add a sub-menu for showing all activities as a list item.
+            SubMenu expandedSubMenu = subMenu.addSubMenu(Menu.NONE, collapsedActivityCount,
+                    collapsedActivityCount,
+                    mContext.getString(R.string.abs__activity_chooser_view_see_all));
+            for (int i = 0; i < expandedActivityCount; i++) {
+                ResolveInfo activity = dataModel.getActivity(i);
+                expandedSubMenu.add(0, i, i, activity.loadLabel(packageManager))
+                    .setIcon(activity.loadIcon(packageManager))
+                    .setOnMenuItemClickListener(mOnMenuItemClickListener);
+            }
+        }
+    }
+
+    /**
+     * Sets the file name of a file for persisting the share history which
+     * history will be used for ordering share targets. This file will be used
+     * for all view created by {@link #onCreateActionView()}. Defaults to
+     * {@link #DEFAULT_SHARE_HISTORY_FILE_NAME}. Set to <code>null</code>
+     * if share history should not be persisted between sessions.
+     * <p>
+     * <strong>Note:</strong> The history file name can be set any time, however
+     * only the action views created by {@link #onCreateActionView()} after setting
+     * the file name will be backed by the provided file.
+     * <p>
+     *
+     * @param shareHistoryFile The share history file name.
+     */
+    public void setShareHistoryFileName(String shareHistoryFile) {
+        mShareHistoryFileName = shareHistoryFile;
+        setActivityChooserPolicyIfNeeded();
+    }
+
+    /**
+     * Sets an intent with information about the share action. Here is a
+     * sample for constructing a share intent:
+     * <p>
+     * <pre>
+     * <code>
+     *  Intent shareIntent = new Intent(Intent.ACTION_SEND);
+     *  shareIntent.setType("image/*");
+     *  Uri uri = Uri.fromFile(new File(getFilesDir(), "foo.jpg"));
+     *  shareIntent.putExtra(Intent.EXTRA_STREAM, uri.toString());
+     * </pre>
+     * </code>
+     * </p>
+     *
+     * @param shareIntent The share intent.
+     *
+     * @see Intent#ACTION_SEND
+     * @see Intent#ACTION_SEND_MULTIPLE
+     */
+    public void setShareIntent(Intent shareIntent) {
+        ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
+            mShareHistoryFileName);
+        dataModel.setIntent(shareIntent);
+    }
+
+    /**
+     * Reusable listener for handling share item clicks.
+     */
+    private class ShareMenuItemOnMenuItemClickListener implements OnMenuItemClickListener {
+        @Override
+        public boolean onMenuItemClick(MenuItem item) {
+            ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
+                    mShareHistoryFileName);
+            final int itemId = item.getItemId();
+            Intent launchIntent = dataModel.chooseActivity(itemId);
+            if (launchIntent != null) {
+                mContext.startActivity(launchIntent);
+            }
+            return true;
+        }
+    }
+
+    /**
+     * Set the activity chooser policy of the model backed by the current
+     * share history file if needed which is if there is a registered callback.
+     */
+    private void setActivityChooserPolicyIfNeeded() {
+        if (mOnShareTargetSelectedListener == null) {
+            return;
+        }
+        if (mOnChooseActivityListener == null) {
+            mOnChooseActivityListener = new ShareAcitivityChooserModelPolicy();
+        }
+        ActivityChooserModel dataModel = ActivityChooserModel.get(mContext, mShareHistoryFileName);
+        dataModel.setOnChooseActivityListener(mOnChooseActivityListener);
+    }
+
+    /**
+     * Policy that delegates to the {@link OnShareTargetSelectedListener}, if such.
+     */
+    private class ShareAcitivityChooserModelPolicy implements OnChooseActivityListener {
+        @Override
+        public boolean onChooseActivity(ActivityChooserModel host, Intent intent) {
+            if (mOnShareTargetSelectedListener != null) {
+                return mOnShareTargetSelectedListener.onShareTargetSelected(
+                        ShareActionProvider.this, intent);
+            }
+            return false;
+        }
+    }
+}
diff --git a/android-libraries/TreeViewList/.classpath b/android-libraries/TreeViewList/.classpath
new file mode 100644 (file)
index 0000000..a4f1e40
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="src" path="gen"/>\r
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>\r
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
+       <classpathentry kind="output" path="bin/classes"/>\r
+</classpath>\r
diff --git a/android-libraries/TreeViewList/.project b/android-libraries/TreeViewList/.project
new file mode 100644 (file)
index 0000000..c9d4fda
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>TreeViewList</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/android-libraries/TreeViewList/AndroidManifest.xml b/android-libraries/TreeViewList/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..28a7fe0
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"\r
+    package="pl.polidea.treeview"\r
+    android:versionCode="1"\r
+    android:versionName="1.0" >\r
+\r
+    <uses-sdk android:minSdkVersion="7" />\r
+\r
+    <application/>\r
+\r
+</manifest>
\ No newline at end of file
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/AbstractTreeViewAdapter$1.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/AbstractTreeViewAdapter$1.class
new file mode 100644 (file)
index 0000000..2b84661
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/AbstractTreeViewAdapter$1.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/AbstractTreeViewAdapter.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/AbstractTreeViewAdapter.class
new file mode 100644 (file)
index 0000000..40535ba
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/AbstractTreeViewAdapter.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/BuildConfig.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/BuildConfig.class
new file mode 100644 (file)
index 0000000..77562f4
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/BuildConfig.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/InMemoryTreeNode.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/InMemoryTreeNode.class
new file mode 100644 (file)
index 0000000..c2a6124
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/InMemoryTreeNode.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/InMemoryTreeStateManager.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/InMemoryTreeStateManager.class
new file mode 100644 (file)
index 0000000..791ae79
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/InMemoryTreeStateManager.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/NodeAlreadyInTreeException.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/NodeAlreadyInTreeException.class
new file mode 100644 (file)
index 0000000..35af40c
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/NodeAlreadyInTreeException.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/NodeNotInTreeException.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/NodeNotInTreeException.class
new file mode 100644 (file)
index 0000000..a981398
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/NodeNotInTreeException.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$attr.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$attr.class
new file mode 100644 (file)
index 0000000..1a7b40c
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$attr.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$drawable.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$drawable.class
new file mode 100644 (file)
index 0000000..f266770
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$drawable.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$id.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$id.class
new file mode 100644 (file)
index 0000000..7f11957
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$id.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$layout.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$layout.class
new file mode 100644 (file)
index 0000000..a13978f
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$layout.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$style.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$style.class
new file mode 100644 (file)
index 0000000..4a475b2
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$style.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$styleable.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$styleable.class
new file mode 100644 (file)
index 0000000..a992b85
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R$styleable.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R.class
new file mode 100644 (file)
index 0000000..ef23d5e
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/R.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeBuilder.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeBuilder.class
new file mode 100644 (file)
index 0000000..4ddc77c
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeBuilder.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeConfigurationException.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeConfigurationException.class
new file mode 100644 (file)
index 0000000..d2e7193
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeConfigurationException.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeNodeInfo.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeNodeInfo.class
new file mode 100644 (file)
index 0000000..683896c
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeNodeInfo.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeStateManager.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeStateManager.class
new file mode 100644 (file)
index 0000000..f3beab5
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeStateManager.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeViewList$1.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeViewList$1.class
new file mode 100644 (file)
index 0000000..2b9baac
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeViewList$1.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeViewList.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeViewList.class
new file mode 100644 (file)
index 0000000..5303999
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/TreeViewList.class differ
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/overview.html b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/overview.html
new file mode 100644 (file)
index 0000000..bdd09ce
--- /dev/null
@@ -0,0 +1,24 @@
+<html>
+<body>
+This is a small utility that provides quite configurable tree view list.
+It is based on standard android list view. It separates out different
+aspects of the tree: there is a separate list view, tree adapter, tree
+state manager and tree state builder.
+<p>
+<ul>
+       <li>Tree view provides the frame to display the view.</li>
+       <li>Adapter allows to create visual representation of each tree
+       node.</li>
+       <li>State manager provides storage for tree state (connections
+       between parents and children, collapsed/expanded state). It provides
+       all the low-level tree manipulation methods.</li>
+       <li>Tree builder allows to build tree easily providing higher
+       level methods. The tree can be build either from prepared sequentially
+       prepared list of nodes (node id, level) or using (parent/child
+       relationships).</li>
+       <p>For now only in-memory state manager is provided, but Tree State
+       Manger interface is done in the way that database tree manager even for
+       large trees is potentially supported.
+</ul>
+</body>
+</html>
\ No newline at end of file
diff --git a/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/package-info.class b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/package-info.class
new file mode 100644 (file)
index 0000000..d0a1275
Binary files /dev/null and b/android-libraries/TreeViewList/bin/classes/pl/polidea/treeview/package-info.class differ
diff --git a/android-libraries/TreeViewList/bin/jarlist.cache b/android-libraries/TreeViewList/bin/jarlist.cache
new file mode 100644 (file)
index 0000000..1b5ec3f
--- /dev/null
@@ -0,0 +1,3 @@
+# cache for current jar dependecy. DO NOT EDIT.
+# format is <lastModified> <length> <SHA-1> <path>
+# Encoding is UTF-8
diff --git a/android-libraries/TreeViewList/bin/res/drawable-hdpi/collapsed.png b/android-libraries/TreeViewList/bin/res/drawable-hdpi/collapsed.png
new file mode 100644 (file)
index 0000000..84ca818
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-hdpi/collapsed.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable-hdpi/expanded.png b/android-libraries/TreeViewList/bin/res/drawable-hdpi/expanded.png
new file mode 100644 (file)
index 0000000..2761231
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-hdpi/expanded.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable-hdpi/ic_launcher.png b/android-libraries/TreeViewList/bin/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..882eb14
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-hdpi/ic_launcher.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable-ldpi/collapsed.png b/android-libraries/TreeViewList/bin/res/drawable-ldpi/collapsed.png
new file mode 100644 (file)
index 0000000..f9c06f4
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-ldpi/collapsed.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable-ldpi/expanded.png b/android-libraries/TreeViewList/bin/res/drawable-ldpi/expanded.png
new file mode 100644 (file)
index 0000000..7ce5074
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-ldpi/expanded.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable-ldpi/ic_launcher.png b/android-libraries/TreeViewList/bin/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..18689f6
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-ldpi/ic_launcher.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable-mdpi/collapsed.png b/android-libraries/TreeViewList/bin/res/drawable-mdpi/collapsed.png
new file mode 100644 (file)
index 0000000..d2e8774
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-mdpi/collapsed.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable-mdpi/expanded.png b/android-libraries/TreeViewList/bin/res/drawable-mdpi/expanded.png
new file mode 100644 (file)
index 0000000..4c5ad0f
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-mdpi/expanded.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable-mdpi/ic_launcher.png b/android-libraries/TreeViewList/bin/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..02e96b9
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable-mdpi/ic_launcher.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_disabled.9.png b/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_disabled.9.png
new file mode 100644 (file)
index 0000000..6bc40f6
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_disabled.9.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_focus.9.png b/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_focus.9.png
new file mode 100644 (file)
index 0000000..38c6754
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_focus.9.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_longpress.9.png b/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_longpress.9.png
new file mode 100644 (file)
index 0000000..8d2894e
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_longpress.9.png differ
diff --git a/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_pressed.9.png b/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_pressed.9.png
new file mode 100644 (file)
index 0000000..900623e
Binary files /dev/null and b/android-libraries/TreeViewList/bin/res/drawable/list_selector_background_pressed.9.png differ
diff --git a/android-libraries/TreeViewList/bin/treeviewlist.jar b/android-libraries/TreeViewList/bin/treeviewlist.jar
new file mode 100644 (file)
index 0000000..3445f56
Binary files /dev/null and b/android-libraries/TreeViewList/bin/treeviewlist.jar differ
diff --git a/android-libraries/TreeViewList/gen/pl/polidea/treeview/BuildConfig.java b/android-libraries/TreeViewList/gen/pl/polidea/treeview/BuildConfig.java
new file mode 100644 (file)
index 0000000..18bc91b
--- /dev/null
@@ -0,0 +1,6 @@
+/** Automatically generated file. DO NOT MODIFY */
+package pl.polidea.treeview;
+
+public final class BuildConfig {
+    public final static boolean DEBUG = true;
+}
\ No newline at end of file
diff --git a/android-libraries/TreeViewList/gen/pl/polidea/treeview/R.java b/android-libraries/TreeViewList/gen/pl/polidea/treeview/R.java
new file mode 100644 (file)
index 0000000..3ef9b35
--- /dev/null
@@ -0,0 +1,276 @@
+/* AUTO-GENERATED FILE.  DO NOT MODIFY.\r
+ *\r
+ * This class was automatically generated by the\r
+ * aapt tool from the resource data it found.  It\r
+ * should not be modified by hand.\r
+ */\r
+\r
+package pl.polidea.treeview;\r
+\r
+public final class R {\r
+    public static final class attr {\r
+        /** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int collapsible=0x7f010000;\r
+        /** <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int handle_trackball_press=0x7f010004;\r
+        /** <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+         */\r
+        public static int indent_width=0x7f010003;\r
+        /** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int indicator_background=0x7f010006;\r
+        /** <p>Must be one or more (separated by '|') of the following constant values.</p>\r
+<table>\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\r
+<tr><td><code>top</code></td><td>0x30</td><td> Push object to the top of its container, not changing its size. </td></tr>\r
+<tr><td><code>bottom</code></td><td>0x50</td><td> Push object to the bottom of its container, not changing its size. </td></tr>\r
+<tr><td><code>left</code></td><td>0x03</td><td> Push object to the left of its container, not changing its size. </td></tr>\r
+<tr><td><code>right</code></td><td>0x05</td><td> Push object to the right of its container, not changing its size. </td></tr>\r
+<tr><td><code>center_vertical</code></td><td>0x10</td><td> Place object in the vertical center of its container, not changing its size. </td></tr>\r
+<tr><td><code>fill_vertical</code></td><td>0x70</td><td> Grow the vertical size of the object if needed so it completely fills its container. </td></tr>\r
+<tr><td><code>center_horizontal</code></td><td>0x01</td><td> Place object in the horizontal center of its container, not changing its size. </td></tr>\r
+<tr><td><code>fill_horizontal</code></td><td>0x07</td><td> Grow the horizontal size of the object if needed so it completely fills its container. </td></tr>\r
+<tr><td><code>center</code></td><td>0x11</td><td> Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. </td></tr>\r
+<tr><td><code>fill</code></td><td>0x77</td><td> Grow the horizontal and vertical size of the object if needed so it completely fills its container. </td></tr>\r
+<tr><td><code>clip_vertical</code></td><td>0x80</td><td> Additional option that can be set to have the top and/or bottom edges of the child clipped to its container's bounds.\r
+                               The clip will be based on the vertical gravity: a top gravity will clip the bottom edge, a bottom gravity will clip the top\r
+                               edge, and neither will clip both edges. </td></tr>\r
+<tr><td><code>clip_horizontal</code></td><td>0x08</td><td> Additional option that can be set to have the left and/or right edges of the child clipped to its container's bounds.\r
+                               The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the\r
+                               left edge, and neither will clip both edges. </td></tr>\r
+</table>\r
+         */\r
+        public static int indicator_gravity=0x7f010005;\r
+        /** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int row_background=0x7f010007;\r
+        /** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int src_collapsed=0x7f010002;\r
+        /** <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+         */\r
+        public static int src_expanded=0x7f010001;\r
+    }\r
+    public static final class drawable {\r
+        public static int collapsed=0x7f020000;\r
+        public static int divider=0x7f020001;\r
+        public static int expanded=0x7f020002;\r
+        public static int ic_launcher=0x7f020003;\r
+        public static int list_selector_background=0x7f020004;\r
+        public static int list_selector_background_disabled=0x7f020005;\r
+        public static int list_selector_background_focus=0x7f020006;\r
+        public static int list_selector_background_longpress=0x7f020007;\r
+        public static int list_selector_background_pressed=0x7f020008;\r
+        public static int list_selector_background_transition=0x7f020009;\r
+    }\r
+    public static final class id {\r
+        public static int bottom=0x7f040001;\r
+        public static int center=0x7f040008;\r
+        public static int center_horizontal=0x7f040006;\r
+        public static int center_vertical=0x7f040004;\r
+        public static int clip_horizontal=0x7f04000b;\r
+        public static int clip_vertical=0x7f04000a;\r
+        public static int fill=0x7f040009;\r
+        public static int fill_horizontal=0x7f040007;\r
+        public static int fill_vertical=0x7f040005;\r
+        public static int left=0x7f040002;\r
+        public static int right=0x7f040003;\r
+        public static int top=0x7f040000;\r
+        public static int treeview_list_item_frame=0x7f04000e;\r
+        public static int treeview_list_item_image=0x7f04000d;\r
+        public static int treeview_list_item_image_layout=0x7f04000c;\r
+    }\r
+    public static final class layout {\r
+        public static int tree_list_item_wrapper=0x7f030000;\r
+    }\r
+    public static final class style {\r
+        public static int treeViewListStyle=0x7f050000;\r
+    }\r
+    public static final class styleable {\r
+        /** Attributes that can be used with a TreeViewList.\r
+           <p>Includes the following attributes:</p>\r
+           <table>\r
+           <colgroup align="left" />\r
+           <colgroup align="left" />\r
+           <tr><th>Attribute</th><th>Description</th></tr>\r
+           <tr><td><code>{@link #TreeViewList_collapsible pl.polidea.treeview:collapsible}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #TreeViewList_handle_trackball_press pl.polidea.treeview:handle_trackball_press}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #TreeViewList_indent_width pl.polidea.treeview:indent_width}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #TreeViewList_indicator_background pl.polidea.treeview:indicator_background}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #TreeViewList_indicator_gravity pl.polidea.treeview:indicator_gravity}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #TreeViewList_row_background pl.polidea.treeview:row_background}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #TreeViewList_src_collapsed pl.polidea.treeview:src_collapsed}</code></td><td></td></tr>\r
+           <tr><td><code>{@link #TreeViewList_src_expanded pl.polidea.treeview:src_expanded}</code></td><td></td></tr>\r
+           </table>\r
+           @see #TreeViewList_collapsible\r
+           @see #TreeViewList_handle_trackball_press\r
+           @see #TreeViewList_indent_width\r
+           @see #TreeViewList_indicator_background\r
+           @see #TreeViewList_indicator_gravity\r
+           @see #TreeViewList_row_background\r
+           @see #TreeViewList_src_collapsed\r
+           @see #TreeViewList_src_expanded\r
+         */\r
+        public static final int[] TreeViewList = {\r
+            0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003,\r
+            0x7f010004, 0x7f010005, 0x7f010006, 0x7f010007\r
+        };\r
+        /**\r
+          <p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#collapsible}\r
+          attribute's value can be found in the {@link #TreeViewList} array.\r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:collapsible\r
+        */\r
+        public static final int TreeViewList_collapsible = 0;\r
+        /**\r
+          <p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#handle_trackball_press}\r
+          attribute's value can be found in the {@link #TreeViewList} array.\r
+\r
+\r
+          <p>Must be a boolean value, either "<code>true</code>" or "<code>false</code>".\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:handle_trackball_press\r
+        */\r
+        public static final int TreeViewList_handle_trackball_press = 4;\r
+        /**\r
+          <p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#indent_width}\r
+          attribute's value can be found in the {@link #TreeViewList} array.\r
+\r
+\r
+          <p>Must be a dimension value, which is a floating point number appended with a unit such as "<code>14.5sp</code>".\r
+Available units are: px (pixels), dp (density-independent pixels), sp (scaled pixels based on preferred font size),\r
+in (inches), mm (millimeters).\r
+<p>This may also be a reference to a resource (in the form\r
+"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or\r
+theme attribute (in the form\r
+"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")\r
+containing a value of this type.\r
+          @attr name android:indent_width\r
+        */\r
+        public static final int TreeViewList_indent_width = 3;\r
+        /**\r
+          <p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#indicator_background}\r
+          attribute's value can be found in the {@link #TreeViewList} array.\r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          @attr name android:indicator_background\r
+        */\r
+        public static final int TreeViewList_indicator_background = 6;\r
+        /**\r
+          <p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#indicator_gravity}\r
+          attribute's value can be found in the {@link #TreeViewList} array.\r
+\r
+\r
+          <p>Must be one or more (separated by '|') of the following constant values.</p>\r
+<table>\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<colgroup align="left" />\r
+<tr><th>Constant</th><th>Value</th><th>Description</th></tr>\r
+<tr><td><code>top</code></td><td>0x30</td><td> Push object to the top of its container, not changing its size. </td></tr>\r
+<tr><td><code>bottom</code></td><td>0x50</td><td> Push object to the bottom of its container, not changing its size. </td></tr>\r
+<tr><td><code>left</code></td><td>0x03</td><td> Push object to the left of its container, not changing its size. </td></tr>\r
+<tr><td><code>right</code></td><td>0x05</td><td> Push object to the right of its container, not changing its size. </td></tr>\r
+<tr><td><code>center_vertical</code></td><td>0x10</td><td> Place object in the vertical center of its container, not changing its size. </td></tr>\r
+<tr><td><code>fill_vertical</code></td><td>0x70</td><td> Grow the vertical size of the object if needed so it completely fills its container. </td></tr>\r
+<tr><td><code>center_horizontal</code></td><td>0x01</td><td> Place object in the horizontal center of its container, not changing its size. </td></tr>\r
+<tr><td><code>fill_horizontal</code></td><td>0x07</td><td> Grow the horizontal size of the object if needed so it completely fills its container. </td></tr>\r
+<tr><td><code>center</code></td><td>0x11</td><td> Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. </td></tr>\r
+<tr><td><code>fill</code></td><td>0x77</td><td> Grow the horizontal and vertical size of the object if needed so it completely fills its container. </td></tr>\r
+<tr><td><code>clip_vertical</code></td><td>0x80</td><td> Additional option that can be set to have the top and/or bottom edges of the child clipped to its container's bounds.\r
+                               The clip will be based on the vertical gravity: a top gravity will clip the bottom edge, a bottom gravity will clip the top\r
+                               edge, and neither will clip both edges. </td></tr>\r
+<tr><td><code>clip_horizontal</code></td><td>0x08</td><td> Additional option that can be set to have the left and/or right edges of the child clipped to its container's bounds.\r
+                               The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the\r
+                               left edge, and neither will clip both edges. </td></tr>\r
+</table>\r
+          @attr name android:indicator_gravity\r
+        */\r
+        public static final int TreeViewList_indicator_gravity = 5;\r
+        /**\r
+          <p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#row_background}\r
+          attribute's value can be found in the {@link #TreeViewList} array.\r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          @attr name android:row_background\r
+        */\r
+        public static final int TreeViewList_row_background = 7;\r
+        /**\r
+          <p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#src_collapsed}\r
+          attribute's value can be found in the {@link #TreeViewList} array.\r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          @attr name android:src_collapsed\r
+        */\r
+        public static final int TreeViewList_src_collapsed = 2;\r
+        /**\r
+          <p>This symbol is the offset where the {@link pl.polidea.treeview.R.attr#src_expanded}\r
+          attribute's value can be found in the {@link #TreeViewList} array.\r
+\r
+\r
+          <p>May be a reference to another resource, in the form "<code>@[+][<i>package</i>:]<i>type</i>:<i>name</i></code>"\r
+or to a theme attribute in the form "<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>".\r
+<p>May be a color value, in the form of "<code>#<i>rgb</i></code>", "<code>#<i>argb</i></code>",\r
+"<code>#<i>rrggbb</i></code>", or "<code>#<i>aarrggbb</i></code>".\r
+          @attr name android:src_expanded\r
+        */\r
+        public static final int TreeViewList_src_expanded = 1;\r
+    };\r
+}\r
diff --git a/android-libraries/TreeViewList/proguard.cfg b/android-libraries/TreeViewList/proguard.cfg
new file mode 100644 (file)
index 0000000..b1cdf17
--- /dev/null
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+    native <methods>;
+}
+
+-keepclasseswithmembers class * {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+    public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+   public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+  public static final android.os.Parcelable$Creator *;
+}
diff --git a/android-libraries/TreeViewList/project.properties b/android-libraries/TreeViewList/project.properties
new file mode 100644 (file)
index 0000000..5fa344c
--- /dev/null
@@ -0,0 +1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-15
+android.library=true
diff --git a/android-libraries/TreeViewList/res/drawable-hdpi/collapsed.png b/android-libraries/TreeViewList/res/drawable-hdpi/collapsed.png
new file mode 100644 (file)
index 0000000..c1e1f3d
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-hdpi/collapsed.png differ
diff --git a/android-libraries/TreeViewList/res/drawable-hdpi/expanded.png b/android-libraries/TreeViewList/res/drawable-hdpi/expanded.png
new file mode 100644 (file)
index 0000000..cec254a
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-hdpi/expanded.png differ
diff --git a/android-libraries/TreeViewList/res/drawable-hdpi/ic_launcher.png b/android-libraries/TreeViewList/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..8074c4c
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-hdpi/ic_launcher.png differ
diff --git a/android-libraries/TreeViewList/res/drawable-ldpi/collapsed.png b/android-libraries/TreeViewList/res/drawable-ldpi/collapsed.png
new file mode 100644 (file)
index 0000000..a52e846
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-ldpi/collapsed.png differ
diff --git a/android-libraries/TreeViewList/res/drawable-ldpi/expanded.png b/android-libraries/TreeViewList/res/drawable-ldpi/expanded.png
new file mode 100644 (file)
index 0000000..d8b7ab8
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-ldpi/expanded.png differ
diff --git a/android-libraries/TreeViewList/res/drawable-ldpi/ic_launcher.png b/android-libraries/TreeViewList/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..1095584
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-ldpi/ic_launcher.png differ
diff --git a/android-libraries/TreeViewList/res/drawable-mdpi/collapsed.png b/android-libraries/TreeViewList/res/drawable-mdpi/collapsed.png
new file mode 100644 (file)
index 0000000..b235551
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-mdpi/collapsed.png differ
diff --git a/android-libraries/TreeViewList/res/drawable-mdpi/expanded.png b/android-libraries/TreeViewList/res/drawable-mdpi/expanded.png
new file mode 100644 (file)
index 0000000..f7377cb
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-mdpi/expanded.png differ
diff --git a/android-libraries/TreeViewList/res/drawable-mdpi/ic_launcher.png b/android-libraries/TreeViewList/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..a07c69f
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable-mdpi/ic_launcher.png differ
diff --git a/android-libraries/TreeViewList/res/drawable/divider.xml b/android-libraries/TreeViewList/res/drawable/divider.xml
new file mode 100644 (file)
index 0000000..5f37949
--- /dev/null
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+  android:src="@android:drawable/divider_horizontal_dark"
+  android:layout_width="fill_parent" android:layout_height="wrap_content"
+  android:scaleType="fitXY" android:paddingLeft="5sp"
+  android:paddingRight="5sp" android:paddingBottom="2sp" />
diff --git a/android-libraries/TreeViewList/res/drawable/list_selector_background.xml b/android-libraries/TreeViewList/res/drawable/list_selector_background.xml
new file mode 100644 (file)
index 0000000..2b21b0c
--- /dev/null
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project Licensed under the 
+       Apache License, Version 2.0 (the "License"); you may not use this file except 
+       in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
+       Unless required by applicable law or agreed to in writing, software distributed 
+       under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 
+       OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
+       the specific language governing permissions and limitations under the License. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+       <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
+
+       <!-- Even though these two point to the same resource, have two states so 
+               the drawable will invalidate itself when coming out of pressed state. -->
+       <item android:state_focused="true" android:state_enabled="false"
+               android:state_pressed="true" android:drawable="@drawable/list_selector_background_disabled" />
+       <item android:state_focused="true" android:state_enabled="false"
+               android:drawable="@drawable/list_selector_background_disabled" />
+
+       <item android:state_focused="true" android:state_pressed="true"
+               android:drawable="@drawable/list_selector_background_transition" />
+       <item android:state_focused="false" android:state_pressed="true"
+               android:drawable="@drawable/list_selector_background_transition" />
+
+       <item android:state_focused="true"
+               android:drawable="@drawable/list_selector_background_focus" />
+
+       <!-- !!hack!! to fill StateListDrawable.mStateListState with exactly 10 
+               items otherwise it will throw NPE on Android 1.6 -->
+
+       <item android:animationCache="true"
+               android:drawable="@android:color/transparent" />
+
+       <item android:animationCache="false"
+               android:drawable="@android:color/transparent" />
+
+       <item android:alwaysDrawnWithCache="false"
+               android:drawable="@android:color/transparent" />
+
+       <item android:alwaysDrawnWithCache="true"
+               android:drawable="@android:color/transparent" />
+       
+       
+</selector>
\ No newline at end of file
diff --git a/android-libraries/TreeViewList/res/drawable/list_selector_background_disabled.9.png b/android-libraries/TreeViewList/res/drawable/list_selector_background_disabled.9.png
new file mode 100644 (file)
index 0000000..bf970b0
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable/list_selector_background_disabled.9.png differ
diff --git a/android-libraries/TreeViewList/res/drawable/list_selector_background_focus.9.png b/android-libraries/TreeViewList/res/drawable/list_selector_background_focus.9.png
new file mode 100644 (file)
index 0000000..c3e2415
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable/list_selector_background_focus.9.png differ
diff --git a/android-libraries/TreeViewList/res/drawable/list_selector_background_longpress.9.png b/android-libraries/TreeViewList/res/drawable/list_selector_background_longpress.9.png
new file mode 100644 (file)
index 0000000..5cbb251
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable/list_selector_background_longpress.9.png differ
diff --git a/android-libraries/TreeViewList/res/drawable/list_selector_background_pressed.9.png b/android-libraries/TreeViewList/res/drawable/list_selector_background_pressed.9.png
new file mode 100644 (file)
index 0000000..02b4e9a
Binary files /dev/null and b/android-libraries/TreeViewList/res/drawable/list_selector_background_pressed.9.png differ
diff --git a/android-libraries/TreeViewList/res/drawable/list_selector_background_transition.xml b/android-libraries/TreeViewList/res/drawable/list_selector_background_transition.xml
new file mode 100644 (file)
index 0000000..0dec133
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:drawable="@drawable/list_selector_background_pressed"  />
+    <item android:drawable="@drawable/list_selector_background_longpress"  />
+</transition>
diff --git a/android-libraries/TreeViewList/res/layout/tree_list_item_wrapper.xml b/android-libraries/TreeViewList/res/layout/tree_list_item_wrapper.xml
new file mode 100644 (file)
index 0000000..9512a0c
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
+       android:layout_height="fill_parent" >
+       <LinearLayout android:id="@+id/treeview_list_item_image_layout" android:layout_width="80dip"
+               android:layout_height="fill_parent" android:gravity="right|center_vertical">
+               <ImageView android:id="@+id/treeview_list_item_image" android:layout_width="wrap_content"
+                       android:layout_height="wrap_content" android:src="@drawable/collapsed" >
+               </ImageView>
+       </LinearLayout>
+       <FrameLayout android:id="@+id/treeview_list_item_frame" android:layout_width="fill_parent"
+               android:layout_height="fill_parent" android:layout_weight="1">
+       </FrameLayout>
+</LinearLayout>
diff --git a/android-libraries/TreeViewList/res/values/attrs.xml b/android-libraries/TreeViewList/res/values/attrs.xml
new file mode 100644 (file)
index 0000000..30060a4
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+       <declare-styleable name="TreeViewList">
+           <attr name="collapsible" format="boolean" />
+               <attr name="src_expanded" format="reference|color" />
+               <attr name="src_collapsed" format="reference|color" />
+        <attr name="indent_width" format="dimension" />
+        <attr name="handle_trackball_press" format="boolean" />
+               <attr name="indicator_gravity">
+                       <!-- Push object to the top of its container, not changing its size. -->
+                       <flag name="top" value="0x30" />
+                       <!-- Push object to the bottom of its container, not changing its size. -->
+                       <flag name="bottom" value="0x50" />
+                       <!-- Push object to the left of its container, not changing its size. -->
+                       <flag name="left" value="0x03" />
+                       <!-- Push object to the right of its container, not changing its size. -->
+                       <flag name="right" value="0x05" />
+                       <!-- Place object in the vertical center of its container, not changing its size. -->
+                       <flag name="center_vertical" value="0x10" />
+                       <!-- Grow the vertical size of the object if needed so it completely fills its container. -->
+                       <flag name="fill_vertical" value="0x70" />
+                       <!-- Place object in the horizontal center of its container, not changing its size. -->
+                       <flag name="center_horizontal" value="0x01" />
+                       <!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
+                       <flag name="fill_horizontal" value="0x07" />
+                       <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
+                       <flag name="center" value="0x11" />
+                       <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
+                       <flag name="fill" value="0x77" />
+                       <!-- Additional option that can be set to have the top and/or bottom edges of the child clipped to its container's bounds.
+                               The clip will be based on the vertical gravity: a top gravity will clip the bottom edge, a bottom gravity will clip the top
+                               edge, and neither will clip both edges. -->
+                       <flag name="clip_vertical" value="0x80" />
+                       <!-- Additional option that can be set to have the left and/or right edges of the child clipped to its container's bounds.
+                               The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the
+                               left edge, and neither will clip both edges. -->
+                       <flag name="clip_horizontal" value="0x08" />
+               </attr>
+        <attr name="indicator_background" format="reference|color" />
+        <attr name="row_background" format="reference|color" />
+       </declare-styleable>
+</resources>
\ No newline at end of file
diff --git a/android-libraries/TreeViewList/res/values/styles.xml b/android-libraries/TreeViewList/res/values/styles.xml
new file mode 100644 (file)
index 0000000..005c600
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style parent="@android:attr/listViewStyle" name="treeViewListStyle">
+        <item name="android:background">@android:color/white</item>
+        <item name="android:divider">@drawable/divider</item>
+    </style>
+</resources>
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/AbstractTreeViewAdapter.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/AbstractTreeViewAdapter.java
new file mode 100644 (file)
index 0000000..7f2b366
--- /dev/null
@@ -0,0 +1,315 @@
+package pl.polidea.treeview;
+
+import android.app.Activity;
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.drawable.Drawable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.ImageView;
+import android.widget.ImageView.ScaleType;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+
+/**
+ * Adapter used to feed the table view.
+ * 
+ * @param <T>
+ *            class for ID of the tree
+ */
+public abstract class AbstractTreeViewAdapter<T> extends BaseAdapter implements
+        ListAdapter {
+    private final TreeStateManager<T> treeStateManager;
+    private final int numberOfLevels;
+    private final LayoutInflater layoutInflater;
+
+    private int indentWidth = 0;
+    private int indicatorGravity = 0;
+    private Drawable collapsedDrawable;
+    private Drawable expandedDrawable;
+    private Drawable indicatorBackgroundDrawable;
+    private Drawable rowBackgroundDrawable;
+
+    private final OnClickListener indicatorClickListener = new OnClickListener() {
+        @Override
+        public void onClick(final View v) {
+            @SuppressWarnings("unchecked")
+            final T id = (T) v.getTag();
+            expandCollapse(id);
+        }
+    };
+
+    private boolean collapsible;
+    private final Activity activity;
+
+    public Activity getActivity() {
+        return activity;
+    }
+
+    protected TreeStateManager<T> getManager() {
+        return treeStateManager;
+    }
+
+    protected void expandCollapse(final T id) {
+        final TreeNodeInfo<T> info = treeStateManager.getNodeInfo(id);
+        if (!info.isWithChildren()) {
+            // ignore - no default action
+            return;
+        }
+        if (info.isExpanded()) {
+            treeStateManager.collapseChildren(id);
+        } else {
+            treeStateManager.expandDirectChildren(id);
+        }
+    }
+
+    private void calculateIndentWidth() {
+        if (expandedDrawable != null) {
+            indentWidth = Math.max(getIndentWidth(),
+                    expandedDrawable.getIntrinsicWidth());
+        }
+        if (collapsedDrawable != null) {
+            indentWidth = Math.max(getIndentWidth(),
+                    collapsedDrawable.getIntrinsicWidth());
+        }
+    }
+
+    public AbstractTreeViewAdapter(final Activity activity,
+            final TreeStateManager<T> treeStateManager, final int numberOfLevels) {
+        this.activity = activity;
+        this.treeStateManager = treeStateManager;
+        this.layoutInflater = (LayoutInflater) activity
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        this.numberOfLevels = numberOfLevels;
+        this.collapsedDrawable = null;
+        this.expandedDrawable = null;
+        this.rowBackgroundDrawable = null;
+        this.indicatorBackgroundDrawable = null;
+    }
+
+    @Override
+    public void registerDataSetObserver(final DataSetObserver observer) {
+        treeStateManager.registerDataSetObserver(observer);
+    }
+
+    @Override
+    public void unregisterDataSetObserver(final DataSetObserver observer) {
+        treeStateManager.unregisterDataSetObserver(observer);
+    }
+
+    @Override
+    public int getCount() {
+        return treeStateManager.getVisibleCount();
+    }
+
+    @Override
+    public Object getItem(final int position) {
+        return getItemId(position);
+    }
+
+    public T getTreeId(final int position) {
+        return treeStateManager.getVisibleList().get(position);
+    }
+
+    public TreeNodeInfo<T> getTreeNodeInfo(final int position) {
+        return treeStateManager.getNodeInfo(getTreeId(position));
+    }
+
+    @Override
+    public boolean hasStableIds() { // NOPMD
+        return true;
+    }
+
+    @Override
+    public int getItemViewType(final int position) {
+        return getTreeNodeInfo(position).getLevel();
+    }
+
+    @Override
+    public int getViewTypeCount() {
+        return numberOfLevels;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return getCount() == 0;
+    }
+
+    @Override
+    public boolean areAllItemsEnabled() { // NOPMD
+        return true;
+    }
+
+    @Override
+    public boolean isEnabled(final int position) { // NOPMD
+        return true;
+    }
+
+    protected int getTreeListItemWrapperId() {
+        return R.layout.tree_list_item_wrapper;
+    }
+
+    @Override
+    public final View getView(final int position, final View convertView,
+            final ViewGroup parent) {
+        final TreeNodeInfo<T> nodeInfo = getTreeNodeInfo(position);
+        if (convertView == null) {
+            final LinearLayout layout = (LinearLayout) layoutInflater.inflate(
+                    getTreeListItemWrapperId(), null);
+            return populateTreeItem(layout, getNewChildView(nodeInfo),
+                    nodeInfo, true);
+        } else {
+            final LinearLayout linear = (LinearLayout) convertView;
+            final FrameLayout frameLayout = (FrameLayout) linear
+                    .findViewById(R.id.treeview_list_item_frame);
+            final View childView = frameLayout.getChildAt(0);
+            updateView(childView, nodeInfo);
+            return populateTreeItem(linear, childView, nodeInfo, false);
+        }
+    }
+
+    /**
+     * Called when new view is to be created.
+     * 
+     * @param treeNodeInfo
+     *            node info
+     * @return view that should be displayed as tree content
+     */
+    public abstract View getNewChildView(TreeNodeInfo<T> treeNodeInfo);
+
+    /**
+     * Called when new view is going to be reused. You should update the view
+     * and fill it in with the data required to display the new information. You
+     * can also create a new view, which will mean that the old view will not be
+     * reused.
+     * 
+     * @param view
+     *            view that should be updated with the new values
+     * @param treeNodeInfo
+     *            node info used to populate the view
+     * @return view to used as row indented content
+     */
+    public abstract View updateView(View view, TreeNodeInfo<T> treeNodeInfo);
+
+    /**
+     * Retrieves background drawable for the node.
+     * 
+     * @param treeNodeInfo
+     *            node info
+     * @return drawable returned as background for the whole row. Might be null,
+     *         then default background is used
+     */
+    public Drawable getBackgroundDrawable(final TreeNodeInfo<T> treeNodeInfo) { // NOPMD
+        return null;
+    }
+
+    private Drawable getDrawableOrDefaultBackground(final Drawable r) {
+        if (r == null) {
+            return activity.getResources()
+                    .getDrawable(R.drawable.list_selector_background).mutate();
+        } else {
+            return r;
+        }
+    }
+
+    public final LinearLayout populateTreeItem(final LinearLayout layout,
+            final View childView, final TreeNodeInfo<T> nodeInfo,
+            final boolean newChildView) {
+        final Drawable individualRowDrawable = getBackgroundDrawable(nodeInfo);
+        layout.setBackgroundDrawable(individualRowDrawable == null ? getDrawableOrDefaultBackground(rowBackgroundDrawable)
+                : individualRowDrawable);
+        final LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
+                calculateIndentation(nodeInfo), LayoutParams.FILL_PARENT);
+        final LinearLayout indicatorLayout = (LinearLayout) layout
+                .findViewById(R.id.treeview_list_item_image_layout);
+        indicatorLayout.setGravity(indicatorGravity);
+        indicatorLayout.setLayoutParams(indicatorLayoutParams);
+        final ImageView image = (ImageView) layout
+                .findViewById(R.id.treeview_list_item_image);
+        image.setImageDrawable(getDrawable(nodeInfo));
+        image.setBackgroundDrawable(getDrawableOrDefaultBackground(indicatorBackgroundDrawable));
+        image.setScaleType(ScaleType.CENTER);
+        image.setTag(nodeInfo.getId());
+        if (nodeInfo.isWithChildren() && collapsible) {
+            image.setOnClickListener(indicatorClickListener);
+        } else {
+            image.setOnClickListener(null);
+        }
+        layout.setTag(nodeInfo.getId());
+        final FrameLayout frameLayout = (FrameLayout) layout
+                .findViewById(R.id.treeview_list_item_frame);
+        final FrameLayout.LayoutParams childParams = new FrameLayout.LayoutParams(
+                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
+        if (newChildView) {
+            frameLayout.addView(childView, childParams);
+        }
+        frameLayout.setTag(nodeInfo.getId());
+        return layout;
+    }
+
+    protected int calculateIndentation(final TreeNodeInfo<T> nodeInfo) {
+        return getIndentWidth() * (nodeInfo.getLevel() + (collapsible ? 1 : 0));
+    }
+
+    private Drawable getDrawable(final TreeNodeInfo<T> nodeInfo) {
+        if (!nodeInfo.isWithChildren() || !collapsible) {
+            return getDrawableOrDefaultBackground(indicatorBackgroundDrawable);
+        }
+        if (nodeInfo.isExpanded()) {
+            return expandedDrawable;
+        } else {
+            return collapsedDrawable;
+        }
+    }
+
+    public void setIndicatorGravity(final int indicatorGravity) {
+        this.indicatorGravity = indicatorGravity;
+    }
+
+    public void setCollapsedDrawable(final Drawable collapsedDrawable) {
+        this.collapsedDrawable = collapsedDrawable;
+        calculateIndentWidth();
+    }
+
+    public void setExpandedDrawable(final Drawable expandedDrawable) {
+        this.expandedDrawable = expandedDrawable;
+        calculateIndentWidth();
+    }
+
+    public void setIndentWidth(final int indentWidth) {
+        this.indentWidth = indentWidth;
+        calculateIndentWidth();
+    }
+
+    public void setRowBackgroundDrawable(final Drawable rowBackgroundDrawable) {
+        this.rowBackgroundDrawable = rowBackgroundDrawable;
+    }
+
+    public void setIndicatorBackgroundDrawable(
+            final Drawable indicatorBackgroundDrawable) {
+        this.indicatorBackgroundDrawable = indicatorBackgroundDrawable;
+    }
+
+    public void setCollapsible(final boolean collapsible) {
+        this.collapsible = collapsible;
+    }
+
+    public void refresh() {
+        treeStateManager.refresh();
+    }
+
+    private int getIndentWidth() {
+        return indentWidth;
+    }
+
+    @SuppressWarnings("unchecked")
+    public void handleItemClick(final View view, final Object id) {
+        expandCollapse((T) id);
+    }
+
+}
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/InMemoryTreeNode.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/InMemoryTreeNode.java
new file mode 100644 (file)
index 0000000..6035369
--- /dev/null
@@ -0,0 +1,116 @@
+package pl.polidea.treeview;
+
+import java.io.Serializable;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Node. It is package protected so that it cannot be used outside.
+ * 
+ * @param <T>
+ *            type of the identifier used by the tree
+ */
+class InMemoryTreeNode<T> implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private final T id;
+    private final T parent;
+    private final int level;
+    private boolean visible = true;
+    private final List<InMemoryTreeNode<T>> children = new LinkedList<InMemoryTreeNode<T>>();
+    private List<T> childIdListCache = null;
+
+    public InMemoryTreeNode(final T id, final T parent, final int level,
+            final boolean visible) {
+        super();
+        this.id = id;
+        this.parent = parent;
+        this.level = level;
+        this.visible = visible;
+    }
+
+    public int indexOf(final T id) {
+        return getChildIdList().indexOf(id);
+    }
+
+    /**
+     * Cache is built lasily only if needed. The cache is cleaned on any
+     * structure change for that node!).
+     * 
+     * @return list of ids of children
+     */
+    public synchronized List<T> getChildIdList() {
+        if (childIdListCache == null) {
+            childIdListCache = new LinkedList<T>();
+            for (final InMemoryTreeNode<T> n : children) {
+                childIdListCache.add(n.getId());
+            }
+        }
+        return childIdListCache;
+    }
+
+    public boolean isVisible() {
+        return visible;
+    }
+
+    public void setVisible(final boolean visible) {
+        this.visible = visible;
+    }
+
+    public int getChildrenListSize() {
+        return children.size();
+    }
+
+    public synchronized InMemoryTreeNode<T> add(final int index, final T child,
+            final boolean visible) {
+        childIdListCache = null;
+        // Note! top levell children are always visible (!)
+        final InMemoryTreeNode<T> newNode = new InMemoryTreeNode<T>(child,
+                getId(), getLevel() + 1, getId() == null ? true : visible);
+        children.add(index, newNode);
+        return newNode;
+    }
+
+    /**
+     * Note. This method should technically return unmodifiable collection, but
+     * for performance reason on small devices we do not do it.
+     * 
+     * @return children list
+     */
+    public List<InMemoryTreeNode<T>> getChildren() {
+        return children;
+    }
+
+    public synchronized void clearChildren() {
+        children.clear();
+        childIdListCache = null;
+    }
+
+    public synchronized void removeChild(final T child) {
+        final int childIndex = indexOf(child);
+        if (childIndex != -1) {
+            children.remove(childIndex);
+            childIdListCache = null;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "InMemoryTreeNode [id=" + getId() + ", parent=" + getParent()
+                + ", level=" + getLevel() + ", visible=" + visible
+                + ", children=" + children + ", childIdListCache="
+                + childIdListCache + "]";
+    }
+
+    T getId() {
+        return id;
+    }
+
+    T getParent() {
+        return parent;
+    }
+
+    int getLevel() {
+        return level;
+    }
+
+}
\ No newline at end of file
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/InMemoryTreeStateManager.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/InMemoryTreeStateManager.java
new file mode 100644 (file)
index 0000000..bae675b
--- /dev/null
@@ -0,0 +1,374 @@
+package pl.polidea.treeview;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import android.database.DataSetObserver;
+
+/**
+ * In-memory manager of tree state.
+ * 
+ * @param <T>
+ *            type of identifier
+ */
+public class InMemoryTreeStateManager<T> implements TreeStateManager<T> {
+    private static final long serialVersionUID = 1L;
+    private final Map<T, InMemoryTreeNode<T>> allNodes = new HashMap<T, InMemoryTreeNode<T>>();
+    private final InMemoryTreeNode<T> topSentinel = new InMemoryTreeNode<T>(
+            null, null, -1, true);
+    private transient List<T> visibleListCache = null; // lasy initialised
+    private transient List<T> unmodifiableVisibleList = null;
+    private boolean visibleByDefault = true;
+    private final transient Set<DataSetObserver> observers = new HashSet<DataSetObserver>();
+
+    private synchronized void internalDataSetChanged() {
+        visibleListCache = null;
+        unmodifiableVisibleList = null;
+        for (final DataSetObserver observer : observers) {
+            observer.onChanged();
+        }
+    }
+
+    /**
+     * If true new nodes are visible by default.
+     * 
+     * @param visibleByDefault
+     *            if true, then newly added nodes are expanded by default
+     */
+    public void setVisibleByDefault(final boolean visibleByDefault) {
+        this.visibleByDefault = visibleByDefault;
+    }
+
+    private InMemoryTreeNode<T> getNodeFromTreeOrThrow(final T id) {
+        if (id == null) {
+            throw new NodeNotInTreeException("(null)");
+        }
+        final InMemoryTreeNode<T> node = allNodes.get(id);
+        if (node == null) {
+            throw new NodeNotInTreeException(id.toString());
+        }
+        return node;
+    }
+
+    private InMemoryTreeNode<T> getNodeFromTreeOrThrowAllowRoot(final T id) {
+        if (id == null) {
+            return topSentinel;
+        }
+        return getNodeFromTreeOrThrow(id);
+    }
+
+    private void expectNodeNotInTreeYet(final T id) {
+        final InMemoryTreeNode<T> node = allNodes.get(id);
+        if (node != null) {
+            throw new NodeAlreadyInTreeException(id.toString(), node.toString());
+        }
+    }
+
+    @Override
+    public synchronized TreeNodeInfo<T> getNodeInfo(final T id) {
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrow(id);
+        final List<InMemoryTreeNode<T>> children = node.getChildren();
+        boolean expanded = false;
+        if (!children.isEmpty() && children.get(0).isVisible()) {
+            expanded = true;
+        }
+        return new TreeNodeInfo<T>(id, node.getLevel(), !children.isEmpty(),
+                node.isVisible(), expanded);
+    }
+
+    @Override
+    public synchronized List<T> getChildren(final T id) {
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
+        return node.getChildIdList();
+    }
+
+    @Override
+    public synchronized T getParent(final T id) {
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
+        return node.getParent();
+    }
+
+    private boolean getChildrenVisibility(final InMemoryTreeNode<T> node) {
+        boolean visibility;
+        final List<InMemoryTreeNode<T>> children = node.getChildren();
+        if (children.isEmpty()) {
+            visibility = visibleByDefault;
+        } else {
+            visibility = children.get(0).isVisible();
+        }
+        return visibility;
+    }
+
+    @Override
+    public synchronized void addBeforeChild(final T parent, final T newChild,
+            final T beforeChild) {
+        expectNodeNotInTreeYet(newChild);
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(parent);
+        final boolean visibility = getChildrenVisibility(node);
+        // top nodes are always expanded.
+        if (beforeChild == null) {
+            final InMemoryTreeNode<T> added = node.add(0, newChild, visibility);
+            allNodes.put(newChild, added);
+        } else {
+            final int index = node.indexOf(beforeChild);
+            final InMemoryTreeNode<T> added = node.add(index == -1 ? 0 : index,
+                    newChild, visibility);
+            allNodes.put(newChild, added);
+        }
+        if (visibility) {
+            internalDataSetChanged();
+        }
+    }
+
+    @Override
+    public synchronized void addAfterChild(final T parent, final T newChild,
+            final T afterChild) {
+        expectNodeNotInTreeYet(newChild);
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(parent);
+        final boolean visibility = getChildrenVisibility(node);
+        if (afterChild == null) {
+            final InMemoryTreeNode<T> added = node.add(
+                    node.getChildrenListSize(), newChild, visibility);
+            allNodes.put(newChild, added);
+        } else {
+            final int index = node.indexOf(afterChild);
+            final InMemoryTreeNode<T> added = node.add(
+                    index == -1 ? node.getChildrenListSize() : index, newChild,
+                    visibility);
+            allNodes.put(newChild, added);
+        }
+        if (visibility) {
+            internalDataSetChanged();
+        }
+    }
+
+    @Override
+    public synchronized void removeNodeRecursively(final T id) {
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
+        final boolean visibleNodeChanged = removeNodeRecursively(node);
+        final T parent = node.getParent();
+        final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
+        parentNode.removeChild(id);
+        if (visibleNodeChanged) {
+            internalDataSetChanged();
+        }
+    }
+
+    private boolean removeNodeRecursively(final InMemoryTreeNode<T> node) {
+        boolean visibleNodeChanged = false;
+        for (final InMemoryTreeNode<T> child : node.getChildren()) {
+            if (removeNodeRecursively(child)) {
+                visibleNodeChanged = true;
+            }
+        }
+        node.clearChildren();
+        if (node.getId() != null) {
+            allNodes.remove(node.getId());
+            if (node.isVisible()) {
+                visibleNodeChanged = true;
+            }
+        }
+        return visibleNodeChanged;
+    }
+
+    private void setChildrenVisibility(final InMemoryTreeNode<T> node,
+            final boolean visible, final boolean recursive) {
+        for (final InMemoryTreeNode<T> child : node.getChildren()) {
+            child.setVisible(visible);
+            if (recursive) {
+                setChildrenVisibility(child, visible, true);
+            }
+        }
+    }
+
+    @Override
+    public synchronized void expandDirectChildren(final T id) {
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
+        setChildrenVisibility(node, true, false);
+        internalDataSetChanged();
+    }
+
+    @Override
+    public synchronized void expandEverythingBelow(final T id) {
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
+        setChildrenVisibility(node, true, true);
+        internalDataSetChanged();
+    }
+
+    @Override
+    public synchronized void collapseChildren(final T id) {
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
+        if (node == topSentinel) {
+            for (final InMemoryTreeNode<T> n : topSentinel.getChildren()) {
+                setChildrenVisibility(n, false, true);
+            }
+        } else {
+            setChildrenVisibility(node, false, true);
+        }
+        internalDataSetChanged();
+    }
+
+    @Override
+    public synchronized T getNextSibling(final T id) {
+        final T parent = getParent(id);
+        final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
+        boolean returnNext = false;
+        for (final InMemoryTreeNode<T> child : parentNode.getChildren()) {
+            if (returnNext) {
+                return child.getId();
+            }
+            if (child.getId().equals(id)) {
+                returnNext = true;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public synchronized T getPreviousSibling(final T id) {
+        final T parent = getParent(id);
+        final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
+        final T previousSibling = null;
+        for (final InMemoryTreeNode<T> child : parentNode.getChildren()) {
+            if (child.getId().equals(id)) {
+                return previousSibling;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public synchronized boolean isInTree(final T id) {
+        return allNodes.containsKey(id);
+    }
+
+    @Override
+    public synchronized int getVisibleCount() {
+        return getVisibleList().size();
+    }
+
+    @Override
+    public synchronized List<T> getVisibleList() {
+        T currentId = null;
+        if (visibleListCache == null) {
+            visibleListCache = new ArrayList<T>(allNodes.size());
+            do {
+                currentId = getNextVisible(currentId);
+                if (currentId == null) {
+                    break;
+                } else {
+                    visibleListCache.add(currentId);
+                }
+            } while (true);
+        }
+        if (unmodifiableVisibleList == null) {
+            unmodifiableVisibleList = Collections
+                    .unmodifiableList(visibleListCache);
+        }
+        return unmodifiableVisibleList;
+    }
+
+    public synchronized T getNextVisible(final T id) {
+        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
+        if (!node.isVisible()) {
+            return null;
+        }
+        final List<InMemoryTreeNode<T>> children = node.getChildren();
+        if (!children.isEmpty()) {
+            final InMemoryTreeNode<T> firstChild = children.get(0);
+            if (firstChild.isVisible()) {
+                return firstChild.getId();
+            }
+        }
+        final T sibl = getNextSibling(id);
+        if (sibl != null) {
+            return sibl;
+        }
+        T parent = node.getParent();
+        do {
+            if (parent == null) {
+                return null;
+            }
+            final T parentSibling = getNextSibling(parent);
+            if (parentSibling != null) {
+                return parentSibling;
+            }
+            parent = getNodeFromTreeOrThrow(parent).getParent();
+        } while (true);
+    }
+
+    @Override
+    public synchronized void registerDataSetObserver(
+            final DataSetObserver observer) {
+        observers.add(observer);
+    }
+
+    @Override
+    public synchronized void unregisterDataSetObserver(
+            final DataSetObserver observer) {
+        observers.remove(observer);
+    }
+
+    @Override
+    public int getLevel(final T id) {
+        return getNodeFromTreeOrThrow(id).getLevel();
+    }
+
+    @Override
+    public Integer[] getHierarchyDescription(final T id) {
+        final int level = getLevel(id);
+        final Integer[] hierarchy = new Integer[level + 1];
+        int currentLevel = level;
+        T currentId = id;
+        T parent = getParent(currentId);
+        while (currentLevel >= 0) {
+            hierarchy[currentLevel--] = getChildren(parent).indexOf(currentId);
+            currentId = parent;
+            parent = getParent(parent);
+        }
+        return hierarchy;
+    }
+
+    private void appendToSb(final StringBuilder sb, final T id) {
+        if (id != null) {
+            final TreeNodeInfo<T> node = getNodeInfo(id);
+            final int indent = node.getLevel() * 4;
+            final char[] indentString = new char[indent];
+            Arrays.fill(indentString, ' ');
+            sb.append(indentString);
+            sb.append(node.toString());
+            sb.append(Arrays.asList(getHierarchyDescription(id)).toString());
+            sb.append("\n");
+        }
+        final List<T> children = getChildren(id);
+        for (final T child : children) {
+            appendToSb(sb, child);
+        }
+    }
+
+    @Override
+    public synchronized String toString() {
+        final StringBuilder sb = new StringBuilder();
+        appendToSb(sb, null);
+        return sb.toString();
+    }
+
+    @Override
+    public synchronized void clear() {
+        allNodes.clear();
+        topSentinel.clearChildren();
+        internalDataSetChanged();
+    }
+
+    @Override
+    public void refresh() {
+        internalDataSetChanged();
+    }
+
+}
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/NodeAlreadyInTreeException.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/NodeAlreadyInTreeException.java
new file mode 100644 (file)
index 0000000..680d026
--- /dev/null
@@ -0,0 +1,14 @@
+package pl.polidea.treeview;
+
+/**
+ * The node being added is already in the tree.
+ * 
+ */
+public class NodeAlreadyInTreeException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+
+    public NodeAlreadyInTreeException(final String id, final String oldNode) {
+        super("The node has already been added to the tree: " + id + ". Old node is:" + oldNode);
+    }
+
+}
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/NodeNotInTreeException.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/NodeNotInTreeException.java
new file mode 100644 (file)
index 0000000..f20450e
--- /dev/null
@@ -0,0 +1,15 @@
+package pl.polidea.treeview;
+
+/**
+ * This exception is thrown when the tree does not contain node requested.
+ * 
+ */
+public class NodeNotInTreeException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public NodeNotInTreeException(final String id) {
+        super("The tree does not contain the node specified: " + id);
+    }
+
+}
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeBuilder.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeBuilder.java
new file mode 100644 (file)
index 0000000..13b499c
--- /dev/null
@@ -0,0 +1,126 @@
+package pl.polidea.treeview;
+
+import android.util.Log;
+
+/**
+ * Allows to build tree easily in sequential mode (you have to know levels of
+ * all the tree elements upfront). You should rather use this class rather than
+ * manager if you build initial tree from some external data source.
+ * 
+ * @param <T>
+ */
+public class TreeBuilder<T> {
+    private static final String TAG = TreeBuilder.class.getSimpleName();
+
+    private final TreeStateManager<T> manager;
+
+    private T lastAddedId = null;
+    private int lastLevel = -1;
+
+    public TreeBuilder(final TreeStateManager<T> manager) {
+        this.manager = manager;
+    }
+
+    public void clear() {
+        manager.clear();
+    }
+
+    /**
+     * Adds new relation to existing tree. Child is set as the last child of the
+     * parent node. Parent has to already exist in the tree, child cannot yet
+     * exist. This method is mostly useful in case you add entries layer by
+     * layer - i.e. first top level entries, then children for all parents, then
+     * grand-children and so on.
+     * 
+     * @param parent
+     *            parent id
+     * @param child
+     *            child id
+     */
+    public synchronized void addRelation(final T parent, final T child) {
+        Log.d(TAG, "Adding relation parent:" + parent + " -> child: " + child);
+        manager.addAfterChild(parent, child, null);
+        lastAddedId = child;
+        lastLevel = manager.getLevel(child);
+    }
+
+    /**
+     * Adds sequentially new node. Using this method is the simplest way of
+     * building tree - if you have all the elements in the sequence as they
+     * should be displayed in fully-expanded tree. You can combine it with add
+     * relation - for example you can add information about few levels using
+     * {@link addRelation} and then after the right level is added as parent,
+     * you can continue adding them using sequential operation.
+     * 
+     * @param id
+     *            id of the node
+     * @param level
+     *            its level
+     */
+    public synchronized void sequentiallyAddNextNode(final T id, final int level) {
+        Log.d(TAG, "Adding sequentiall node " + id + " at level " + level);
+        if (lastAddedId == null) {
+            addNodeToParentOneLevelDown(null, id, level);
+        } else {
+            if (level <= lastLevel) {
+                final T parent = findParentAtLevel(lastAddedId, level - 1);
+                addNodeToParentOneLevelDown(parent, id, level);
+            } else {
+                addNodeToParentOneLevelDown(lastAddedId, id, level);
+            }
+        }
+    }
+
+    /**
+     * Find parent of the node at the level specified.
+     * 
+     * @param node
+     *            node from which we start
+     * @param levelToFind
+     *            level which we are looking for
+     * @return the node found (null if it is topmost node).
+     */
+    private T findParentAtLevel(final T node, final int levelToFind) {
+        T parent = manager.getParent(node);
+        while (parent != null) {
+            if (manager.getLevel(parent) == levelToFind) {
+                break;
+            }
+            parent = manager.getParent(parent);
+        }
+        return parent;
+    }
+
+    /**
+     * Adds note to parent at the level specified. But it verifies that the
+     * level is one level down than the parent!
+     * 
+     * @param parent
+     *            parent parent
+     * @param id
+     *            new node id
+     * @param level
+     *            should always be parent's level + 1
+     */
+    private void addNodeToParentOneLevelDown(final T parent, final T id,
+            final int level) {
+        if (parent == null && level != 0) {
+            throw new TreeConfigurationException("Trying to add new id " + id
+                    + " to top level with level != 0 (" + level + ")");
+        }
+        if (parent != null && manager.getLevel(parent) != level - 1) {
+            throw new TreeConfigurationException("Trying to add new id " + id
+                    + " <" + level + "> to " + parent + " <"
+                    + manager.getLevel(parent)
+                    + ">. The difference in levels up is bigger than 1.");
+        }
+        manager.addAfterChild(parent, id, null);
+        setLastAdded(id, level);
+    }
+
+    private void setLastAdded(final T id, final int level) {
+        lastAddedId = id;
+        lastLevel = level;
+    }
+
+}
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeConfigurationException.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeConfigurationException.java
new file mode 100644 (file)
index 0000000..1fa72e0
--- /dev/null
@@ -0,0 +1,15 @@
+package pl.polidea.treeview;
+
+/**
+ * Exception thrown when there is a problem with configuring tree.
+ * 
+ */
+public class TreeConfigurationException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    public TreeConfigurationException(final String detailMessage) {
+        super(detailMessage);
+    }
+
+}
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeNodeInfo.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeNodeInfo.java
new file mode 100644 (file)
index 0000000..32d18dd
--- /dev/null
@@ -0,0 +1,69 @@
+package pl.polidea.treeview;
+
+/**
+ * Information about the node.
+ * 
+ * @param <T>
+ *            type of the id for the tree
+ */
+public class TreeNodeInfo<T> {
+    private final T id;
+    private final int level;
+    private final boolean withChildren;
+    private final boolean visible;
+    private final boolean expanded;
+
+    /**
+     * Creates the node information.
+     * 
+     * @param id
+     *            id of the node
+     * @param level
+     *            level of the node
+     * @param withChildren
+     *            whether the node has children.
+     * @param visible
+     *            whether the tree node is visible.
+     * @param expanded
+     *            whether the tree node is expanded
+     * 
+     */
+    public TreeNodeInfo(final T id, final int level,
+            final boolean withChildren, final boolean visible,
+            final boolean expanded) {
+        super();
+        this.id = id;
+        this.level = level;
+        this.withChildren = withChildren;
+        this.visible = visible;
+        this.expanded = expanded;
+    }
+
+    public T getId() {
+        return id;
+    }
+
+    public boolean isWithChildren() {
+        return withChildren;
+    }
+
+    public boolean isVisible() {
+        return visible;
+    }
+
+    public boolean isExpanded() {
+        return expanded;
+    }
+
+    public int getLevel() {
+        return level;
+    }
+
+    @Override
+    public String toString() {
+        return "TreeNodeInfo [id=" + id + ", level=" + level
+                + ", withChildren=" + withChildren + ", visible=" + visible
+                + ", expanded=" + expanded + "]";
+    }
+
+}
\ No newline at end of file
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeStateManager.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeStateManager.java
new file mode 100644 (file)
index 0000000..781b70e
--- /dev/null
@@ -0,0 +1,193 @@
+package pl.polidea.treeview;
+
+import java.io.Serializable;
+import java.util.List;
+
+import android.database.DataSetObserver;
+
+/**
+ * Manages information about state of the tree. It only keeps information about
+ * tree elements, not the elements themselves.
+ * 
+ * @param <T>
+ *            type of the identifier for nodes in the tree
+ */
+public interface TreeStateManager<T> extends Serializable {
+
+    /**
+     * Returns array of integers showing the location of the node in hierarchy.
+     * It corresponds to heading numbering. {0,0,0} in 3 level node is the first
+     * node {0,0,1} is second leaf (assuming that there are two leaves in first
+     * subnode of the first node).
+     * 
+     * @param id
+     *            id of the node
+     * @return textual description of the hierarchy in tree for the node.
+     */
+    Integer[] getHierarchyDescription(T id);
+
+    /**
+     * Returns level of the node.
+     * 
+     * @param id
+     *            id of the node
+     * @return level in the tree
+     */
+    int getLevel(T id);
+
+    /**
+     * Returns information about the node.
+     * 
+     * @param id
+     *            node id
+     * @return node info
+     */
+    TreeNodeInfo<T> getNodeInfo(T id);
+
+    /**
+     * Returns children of the node.
+     * 
+     * @param id
+     *            id of the node or null if asking for top nodes
+     * @return children of the node
+     */
+    List<T> getChildren(T id);
+
+    /**
+     * Returns parent of the node.
+     * 
+     * @param id
+     *            id of the node
+     * @return parent id or null if no parent
+     */
+    T getParent(T id);
+
+    /**
+     * Adds the node before child or at the beginning.
+     * 
+     * @param parent
+     *            id of the parent node. If null - adds at the top level
+     * @param newChild
+     *            new child to add if null - adds at the beginning.
+     * @param beforeChild
+     *            child before which to add the new child
+     */
+    void addBeforeChild(T parent, T newChild, T beforeChild);
+
+    /**
+     * Adds the node after child or at the end.
+     * 
+     * @param parent
+     *            id of the parent node. If null - adds at the top level.
+     * @param newChild
+     *            new child to add. If null - adds at the end.
+     * @param afterChild
+     *            child after which to add the new child
+     */
+    void addAfterChild(T parent, T newChild, T afterChild);
+
+    /**
+     * Removes the node and all children from the tree.
+     * 
+     * @param id
+     *            id of the node to remove or null if all nodes are to be
+     *            removed.
+     */
+    void removeNodeRecursively(T id);
+
+    /**
+     * Expands all children of the node.
+     * 
+     * @param id
+     *            node which children should be expanded. cannot be null (top
+     *            nodes are always expanded!).
+     */
+    void expandDirectChildren(T id);
+
+    /**
+     * Expands everything below the node specified. Might be null - then expands
+     * all.
+     * 
+     * @param id
+     *            node which children should be expanded or null if all nodes
+     *            are to be expanded.
+     */
+    void expandEverythingBelow(T id);
+
+    /**
+     * Collapse children.
+     * 
+     * @param id
+     *            id collapses everything below node specified. If null,
+     *            collapses everything but top-level nodes.
+     */
+    void collapseChildren(T id);
+
+    /**
+     * Returns next sibling of the node (or null if no further sibling).
+     * 
+     * @param id
+     *            node id
+     * @return the sibling (or null if no next)
+     */
+    T getNextSibling(T id);
+
+    /**
+     * Returns previous sibling of the node (or null if no previous sibling).
+     * 
+     * @param id
+     *            node id
+     * @return the sibling (or null if no previous)
+     */
+    T getPreviousSibling(T id);
+
+    /**
+     * Checks if given node is already in tree.
+     * 
+     * @param id
+     *            id of the node
+     * @return true if node is already in tree.
+     */
+    boolean isInTree(T id);
+
+    /**
+     * Count visible elements.
+     * 
+     * @return number of currently visible elements.
+     */
+    int getVisibleCount();
+
+    /**
+     * Returns visible node list.
+     * 
+     * @return return the list of all visible nodes in the right sequence
+     */
+    List<T> getVisibleList();
+
+    /**
+     * Registers observers with the manager.
+     * 
+     * @param observer
+     *            observer
+     */
+    void registerDataSetObserver(final DataSetObserver observer);
+
+    /**
+     * Unregisters observers with the manager.
+     * 
+     * @param observer
+     *            observer
+     */
+    void unregisterDataSetObserver(final DataSetObserver observer);
+
+    /**
+     * Cleans tree stored in manager. After this operation the tree is empty.
+     * 
+     */
+    void clear();
+
+    /**
+     * Refreshes views connected to the manager.
+     */
+    void refresh();
+}
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeViewList.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/TreeViewList.java
new file mode 100644 (file)
index 0000000..fb48ab5
--- /dev/null
@@ -0,0 +1,198 @@
+package pl.polidea.treeview;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+/**
+ * Tree view, expandable multi-level.
+ * 
+ * <pre>
+ * attr ref pl.polidea.treeview.R.styleable#TreeViewList_collapsible
+ * attr ref pl.polidea.treeview.R.styleable#TreeViewList_src_expanded
+ * attr ref pl.polidea.treeview.R.styleable#TreeViewList_src_collapsed
+ * attr ref pl.polidea.treeview.R.styleable#TreeViewList_indent_width
+ * attr ref pl.polidea.treeview.R.styleable#TreeViewList_handle_trackball_press
+ * attr ref pl.polidea.treeview.R.styleable#TreeViewList_indicator_gravity
+ * attr ref pl.polidea.treeview.R.styleable#TreeViewList_indicator_background
+ * attr ref pl.polidea.treeview.R.styleable#TreeViewList_row_background
+ * </pre>
+ */
+public class TreeViewList extends ListView {
+    private static final int DEFAULT_COLLAPSED_RESOURCE = R.drawable.collapsed;
+    private static final int DEFAULT_EXPANDED_RESOURCE = R.drawable.expanded;
+    private static final int DEFAULT_INDENT = 0;
+    private static final int DEFAULT_GRAVITY = Gravity.LEFT
+            | Gravity.CENTER_VERTICAL;
+    private Drawable expandedDrawable;
+    private Drawable collapsedDrawable;
+    private Drawable rowBackgroundDrawable;
+    private Drawable indicatorBackgroundDrawable;
+    private int indentWidth = 0;
+    private int indicatorGravity = 0;
+    private AbstractTreeViewAdapter< ? > treeAdapter;
+    private boolean collapsible;
+    private boolean handleTrackballPress;
+
+    public TreeViewList(final Context context, final AttributeSet attrs) {
+        this(context, attrs, R.style.treeViewListStyle);
+    }
+
+    public TreeViewList(final Context context) {
+        this(context, null);
+    }
+
+    public TreeViewList(final Context context, final AttributeSet attrs,
+            final int defStyle) {
+        super(context, attrs, defStyle);
+        parseAttributes(context, attrs);
+    }
+
+    private void parseAttributes(final Context context, final AttributeSet attrs) {
+        final TypedArray a = context.obtainStyledAttributes(attrs,
+                R.styleable.TreeViewList);
+        expandedDrawable = a.getDrawable(R.styleable.TreeViewList_src_expanded);
+        if (expandedDrawable == null) {
+            expandedDrawable = context.getResources().getDrawable(
+                    DEFAULT_EXPANDED_RESOURCE);
+        }
+        collapsedDrawable = a
+                .getDrawable(R.styleable.TreeViewList_src_collapsed);
+        if (collapsedDrawable == null) {
+            collapsedDrawable = context.getResources().getDrawable(
+                    DEFAULT_COLLAPSED_RESOURCE);
+        }
+        indentWidth = a.getDimensionPixelSize(
+                R.styleable.TreeViewList_indent_width, DEFAULT_INDENT);
+        indicatorGravity = a.getInteger(
+                R.styleable.TreeViewList_indicator_gravity, DEFAULT_GRAVITY);
+        indicatorBackgroundDrawable = a
+                .getDrawable(R.styleable.TreeViewList_indicator_background);
+        rowBackgroundDrawable = a
+                .getDrawable(R.styleable.TreeViewList_row_background);
+        collapsible = a.getBoolean(R.styleable.TreeViewList_collapsible, true);
+        handleTrackballPress = a.getBoolean(
+                R.styleable.TreeViewList_handle_trackball_press, true);
+    }
+
+    @Override
+    public void setAdapter(final ListAdapter adapter) {
+        if (!(adapter instanceof AbstractTreeViewAdapter)) {
+            throw new TreeConfigurationException(
+                    "The adapter is not of TreeViewAdapter type");
+        }
+        treeAdapter = (AbstractTreeViewAdapter< ? >) adapter;
+        syncAdapter();
+        super.setAdapter(treeAdapter);
+    }
+
+    private void syncAdapter() {
+        treeAdapter.setCollapsedDrawable(collapsedDrawable);
+        treeAdapter.setExpandedDrawable(expandedDrawable);
+        treeAdapter.setIndicatorGravity(indicatorGravity);
+        treeAdapter.setIndentWidth(indentWidth);
+        treeAdapter.setIndicatorBackgroundDrawable(indicatorBackgroundDrawable);
+        treeAdapter.setRowBackgroundDrawable(rowBackgroundDrawable);
+        treeAdapter.setCollapsible(collapsible);
+        if (handleTrackballPress) {
+            setOnItemClickListener(new OnItemClickListener() {
+                @Override
+                public void onItemClick(final AdapterView< ? > parent,
+                        final View view, final int position, final long id) {
+                    treeAdapter.handleItemClick(view, view.getTag());
+                }
+            });
+        } else {
+            setOnClickListener(null);
+        }
+
+    }
+
+    public void setExpandedDrawable(final Drawable expandedDrawable) {
+        this.expandedDrawable = expandedDrawable;
+        syncAdapter();
+        treeAdapter.refresh();
+    }
+
+    public void setCollapsedDrawable(final Drawable collapsedDrawable) {
+        this.collapsedDrawable = collapsedDrawable;
+        syncAdapter();
+        treeAdapter.refresh();
+    }
+
+    public void setRowBackgroundDrawable(final Drawable rowBackgroundDrawable) {
+        this.rowBackgroundDrawable = rowBackgroundDrawable;
+        syncAdapter();
+        treeAdapter.refresh();
+    }
+
+    public void setIndicatorBackgroundDrawable(
+            final Drawable indicatorBackgroundDrawable) {
+        this.indicatorBackgroundDrawable = indicatorBackgroundDrawable;
+        syncAdapter();
+        treeAdapter.refresh();
+    }
+
+    public void setIndentWidth(final int indentWidth) {
+        this.indentWidth = indentWidth;
+        syncAdapter();
+        treeAdapter.refresh();
+    }
+
+    public void setIndicatorGravity(final int indicatorGravity) {
+        this.indicatorGravity = indicatorGravity;
+        syncAdapter();
+        treeAdapter.refresh();
+    }
+
+    public void setCollapsible(final boolean collapsible) {
+        this.collapsible = collapsible;
+        syncAdapter();
+        treeAdapter.refresh();
+    }
+
+    public void setHandleTrackballPress(final boolean handleTrackballPress) {
+        this.handleTrackballPress = handleTrackballPress;
+        syncAdapter();
+        treeAdapter.refresh();
+    }
+
+    public Drawable getExpandedDrawable() {
+        return expandedDrawable;
+    }
+
+    public Drawable getCollapsedDrawable() {
+        return collapsedDrawable;
+    }
+
+    public Drawable getRowBackgroundDrawable() {
+        return rowBackgroundDrawable;
+    }
+
+    public Drawable getIndicatorBackgroundDrawable() {
+        return indicatorBackgroundDrawable;
+    }
+
+    public int getIndentWidth() {
+        return indentWidth;
+    }
+
+    public int getIndicatorGravity() {
+        return indicatorGravity;
+    }
+
+    public boolean isCollapsible() {
+        return collapsible;
+    }
+
+    public boolean isHandleTrackballPress() {
+        return handleTrackballPress;
+    }
+
+}
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/overview.html b/android-libraries/TreeViewList/src/pl/polidea/treeview/overview.html
new file mode 100644 (file)
index 0000000..bdd09ce
--- /dev/null
@@ -0,0 +1,24 @@
+<html>
+<body>
+This is a small utility that provides quite configurable tree view list.
+It is based on standard android list view. It separates out different
+aspects of the tree: there is a separate list view, tree adapter, tree
+state manager and tree state builder.
+<p>
+<ul>
+       <li>Tree view provides the frame to display the view.</li>
+       <li>Adapter allows to create visual representation of each tree
+       node.</li>
+       <li>State manager provides storage for tree state (connections
+       between parents and children, collapsed/expanded state). It provides
+       all the low-level tree manipulation methods.</li>
+       <li>Tree builder allows to build tree easily providing higher
+       level methods. The tree can be build either from prepared sequentially
+       prepared list of nodes (node id, level) or using (parent/child
+       relationships).</li>
+       <p>For now only in-memory state manager is provided, but Tree State
+       Manger interface is done in the way that database tree manager even for
+       large trees is potentially supported.
+</ul>
+</body>
+</html>
\ No newline at end of file
diff --git a/android-libraries/TreeViewList/src/pl/polidea/treeview/package-info.java b/android-libraries/TreeViewList/src/pl/polidea/treeview/package-info.java
new file mode 100644 (file)
index 0000000..a622e09
--- /dev/null
@@ -0,0 +1,4 @@
+/**
+ * Provides expandable Tree View implementation.
+ */
+package pl.polidea.treeview;
\ No newline at end of file
diff --git a/android-libraries/achartengine/.classpath b/android-libraries/achartengine/.classpath
new file mode 100644 (file)
index 0000000..a4f1e40
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="src" path="gen"/>\r
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>\r
+       <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
+       <classpathentry kind="output" path="bin/classes"/>\r
+</classpath>\r
diff --git a/android-libraries/achartengine/.project b/android-libraries/achartengine/.project
new file mode 100644 (file)
index 0000000..fb1c756
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>achartengine</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>com.android.ide.eclipse.adt.ApkBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>com.android.ide.eclipse.adt.AndroidNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/android-libraries/achartengine/AndroidManifest.xml b/android-libraries/achartengine/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..083e05f
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="org.achartengine.chartdemo.demo"
+      android:versionCode="1"
+      android:versionName="1.0.0">
+
+<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="7"></uses-sdk>
+</manifest> 
\ No newline at end of file
diff --git a/android-libraries/achartengine/extra/LICENSE-2.0.txt b/android-libraries/achartengine/extra/LICENSE-2.0.txt
new file mode 100644 (file)
index 0000000..d645695
--- /dev/null
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/android-libraries/achartengine/project.properties b/android-libraries/achartengine/project.properties
new file mode 100644 (file)
index 0000000..337e8f3
--- /dev/null
@@ -0,0 +1,12 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-7
+android.library=true
diff --git a/android-libraries/achartengine/src/org/achartengine/ChartFactory.java b/android-libraries/achartengine/src/org/achartengine/ChartFactory.java
new file mode 100644 (file)
index 0000000..301f1a8
--- /dev/null
@@ -0,0 +1,708 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.BarChart;\r
+import org.achartengine.chart.BarChart.Type;\r
+import org.achartengine.chart.BubbleChart;\r
+import org.achartengine.chart.CombinedXYChart;\r
+import org.achartengine.chart.CubicLineChart;\r
+import org.achartengine.chart.DialChart;\r
+import org.achartengine.chart.DoughnutChart;\r
+import org.achartengine.chart.LineChart;\r
+import org.achartengine.chart.PieChart;\r
+import org.achartengine.chart.RangeBarChart;\r
+import org.achartengine.chart.ScatterChart;\r
+import org.achartengine.chart.TimeChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.model.CategorySeries;\r
+import org.achartengine.model.MultipleCategorySeries;\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.DialRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.content.Context;\r
+import android.content.Intent;\r
+\r
+/**\r
+ * Utility methods for creating chart views or intents.\r
+ */\r
+public class ChartFactory {\r
+  /** The key for the chart data. */\r
+  public static final String CHART = "chart";\r
+\r
+  /** The key for the chart graphical activity title. */\r
+  public static final String TITLE = "title";\r
+\r
+  private ChartFactory() {\r
+    // empty for now\r
+  }\r
+\r
+  /**\r
+   * Creates a line chart view.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @return a line chart graphical view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final GraphicalView getLineChartView(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    checkParameters(dataset, renderer);\r
+    XYChart chart = new LineChart(dataset, renderer);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a cubic line chart view.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @return a line chart graphical view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final GraphicalView getCubeLineChartView(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness) {\r
+    checkParameters(dataset, renderer);\r
+    XYChart chart = new CubicLineChart(dataset, renderer, smoothness);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a scatter chart view.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @return a scatter chart graphical view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final GraphicalView getScatterChartView(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    checkParameters(dataset, renderer);\r
+    XYChart chart = new ScatterChart(dataset, renderer);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a bubble chart view.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @return a scatter chart graphical view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final GraphicalView getBubbleChartView(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    checkParameters(dataset, renderer);\r
+    XYChart chart = new BubbleChart(dataset, renderer);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a time chart view.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param format the date format pattern to be used for displaying the X axis\r
+   *          date labels. If null, a default appropriate format will be used.\r
+   * @return a time chart graphical view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final GraphicalView getTimeChartView(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String format) {\r
+    checkParameters(dataset, renderer);\r
+    TimeChart chart = new TimeChart(dataset, renderer);\r
+    chart.setDateFormat(format);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a bar chart view.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param type the bar chart type\r
+   * @return a bar chart graphical view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final GraphicalView getBarChartView(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+    checkParameters(dataset, renderer);\r
+    XYChart chart = new BarChart(dataset, renderer, type);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a range bar chart view.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param type the range bar chart type\r
+   * @return a bar chart graphical view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final GraphicalView getRangeBarChartView(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+    checkParameters(dataset, renderer);\r
+    XYChart chart = new RangeBarChart(dataset, renderer, type);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a combined XY chart view.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param types the chart types (cannot be null)\r
+   * @return a combined XY chart graphical view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if a dataset number of items is different than the number of\r
+   *           series renderers or number of chart types\r
+   */\r
+  public static final GraphicalView getCombinedXYChartView(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String[] types) {\r
+    if (dataset == null || renderer == null || types == null\r
+        || dataset.getSeriesCount() != types.length) {\r
+      throw new IllegalArgumentException(\r
+          "Dataset, renderer and types should be not null and the datasets series count should be equal to the types length");\r
+    }\r
+    checkParameters(dataset, renderer);\r
+    CombinedXYChart chart = new CombinedXYChart(dataset, renderer, types);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a pie chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the category series dataset (cannot be null)\r
+   * @param renderer the series renderer (cannot be null)\r
+   * @return a pie chart view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset number of items is different than the number of\r
+   *           series renderers\r
+   */\r
+  public static final GraphicalView getPieChartView(Context context, CategorySeries dataset,\r
+      DefaultRenderer renderer) {\r
+    checkParameters(dataset, renderer);\r
+    PieChart chart = new PieChart(dataset, renderer);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a dial chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the category series dataset (cannot be null)\r
+   * @param renderer the dial renderer (cannot be null)\r
+   * @return a pie chart view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset number of items is different than the number of\r
+   *           series renderers\r
+   */\r
+  public static final GraphicalView getDialChartView(Context context, CategorySeries dataset,\r
+      DialRenderer renderer) {\r
+    checkParameters(dataset, renderer);\r
+    DialChart chart = new DialChart(dataset, renderer);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * Creates a doughnut chart intent that can be used to start the graphical\r
+   * view activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple category series dataset (cannot be null)\r
+   * @param renderer the series renderer (cannot be null)\r
+   * @return a pie chart view\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset number of items is different than the number of\r
+   *           series renderers\r
+   */\r
+  public static final GraphicalView getDoughnutChartView(Context context,\r
+      MultipleCategorySeries dataset, DefaultRenderer renderer) {\r
+    checkParameters(dataset, renderer);\r
+    DoughnutChart chart = new DoughnutChart(dataset, renderer);\r
+    return new GraphicalView(context, chart);\r
+  }\r
+\r
+  /**\r
+   * \r
+   * Creates a line chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @return a line chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer) {\r
+    return getLineChartIntent(context, dataset, renderer, "");\r
+  }\r
+\r
+  /**\r
+   * \r
+   * Creates a cubic line chart intent that can be used to start the graphical\r
+   * view activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @return a line chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getCubicLineChartIntent(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness) {\r
+    return getCubicLineChartIntent(context, dataset, renderer, smoothness, "");\r
+  }\r
+\r
+  /**\r
+   * Creates a scatter chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @return a scatter chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getScatterChartIntent(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    return getScatterChartIntent(context, dataset, renderer, "");\r
+  }\r
+\r
+  /**\r
+   * Creates a bubble chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @return a scatter chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getBubbleChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer) {\r
+    return getBubbleChartIntent(context, dataset, renderer, "");\r
+  }\r
+\r
+  /**\r
+   * Creates a time chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param format the date format pattern to be used for displaying the X axis\r
+   *          date labels. If null, a default appropriate format will be used.\r
+   * @return a time chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getTimeChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer, String format) {\r
+    return getTimeChartIntent(context, dataset, renderer, format, "");\r
+  }\r
+\r
+  /**\r
+   * Creates a bar chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param type the bar chart type\r
+   * @return a bar chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getBarChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer, Type type) {\r
+    return getBarChartIntent(context, dataset, renderer, type, "");\r
+  }\r
+\r
+  /**\r
+   * Creates a line chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param activityTitle the graphical chart activity title. If this is null,\r
+   *          then the title bar will be hidden. If a blank title is passed in,\r
+   *          then the title bar will be the default. Pass in any other string\r
+   *          to set a custom title.\r
+   * @return a line chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getLineChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer, String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    XYChart chart = new LineChart(dataset, renderer);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a line chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param activityTitle the graphical chart activity title. If this is null,\r
+   *          then the title bar will be hidden. If a blank title is passed in,\r
+   *          then the title bar will be the default. Pass in any other string\r
+   *          to set a custom title.\r
+   * @return a line chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getCubicLineChartIntent(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, float smoothness,\r
+      String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    XYChart chart = new CubicLineChart(dataset, renderer, smoothness);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a scatter chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a scatter chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getScatterChartIntent(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    XYChart chart = new ScatterChart(dataset, renderer);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a bubble chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a scatter chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getBubbleChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer, String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    XYChart chart = new BubbleChart(dataset, renderer);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a time chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param format the date format pattern to be used for displaying the X axis\r
+   *          date labels. If null, a default appropriate format will be used\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a time chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getTimeChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer, String format, String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    TimeChart chart = new TimeChart(dataset, renderer);\r
+    chart.setDateFormat(format);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a bar chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param type the bar chart type\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a bar chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getBarChartIntent(Context context, XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer, Type type, String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    BarChart chart = new BarChart(dataset, renderer, type);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a range bar chart intent that can be used to start the graphical\r
+   * view activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param type the range bar chart type\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a range bar chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  public static final Intent getRangeBarChartIntent(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type,\r
+      String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    RangeBarChart chart = new RangeBarChart(dataset, renderer, type);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a combined XY chart intent that can be used to start the graphical\r
+   * view activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @param types the chart types (cannot be null)\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a combined XY chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if a dataset number of items is different than the number of\r
+   *           series renderers or number of chart types\r
+   */\r
+  public static final Intent getCombinedXYChartIntent(Context context,\r
+      XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, String[] types,\r
+      String activityTitle) {\r
+    if (dataset == null || renderer == null || types == null\r
+        || dataset.getSeriesCount() != types.length) {\r
+      throw new IllegalArgumentException(\r
+          "Datasets, renderers and types should be not null and the datasets series count should be equal to the types length");\r
+    }\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    CombinedXYChart chart = new CombinedXYChart(dataset, renderer, types);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a pie chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the category series dataset (cannot be null)\r
+   * @param renderer the series renderer (cannot be null)\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a pie chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset number of items is different than the number of\r
+   *           series renderers\r
+   */\r
+  public static final Intent getPieChartIntent(Context context, CategorySeries dataset,\r
+      DefaultRenderer renderer, String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    PieChart chart = new PieChart(dataset, renderer);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a doughnut chart intent that can be used to start the graphical\r
+   * view activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the multiple category series dataset (cannot be null)\r
+   * @param renderer the series renderer (cannot be null)\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a pie chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset number of items is different than the number of\r
+   *           series renderers\r
+   */\r
+  public static final Intent getDoughnutChartIntent(Context context,\r
+      MultipleCategorySeries dataset, DefaultRenderer renderer, String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    DoughnutChart chart = new DoughnutChart(dataset, renderer);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Creates a dial chart intent that can be used to start the graphical view\r
+   * activity.\r
+   * \r
+   * @param context the context\r
+   * @param dataset the category series dataset (cannot be null)\r
+   * @param renderer the dial renderer (cannot be null)\r
+   * @param activityTitle the graphical chart activity title\r
+   * @return a dial chart intent\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset number of items is different than the number of\r
+   *           series renderers\r
+   */\r
+  public static final Intent getDialChartIntent(Context context, CategorySeries dataset,\r
+      DialRenderer renderer, String activityTitle) {\r
+    checkParameters(dataset, renderer);\r
+    Intent intent = new Intent(context, GraphicalActivity.class);\r
+    DialChart chart = new DialChart(dataset, renderer);\r
+    intent.putExtra(CHART, chart);\r
+    intent.putExtra(TITLE, activityTitle);\r
+    return intent;\r
+  }\r
+\r
+  /**\r
+   * Checks the validity of the dataset and renderer parameters.\r
+   * \r
+   * @param dataset the multiple series dataset (cannot be null)\r
+   * @param renderer the multiple series renderer (cannot be null)\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset and the renderer don't include the same number of\r
+   *           series\r
+   */\r
+  private static void checkParameters(XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer) {\r
+    if (dataset == null || renderer == null\r
+        || dataset.getSeriesCount() != renderer.getSeriesRendererCount()) {\r
+      throw new IllegalArgumentException(\r
+          "Dataset and renderer should be not null and should have the same number of series");\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Checks the validity of the dataset and renderer parameters.\r
+   * \r
+   * @param dataset the category series dataset (cannot be null)\r
+   * @param renderer the series renderer (cannot be null)\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset number of items is different than the number of\r
+   *           series renderers\r
+   */\r
+  private static void checkParameters(CategorySeries dataset, DefaultRenderer renderer) {\r
+    if (dataset == null || renderer == null\r
+        || dataset.getItemCount() != renderer.getSeriesRendererCount()) {\r
+      throw new IllegalArgumentException(\r
+          "Dataset and renderer should be not null and the dataset number of items should be equal to the number of series renderers");\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Checks the validity of the dataset and renderer parameters.\r
+   * \r
+   * @param dataset the category series dataset (cannot be null)\r
+   * @param renderer the series renderer (cannot be null)\r
+   * @throws IllegalArgumentException if dataset is null or renderer is null or\r
+   *           if the dataset number of items is different than the number of\r
+   *           series renderers\r
+   */\r
+  private static void checkParameters(MultipleCategorySeries dataset, DefaultRenderer renderer) {\r
+    if (dataset == null || renderer == null\r
+        || !checkMultipleSeriesItems(dataset, renderer.getSeriesRendererCount())) {\r
+      throw new IllegalArgumentException(\r
+          "Titles and values should be not null and the dataset number of items should be equal to the number of series renderers");\r
+    }\r
+  }\r
+\r
+  private static boolean checkMultipleSeriesItems(MultipleCategorySeries dataset, int value) {\r
+    int count = dataset.getCategoriesCount();\r
+    boolean equal = true;\r
+    for (int k = 0; k < count && equal; k++) {\r
+      equal = dataset.getValues(k).length == dataset.getTitles(k).length;\r
+    }\r
+    return equal;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/GraphicalActivity.java b/android-libraries/achartengine/src/org/achartengine/GraphicalActivity.java
new file mode 100644 (file)
index 0000000..56c190a
--- /dev/null
@@ -0,0 +1,48 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+\r
+import android.app.Activity;\r
+import android.os.Bundle;\r
+import android.view.Window;\r
+\r
+/**\r
+ * An activity that encapsulates a graphical view of the chart.\r
+ */\r
+public class GraphicalActivity extends Activity {\r
+  /** The encapsulated graphical view. */\r
+  private GraphicalView mView;\r
+  /** The chart to be drawn. */\r
+  private AbstractChart mChart;\r
+\r
+  @Override\r
+  protected void onCreate(Bundle savedInstanceState) {\r
+    super.onCreate(savedInstanceState);\r
+    Bundle extras = getIntent().getExtras();\r
+    mChart = (AbstractChart) extras.getSerializable(ChartFactory.CHART);\r
+    mView = new GraphicalView(this, mChart);\r
+    String title = extras.getString(ChartFactory.TITLE);\r
+    if (title == null) {\r
+      requestWindowFeature(Window.FEATURE_NO_TITLE);\r
+    } else if (title.length() > 0) {\r
+      setTitle(title);\r
+    }\r
+    setContentView(mView);\r
+  }\r
+\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/GraphicalView.java b/android-libraries/achartengine/src/org/achartengine/GraphicalView.java
new file mode 100644 (file)
index 0000000..e9aebff
--- /dev/null
@@ -0,0 +1,337 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.model.Point;\r
+import org.achartengine.model.SeriesSelection;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.tools.FitZoom;\r
+import org.achartengine.tools.PanListener;\r
+import org.achartengine.tools.Zoom;\r
+import org.achartengine.tools.ZoomListener;\r
+\r
+import android.content.Context;\r
+import android.graphics.Bitmap;\r
+import android.graphics.BitmapFactory;\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Rect;\r
+import android.graphics.RectF;\r
+import android.os.Build;\r
+import android.os.Handler;\r
+import android.view.MotionEvent;\r
+import android.view.View;\r
+\r
+/**\r
+ * The view that encapsulates the graphical chart.\r
+ */\r
+public class GraphicalView extends View {\r
+  /** The chart to be drawn. */\r
+  private AbstractChart mChart;\r
+  /** The chart renderer. */\r
+  private DefaultRenderer mRenderer;\r
+  /** The view bounds. */\r
+  private Rect mRect = new Rect();\r
+  /** The user interface thread handler. */\r
+  private Handler mHandler;\r
+  /** The zoom buttons rectangle. */\r
+  private RectF mZoomR = new RectF();\r
+  /** The zoom in icon. */\r
+  private Bitmap zoomInImage;\r
+  /** The zoom out icon. */\r
+  private Bitmap zoomOutImage;\r
+  /** The fit zoom icon. */\r
+  private Bitmap fitZoomImage;\r
+  /** The zoom area size. */\r
+  private int zoomSize = 50;\r
+  /** The zoom buttons background color. */\r
+  private static final int ZOOM_BUTTONS_COLOR = Color.argb(175, 150, 150, 150);\r
+  /** The zoom in tool. */\r
+  private Zoom mZoomIn;\r
+  /** The zoom out tool. */\r
+  private Zoom mZoomOut;\r
+  /** The fit zoom tool. */\r
+  private FitZoom mFitZoom;\r
+  /** The paint to be used when drawing the chart. */\r
+  private Paint mPaint = new Paint();\r
+  /** The touch handler. */\r
+  private ITouchHandler mTouchHandler;\r
+  /** The old x coordinate. */\r
+  private float oldX;\r
+  /** The old y coordinate. */\r
+  private float oldY;\r
+\r
+  /**\r
+   * Creates a new graphical view.\r
+   * \r
+   * @param context the context\r
+   * @param chart the chart to be drawn\r
+   */\r
+  public GraphicalView(Context context, AbstractChart chart) {\r
+    super(context);\r
+    mChart = chart;\r
+    mHandler = new Handler();\r
+    if (mChart instanceof XYChart) {\r
+      mRenderer = ((XYChart) mChart).getRenderer();\r
+    } else {\r
+      mRenderer = ((RoundChart) mChart).getRenderer();\r
+    }\r
+    if (mRenderer.isZoomButtonsVisible()) {\r
+      zoomInImage = BitmapFactory.decodeStream(GraphicalView.class\r
+          .getResourceAsStream("image/zoom_in.png"));\r
+      zoomOutImage = BitmapFactory.decodeStream(GraphicalView.class\r
+          .getResourceAsStream("image/zoom_out.png"));\r
+      fitZoomImage = BitmapFactory.decodeStream(GraphicalView.class\r
+          .getResourceAsStream("image/zoom-1.png"));\r
+    }\r
+\r
+    if (mRenderer instanceof XYMultipleSeriesRenderer\r
+        && ((XYMultipleSeriesRenderer) mRenderer).getMarginsColor() == XYMultipleSeriesRenderer.NO_COLOR) {\r
+      ((XYMultipleSeriesRenderer) mRenderer).setMarginsColor(mPaint.getColor());\r
+    }\r
+    if (mRenderer.isZoomEnabled() && mRenderer.isZoomButtonsVisible()\r
+        || mRenderer.isExternalZoomEnabled()) {\r
+      mZoomIn = new Zoom(mChart, true, mRenderer.getZoomRate());\r
+      mZoomOut = new Zoom(mChart, false, mRenderer.getZoomRate());\r
+      mFitZoom = new FitZoom(mChart);\r
+    }\r
+    int version = 7;\r
+    try {\r
+      version = Integer.valueOf(Build.VERSION.SDK);\r
+    } catch (Exception e) {\r
+      // do nothing\r
+    }\r
+    if (version < 7) {\r
+      mTouchHandler = new TouchHandlerOld(this, mChart);\r
+    } else {\r
+      mTouchHandler = new TouchHandler(this, mChart);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns the current series selection object.\r
+   * \r
+   * @return the series selection\r
+   */\r
+  public SeriesSelection getCurrentSeriesAndPoint() {\r
+    return mChart.getSeriesAndPointForScreenCoordinate(new Point(oldX, oldY));\r
+  }\r
+\r
+  /**\r
+   * Transforms the currently selected screen point to a real point.\r
+   * \r
+   * @param scale the scale\r
+   * @return the currently selected real point\r
+   */\r
+  public double[] toRealPoint(int scale) {\r
+    if (mChart instanceof XYChart) {\r
+      XYChart chart = (XYChart) mChart;\r
+      return chart.toRealPoint(oldX, oldY, scale);\r
+    }\r
+    return null;\r
+  }\r
+\r
+  @Override\r
+  protected void onDraw(Canvas canvas) {\r
+    super.onDraw(canvas);\r
+    canvas.getClipBounds(mRect);\r
+    int top = mRect.top;\r
+    int left = mRect.left;\r
+    int width = mRect.width();\r
+    int height = mRect.height();\r
+    if (mRenderer.isInScroll()) {\r
+      top = 0;\r
+      left = 0;\r
+      width = getMeasuredWidth();\r
+      height = getMeasuredHeight();\r
+    }\r
+    mChart.draw(canvas, left, top, width, height, mPaint);\r
+    if (mRenderer != null && mRenderer.isZoomEnabled() && mRenderer.isZoomButtonsVisible()) {\r
+      mPaint.setColor(ZOOM_BUTTONS_COLOR);\r
+      zoomSize = Math.max(zoomSize, Math.min(width, height) / 7);\r
+      mZoomR.set(left + width - zoomSize * 3, top + height - zoomSize * 0.775f, left + width, top\r
+          + height);\r
+      canvas.drawRoundRect(mZoomR, zoomSize / 3, zoomSize / 3, mPaint);\r
+      float buttonY = top + height - zoomSize * 0.625f;\r
+      canvas.drawBitmap(zoomInImage, left + width - zoomSize * 2.75f, buttonY, null);\r
+      canvas.drawBitmap(zoomOutImage, left + width - zoomSize * 1.75f, buttonY, null);\r
+      canvas.drawBitmap(fitZoomImage, left + width - zoomSize * 0.75f, buttonY, null);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Sets the zoom rate.\r
+   * \r
+   * @param rate the zoom rate\r
+   */\r
+  public void setZoomRate(float rate) {\r
+    if (mZoomIn != null && mZoomOut != null) {\r
+      mZoomIn.setZoomRate(rate);\r
+      mZoomOut.setZoomRate(rate);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Do a chart zoom in.\r
+   */\r
+  public void zoomIn() {\r
+    if (mZoomIn != null) {\r
+      mZoomIn.apply(Zoom.ZOOM_AXIS_XY);\r
+      repaint();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Do a chart zoom out.\r
+   */\r
+  public void zoomOut() {\r
+    if (mZoomOut != null) {\r
+      mZoomOut.apply(Zoom.ZOOM_AXIS_XY);\r
+      repaint();\r
+    }\r
+  }\r
+  \r
+\r
+\r
+  /**\r
+   * Do a chart zoom reset / fit zoom.\r
+   */\r
+  public void zoomReset() {\r
+    if (mFitZoom != null) {\r
+      mFitZoom.apply();\r
+      mZoomIn.notifyZoomResetListeners();\r
+      repaint();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Adds a new zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  public void addZoomListener(ZoomListener listener, boolean onButtons, boolean onPinch) {\r
+    if (onButtons) {\r
+      if (mZoomIn != null) {\r
+        mZoomIn.addZoomListener(listener);\r
+        mZoomOut.addZoomListener(listener);\r
+      }\r
+      if (onPinch) {\r
+        mTouchHandler.addZoomListener(listener);\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Removes a zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  public synchronized void removeZoomListener(ZoomListener listener) {\r
+    if (mZoomIn != null) {\r
+      mZoomIn.removeZoomListener(listener);\r
+      mZoomOut.removeZoomListener(listener);\r
+    }\r
+    mTouchHandler.removeZoomListener(listener);\r
+  }\r
+\r
+  /**\r
+   * Adds a new pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  public void addPanListener(PanListener listener) {\r
+    mTouchHandler.addPanListener(listener);\r
+  }\r
+\r
+  /**\r
+   * Removes a pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  public void removePanListener(PanListener listener) {\r
+    mTouchHandler.removePanListener(listener);\r
+  }\r
+\r
+  protected RectF getZoomRectangle() {\r
+    return mZoomR;\r
+  }\r
+\r
+  @Override\r
+  public boolean onTouchEvent(MotionEvent event) {\r
+    if (event.getAction() == MotionEvent.ACTION_DOWN) {\r
+      // save the x and y so they can be used in the click and long press\r
+      // listeners\r
+      oldX = event.getX();\r
+      oldY = event.getY();\r
+    }\r
+    if (mRenderer != null && (mRenderer.isPanEnabled() || mRenderer.isZoomEnabled())) {\r
+      if (mTouchHandler.handleTouch(event)) {\r
+        return true;\r
+      }\r
+    }\r
+    return super.onTouchEvent(event);\r
+  }\r
+\r
+  /**\r
+   * Schedule a view content repaint.\r
+   */\r
+  public void repaint() {\r
+    mHandler.post(new Runnable() {\r
+      public void run() {\r
+        invalidate();\r
+      }\r
+    });\r
+  }\r
+\r
+  /**\r
+   * Schedule a view content repaint, in the specified rectangle area.\r
+   * \r
+   * @param left the left position of the area to be repainted\r
+   * @param top the top position of the area to be repainted\r
+   * @param right the right position of the area to be repainted\r
+   * @param bottom the bottom position of the area to be repainted\r
+   */\r
+  public void repaint(final int left, final int top, final int right, final int bottom) {\r
+    mHandler.post(new Runnable() {\r
+      public void run() {\r
+        invalidate(left, top, right, bottom);\r
+      }\r
+    });\r
+  }\r
+\r
+  /**\r
+   * Saves the content of the graphical view to a bitmap.\r
+   * \r
+   * @return the bitmap\r
+   */\r
+  public Bitmap toBitmap() {\r
+    setDrawingCacheEnabled(false);\r
+    if (!isDrawingCacheEnabled()) {\r
+      setDrawingCacheEnabled(true);\r
+    }\r
+    if (mRenderer.isApplyBackgroundColor()) {\r
+      setDrawingCacheBackgroundColor(mRenderer.getBackgroundColor());\r
+    }\r
+    setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);\r
+    return getDrawingCache(true);\r
+  }\r
+\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/ITouchHandler.java b/android-libraries/achartengine/src/org/achartengine/ITouchHandler.java
new file mode 100644 (file)
index 0000000..4debe96
--- /dev/null
@@ -0,0 +1,63 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.tools.PanListener;\r
+import org.achartengine.tools.ZoomListener;\r
+\r
+import android.view.MotionEvent;\r
+\r
+/**\r
+ * The interface to be implemented by the touch handlers.\r
+ */\r
+public interface ITouchHandler {\r
+  /**\r
+   * Handles the touch event.\r
+   * \r
+   * @param event the touch event\r
+   * @return true if the event was handled\r
+   */\r
+  boolean handleTouch(MotionEvent event);\r
+  \r
+  /**\r
+   * Adds a new zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  void addZoomListener(ZoomListener listener);\r
+\r
+  /**\r
+   * Removes a zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  void removeZoomListener(ZoomListener listener);\r
+  \r
+  /**\r
+   * Adds a new pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  void addPanListener(PanListener listener);\r
+\r
+  /**\r
+   * Removes a pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  void removePanListener(PanListener listener);\r
+\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/TouchHandler.java b/android-libraries/achartengine/src/org/achartengine/TouchHandler.java
new file mode 100644 (file)
index 0000000..a06d05d
--- /dev/null
@@ -0,0 +1,204 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.tools.Pan;\r
+import org.achartengine.tools.PanListener;\r
+import org.achartengine.tools.Zoom;\r
+import org.achartengine.tools.ZoomListener;\r
+\r
+import android.graphics.RectF;\r
+import android.view.MotionEvent;\r
+\r
+/**\r
+ * The main handler of the touch events.\r
+ */\r
+public class TouchHandler implements ITouchHandler {\r
+  /** The chart renderer. */\r
+  private DefaultRenderer mRenderer;\r
+  /** The old x coordinate. */\r
+  private float oldX;\r
+  /** The old y coordinate. */\r
+  private float oldY;\r
+  /** The old x2 coordinate. */\r
+  private float oldX2;\r
+  /** The old y2 coordinate. */\r
+  private float oldY2;\r
+  /** The zoom buttons rectangle. */\r
+  private RectF zoomR = new RectF();\r
+  /** The pan tool. */\r
+  private Pan mPan;\r
+  /** The zoom for the pinch gesture. */\r
+  private Zoom mPinchZoom;\r
+  /** The graphical view. */\r
+  private GraphicalView graphicalView;\r
+\r
+  /**\r
+   * Creates a new graphical view.\r
+   * \r
+   * @param view the graphical view\r
+   * @param chart the chart to be drawn\r
+   */\r
+  public TouchHandler(GraphicalView view, AbstractChart chart) {\r
+    graphicalView = view;\r
+    zoomR = graphicalView.getZoomRectangle();\r
+    if (chart instanceof XYChart) {\r
+      mRenderer = ((XYChart) chart).getRenderer();\r
+    } else {\r
+      mRenderer = ((RoundChart) chart).getRenderer();\r
+    }\r
+    if (mRenderer.isPanEnabled()) {\r
+      mPan = new Pan(chart);\r
+    }\r
+    if (mRenderer.isZoomEnabled()) {\r
+      mPinchZoom = new Zoom(chart, true, 1);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Handles the touch event.\r
+   * \r
+   * @param event the touch event\r
+   */\r
+  public boolean handleTouch(MotionEvent event) {\r
+    int action = event.getAction();\r
+    if (mRenderer != null && action == MotionEvent.ACTION_MOVE) {\r
+      if (oldX >= 0 || oldY >= 0) {\r
+        float newX = event.getX(0);\r
+        float newY = event.getY(0);\r
+        if (event.getPointerCount() > 1 && (oldX2 >= 0 || oldY2 >= 0) && mRenderer.isZoomEnabled()) {\r
+          float newX2 = event.getX(1);\r
+          float newY2 = event.getY(1);\r
+          float newDeltaX = Math.abs(newX - newX2);\r
+          float newDeltaY = Math.abs(newY - newY2);\r
+          float oldDeltaX = Math.abs(oldX - oldX2);\r
+          float oldDeltaY = Math.abs(oldY - oldY2);\r
+          float zoomRate = 1;\r
+\r
+          float tan1 = Math.abs(newY - oldY) / Math.abs(newX - oldX);\r
+          float tan2 = Math.abs(newY2 - oldY2) / Math.abs(newX2 - oldX2);\r
+          if ( tan1 <= 0.577 && tan2 <= 0.577) {\r
+            // horizontal pinch zoom, |deltaY| / |deltaX| is [0 ~ 0.577], 0.577 is the approximate value of tan(Pi/6)\r
+            zoomRate = newDeltaX / oldDeltaX;\r
+            if (zoomRate > 0.909 && zoomRate < 1.1) {\r
+              mPinchZoom.setZoomRate(zoomRate);\r
+              mPinchZoom.apply(Zoom.ZOOM_AXIS_X);\r
+            }\r
+          } else if ( tan1 >= 1.732 && tan2 >= 1.732 ) {\r
+            // pinch zoom vertically, |deltaY| / |deltaX| is [1.732 ~ infinity], 1.732 is the approximate value of tan(Pi/3)\r
+            zoomRate = newDeltaY / oldDeltaY;\r
+            if (zoomRate > 0.909 && zoomRate < 1.1) {\r
+              mPinchZoom.setZoomRate(zoomRate);\r
+              mPinchZoom.apply(Zoom.ZOOM_AXIS_Y);\r
+            }\r
+          } else if ( (tan1 > 0.577 && tan1 < 1.732) && (tan2 > 0.577 && tan2 < 1.732) ){\r
+            // pinch zoom diagonally\r
+            if (Math.abs(newX - oldX) >= Math.abs(newY - oldY)) {\r
+              zoomRate = newDeltaX / oldDeltaX;\r
+            } else {\r
+              zoomRate = newDeltaY / oldDeltaY;\r
+            }\r
+            if (zoomRate > 0.909 && zoomRate < 1.1) {\r
+              mPinchZoom.setZoomRate(zoomRate);\r
+              mPinchZoom.apply(Zoom.ZOOM_AXIS_XY);\r
+            }\r
+          }\r
+          oldX2 = newX2;\r
+          oldY2 = newY2;\r
+        } else if (mRenderer.isPanEnabled()) {\r
+          mPan.apply(oldX, oldY, newX, newY);\r
+          oldX2 = 0;\r
+          oldY2 = 0;\r
+        }\r
+        oldX = newX;\r
+        oldY = newY;\r
+        graphicalView.repaint();\r
+        return true;\r
+      }\r
+    } else if (action == MotionEvent.ACTION_DOWN) {\r
+      oldX = event.getX(0);\r
+      oldY = event.getY(0);\r
+      if (mRenderer != null && mRenderer.isZoomEnabled() && zoomR.contains(oldX, oldY)) {\r
+        if (oldX < zoomR.left + zoomR.width() / 3) {\r
+          graphicalView.zoomIn();\r
+        } else if (oldX < zoomR.left + zoomR.width() * 2 / 3) {\r
+          graphicalView.zoomOut();\r
+        } else {\r
+          graphicalView.zoomReset();\r
+        }\r
+        return true;\r
+      }\r
+    } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {\r
+      oldX = 0;\r
+      oldY = 0;\r
+      oldX2 = 0;\r
+      oldY2 = 0;\r
+      if (action == MotionEvent.ACTION_POINTER_UP) {\r
+        oldX = -1;\r
+        oldY = -1;\r
+      }\r
+    }\r
+    return !mRenderer.isClickEnabled();\r
+  }\r
+\r
+  /**\r
+   * Adds a new zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  public void addZoomListener(ZoomListener listener) {\r
+    if (mPinchZoom != null) {\r
+      mPinchZoom.addZoomListener(listener);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Removes a zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  public void removeZoomListener(ZoomListener listener) {\r
+    if (mPinchZoom != null) {\r
+      mPinchZoom.removeZoomListener(listener);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Adds a new pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  public void addPanListener(PanListener listener) {\r
+    if (mPan != null) {\r
+      mPan.addPanListener(listener);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Removes a pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  public void removePanListener(PanListener listener) {\r
+    if (mPan != null) {\r
+      mPan.removePanListener(listener);\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/TouchHandlerOld.java b/android-libraries/achartengine/src/org/achartengine/TouchHandlerOld.java
new file mode 100644 (file)
index 0000000..38b4f22
--- /dev/null
@@ -0,0 +1,137 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.tools.Pan;\r
+import org.achartengine.tools.PanListener;\r
+import org.achartengine.tools.ZoomListener;\r
+\r
+import android.graphics.RectF;\r
+import android.view.MotionEvent;\r
+\r
+/**\r
+ * A handler implementation for touch events for older platforms.\r
+ */\r
+public class TouchHandlerOld implements ITouchHandler {\r
+  /** The chart renderer. */\r
+  private DefaultRenderer mRenderer;\r
+  /** The old x coordinate. */\r
+  private float oldX;\r
+  /** The old y coordinate. */\r
+  private float oldY;\r
+  /** The zoom buttons rectangle. */\r
+  private RectF zoomR = new RectF();\r
+  /** The pan tool. */\r
+  private Pan mPan;\r
+  /** The graphical view. */\r
+  private GraphicalView graphicalView;\r
+\r
+  /**\r
+   * Creates an implementation of the old version of the touch handler.\r
+   * \r
+   * @param view the graphical view\r
+   * @param chart the chart to be drawn\r
+   */\r
+  public TouchHandlerOld(GraphicalView view, AbstractChart chart) {\r
+    graphicalView = view;\r
+    zoomR = graphicalView.getZoomRectangle();\r
+    if (chart instanceof XYChart) {\r
+      mRenderer = ((XYChart) chart).getRenderer();\r
+    } else {\r
+      mRenderer = ((RoundChart) chart).getRenderer();\r
+    }\r
+    if (mRenderer.isPanEnabled()) {\r
+      mPan = new Pan(chart);\r
+    }\r
+  }\r
+\r
+  public boolean handleTouch(MotionEvent event) {\r
+    int action = event.getAction();\r
+    if (mRenderer != null && action == MotionEvent.ACTION_MOVE) {\r
+      if (oldX >= 0 || oldY >= 0) {\r
+        float newX = event.getX();\r
+        float newY = event.getY();\r
+        if (mRenderer.isPanEnabled()) {\r
+          mPan.apply(oldX, oldY, newX, newY);\r
+        }\r
+        oldX = newX;\r
+        oldY = newY;\r
+        graphicalView.repaint();\r
+        return true;\r
+      }\r
+    } else if (action == MotionEvent.ACTION_DOWN) {\r
+      oldX = event.getX();\r
+      oldY = event.getY();\r
+      if (mRenderer != null && mRenderer.isZoomEnabled() && zoomR.contains(oldX, oldY)) {\r
+        if (oldX < zoomR.left + zoomR.width() / 3) {\r
+          graphicalView.zoomIn();\r
+        } else if (oldX < zoomR.left + zoomR.width() * 2 / 3) {\r
+          graphicalView.zoomOut();\r
+        } else {\r
+          graphicalView.zoomReset();\r
+        }\r
+        return true;\r
+      }\r
+    } else if (action == MotionEvent.ACTION_UP) {\r
+      oldX = 0;\r
+      oldY = 0;\r
+    }\r
+    return !mRenderer.isClickEnabled();\r
+  }\r
+\r
+  /**\r
+   * Adds a new zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  public void addZoomListener(ZoomListener listener) {\r
+  }\r
+\r
+  /**\r
+   * Removes a zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  public void removeZoomListener(ZoomListener listener) {\r
+  }\r
+\r
+  /**\r
+   * Adds a new pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  public void addPanListener(PanListener listener) {\r
+    if (mPan != null) {\r
+      mPan.addPanListener(listener);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Removes a pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  public void removePanListener(PanListener listener) {\r
+    if (mPan != null) {\r
+      mPan.removePanListener(listener);\r
+    }\r
+  }\r
+\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/AbstractChart.java b/android-libraries/achartengine/src/org/achartengine/chart/AbstractChart.java
new file mode 100644 (file)
index 0000000..f99a5c2
--- /dev/null
@@ -0,0 +1,475 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.io.Serializable;\r
+import java.util.List;\r
+\r
+import org.achartengine.model.Point;\r
+import org.achartengine.model.SeriesSelection;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;\r
+import org.achartengine.util.MathHelper;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Align;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.Path;\r
+import android.graphics.Rect;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * An abstract class to be implemented by the chart rendering classes.\r
+ */\r
+public abstract class AbstractChart implements Serializable {\r
+  /**\r
+   * The graphical representation of the chart.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param x the top left x value of the view to draw to\r
+   * @param y the top left y value of the view to draw to\r
+   * @param width the width of the view to draw to\r
+   * @param height the height of the view to draw to\r
+   * @param paint the paint\r
+   */\r
+  public abstract void draw(Canvas canvas, int x, int y, int width, int height, Paint paint);\r
+\r
+  /**\r
+   * Draws the chart background.\r
+   * \r
+   * @param renderer the chart renderer\r
+   * @param canvas the canvas to paint to\r
+   * @param x the top left x value of the view to draw to\r
+   * @param y the top left y value of the view to draw to\r
+   * @param width the width of the view to draw to\r
+   * @param height the height of the view to draw to\r
+   * @param paint the paint used for drawing\r
+   * @param newColor if a new color is to be used\r
+   * @param color the color to be used\r
+   */\r
+  protected void drawBackground(DefaultRenderer renderer, Canvas canvas, int x, int y, int width,\r
+      int height, Paint paint, boolean newColor, int color) {\r
+    if (renderer.isApplyBackgroundColor() || newColor) {\r
+      if (newColor) {\r
+        paint.setColor(color);\r
+      } else {\r
+        paint.setColor(renderer.getBackgroundColor());\r
+      }\r
+      paint.setStyle(Style.FILL);\r
+      canvas.drawRect(x, y, x + width, y + height, paint);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Draws the chart legend.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param titles the titles to go to the legend\r
+   * @param left the left X value of the area to draw to\r
+   * @param right the right X value of the area to draw to\r
+   * @param y the y value of the area to draw to\r
+   * @param width the width of the area to draw to\r
+   * @param height the height of the area to draw to\r
+   * @param legendSize the legend size\r
+   * @param paint the paint to be used for drawing\r
+   * @param calculate if only calculating the legend size\r
+   * \r
+   * @return the legend height\r
+   */\r
+  protected int drawLegend(Canvas canvas, DefaultRenderer renderer, String[] titles, int left,\r
+      int right, int y, int width, int height, int legendSize, Paint paint, boolean calculate) {\r
+    float size = 32;\r
+    if (renderer.isShowLegend()) {\r
+      float currentX = left;\r
+      float currentY = y + height - legendSize + size;\r
+      paint.setTextAlign(Align.LEFT);\r
+      paint.setTextSize(renderer.getLegendTextSize());\r
+      int sLength = Math.min(titles.length, renderer.getSeriesRendererCount());\r
+      for (int i = 0; i < sLength; i++) {\r
+        final float lineSize = getLegendShapeWidth(i);\r
+        String text = titles[i];\r
+        if (titles.length == renderer.getSeriesRendererCount()) {\r
+          paint.setColor(renderer.getSeriesRendererAt(i).getColor());\r
+        } else {\r
+          paint.setColor(Color.LTGRAY);\r
+        }\r
+        float[] widths = new float[text.length()];\r
+        paint.getTextWidths(text, widths);\r
+        float sum = 0;\r
+        for (float value : widths) {\r
+          sum += value;\r
+        }\r
+        float extraSize = lineSize + 10 + sum;\r
+        float currentWidth = currentX + extraSize;\r
+\r
+        if (i > 0 && getExceed(currentWidth, renderer, right, width)) {\r
+          currentX = left;\r
+          currentY += renderer.getLegendTextSize();\r
+          size += renderer.getLegendTextSize();\r
+          currentWidth = currentX + extraSize;\r
+        }\r
+        if (getExceed(currentWidth, renderer, right, width)) {\r
+          float maxWidth = right - currentX - lineSize - 10;\r
+          if (isVertical(renderer)) {\r
+            maxWidth = width - currentX - lineSize - 10;\r
+          }\r
+          int nr = paint.breakText(text, true, maxWidth, widths);\r
+          text = text.substring(0, nr) + "...";\r
+        }\r
+        if (!calculate) {\r
+          drawLegendShape(canvas, renderer.getSeriesRendererAt(i), currentX, currentY, i, paint);\r
+          drawString(canvas, text, currentX + lineSize + 5, currentY + 5, paint);\r
+        }\r
+        currentX += extraSize;\r
+      }\r
+    }\r
+    return Math.round(size + renderer.getLegendTextSize());\r
+  }\r
+\r
+  /**\r
+   * Draw a multiple lines string.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param text the text to be painted\r
+   * @param x the x value of the area to draw to\r
+   * @param y the y value of the area to draw to\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  protected void drawString(Canvas canvas, String text, float x, float y, Paint paint) {\r
+    String[] lines = text.split("\n");\r
+    Rect rect = new Rect();\r
+    int yOff = 0;\r
+    for (int i = 0; i < lines.length; ++i) {\r
+      canvas.drawText(lines[i], x, y + yOff, paint);\r
+      paint.getTextBounds(lines[i], 0, lines[i].length(), rect);\r
+      yOff = yOff + rect.height() + 5; // space between lines is 5\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Calculates if the current width exceeds the total width.\r
+   * \r
+   * @param currentWidth the current width\r
+   * @param renderer the renderer\r
+   * @param right the right side pixel value\r
+   * @param width the total width\r
+   * @return if the current width exceeds the total width\r
+   */\r
+  protected boolean getExceed(float currentWidth, DefaultRenderer renderer, int right, int width) {\r
+    boolean exceed = currentWidth > right;\r
+    if (isVertical(renderer)) {\r
+      exceed = currentWidth > width;\r
+    }\r
+    return exceed;\r
+  }\r
+\r
+  /**\r
+   * Checks if the current chart is rendered as vertical.\r
+   * \r
+   * @param renderer the renderer\r
+   * @return if the chart is rendered as a vertical one\r
+   */\r
+  public boolean isVertical(DefaultRenderer renderer) {\r
+    return renderer instanceof XYMultipleSeriesRenderer\r
+        && ((XYMultipleSeriesRenderer) renderer).getOrientation() == Orientation.VERTICAL;\r
+  }\r
+  \r
+  /**\r
+   * Makes sure the fraction digit is not displayed, if not needed.\r
+   * \r
+   * @param label the input label value\r
+   * @return the label without the useless fraction digit\r
+   */\r
+  protected String getLabel(double label) {\r
+    String text = "";\r
+    if (label == Math.round(label)) {\r
+      text = Math.round(label) + "";\r
+    } else {\r
+      text = label + "";\r
+    }\r
+    return text;\r
+  }\r
+\r
+  private static float[] calculateDrawPoints(float p1x, float p1y, float p2x, float p2y,\r
+      int screenHeight, int screenWidth) {\r
+    float drawP1x;\r
+    float drawP1y;\r
+    float drawP2x;\r
+    float drawP2y;\r
+\r
+    if (p1y > screenHeight) {\r
+      // Intersection with the top of the screen\r
+      float m = (p2y - p1y) / (p2x - p1x);\r
+      drawP1x = (screenHeight - p1y + m * p1x) / m;\r
+      drawP1y = screenHeight;\r
+\r
+      if (drawP1x < 0) {\r
+        // If Intersection is left of the screen we calculate the intersection\r
+        // with the left border\r
+        drawP1x = 0;\r
+        drawP1y = p1y - m * p1x;\r
+      } else if (drawP1x > screenWidth) {\r
+        // If Intersection is right of the screen we calculate the intersection\r
+        // with the right border\r
+        drawP1x = screenWidth;\r
+        drawP1y = m * screenWidth + p1y - m * p1x;\r
+      }\r
+    } else if (p1y < 0) {\r
+      float m = (p2y - p1y) / (p2x - p1x);\r
+      drawP1x = (-p1y + m * p1x) / m;\r
+      drawP1y = 0;\r
+      if (drawP1x < 0) {\r
+        drawP1x = 0;\r
+        drawP1y = p1y - m * p1x;\r
+      } else if (drawP1x > screenWidth) {\r
+        drawP1x = screenWidth;\r
+        drawP1y = m * screenWidth + p1y - m * p1x;\r
+      }\r
+    } else {\r
+      // If the point is in the screen use it\r
+      drawP1x = p1x;\r
+      drawP1y = p1y;\r
+    }\r
+\r
+    if (p2y > screenHeight) {\r
+      float m = (p2y - p1y) / (p2x - p1x);\r
+      drawP2x = (screenHeight - p1y + m * p1x) / m;\r
+      drawP2y = screenHeight;\r
+      if (drawP2x < 0) {\r
+        drawP2x = 0;\r
+        drawP2y = p1y - m * p1x;\r
+      } else if (drawP2x > screenWidth) {\r
+        drawP2x = screenWidth;\r
+        drawP2y = m * screenWidth + p1y - m * p1x;\r
+      }\r
+    } else if (p2y < 0) {\r
+      float m = (p2y - p1y) / (p2x - p1x);\r
+      drawP2x = (-p1y + m * p1x) / m;\r
+      drawP2y = 0;\r
+      if (drawP2x < 0) {\r
+        drawP2x = 0;\r
+        drawP2y = p1y - m * p1x;\r
+      } else if (drawP2x > screenWidth) {\r
+        drawP2x = screenWidth;\r
+        drawP2y = m * screenWidth + p1y - m * p1x;\r
+      }\r
+    } else {\r
+      // If the point is in the screen use it\r
+      drawP2x = p2x;\r
+      drawP2y = p2y;\r
+    }\r
+\r
+    return new float[] { drawP1x, drawP1y, drawP2x, drawP2y };\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a path.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param points the points that are contained in the path to paint\r
+   * @param paint the paint to be used for painting\r
+   * @param circular if the path ends with the start point\r
+   */\r
+  protected void drawPath(Canvas canvas, float[] points, Paint paint, boolean circular) {\r
+    Path path = new Path();\r
+    int height = canvas.getHeight();\r
+    int width = canvas.getWidth();\r
+\r
+    float[] tempDrawPoints;\r
+    if (points.length < 4) {\r
+      return;\r
+    }\r
+    tempDrawPoints = calculateDrawPoints(points[0], points[1], points[2], points[3], height, width);\r
+    path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);\r
+    path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);\r
+\r
+    for (int i = 4; i < points.length; i += 2) {\r
+      if ((points[i - 1] < 0 && points[i + 1] < 0)\r
+          || (points[i - 1] > height && points[i + 1] > height)) {\r
+        continue;\r
+      }\r
+      tempDrawPoints = calculateDrawPoints(points[i - 2], points[i - 1], points[i], points[i + 1],\r
+          height, width);\r
+      if (!circular) {\r
+        path.moveTo(tempDrawPoints[0], tempDrawPoints[1]);\r
+      }\r
+      path.lineTo(tempDrawPoints[2], tempDrawPoints[3]);\r
+    }\r
+    if (circular) {\r
+      path.lineTo(points[0], points[1]);\r
+    }\r
+    canvas.drawPath(path, paint);\r
+  }\r
+\r
+  /**\r
+   * Returns the legend shape width.\r
+   * \r
+   * @param seriesIndex the series index\r
+   * @return the legend shape width\r
+   */\r
+  public abstract int getLegendShapeWidth(int seriesIndex);\r
+\r
+  /**\r
+   * The graphical representation of the legend shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param seriesIndex the series index\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  public abstract void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x,\r
+      float y, int seriesIndex, Paint paint);\r
+\r
+  /**\r
+   * Calculates the best text to fit into the available space.\r
+   * \r
+   * @param text the entire text\r
+   * @param width the width to fit the text into\r
+   * @param paint the paint\r
+   * @return the text to fit into the space\r
+   */\r
+  private String getFitText(String text, float width, Paint paint) {\r
+    String newText = text;\r
+    int length = text.length();\r
+    int diff = 0;\r
+    while (paint.measureText(newText) > width && diff < length) {\r
+      diff++;\r
+      newText = text.substring(0, length - diff) + "...";\r
+    }\r
+    if (diff == length) {\r
+      newText = "...";\r
+    }\r
+    return newText;\r
+  }\r
+\r
+  /**\r
+   * Calculates the current legend size.\r
+   * \r
+   * @param renderer the renderer\r
+   * @param defaultHeight the default height\r
+   * @param extraHeight the added extra height\r
+   * @return the legend size\r
+   */\r
+  protected int getLegendSize(DefaultRenderer renderer, int defaultHeight, float extraHeight) {\r
+    int legendSize = renderer.getLegendHeight();\r
+    if (renderer.isShowLegend() && legendSize == 0) {\r
+      legendSize = defaultHeight;\r
+    }\r
+    if (!renderer.isShowLegend() && renderer.isShowLabels()) {\r
+      legendSize = (int) (renderer.getLabelsTextSize() * 4 / 3 + extraHeight);\r
+    }\r
+    return legendSize;\r
+  }\r
+\r
+  /**\r
+   * Draws a text label.\r
+   * \r
+   * @param canvas the canvas\r
+   * @param labelText the label text\r
+   * @param renderer the renderer\r
+   * @param prevLabelsBounds the previous rendered label bounds\r
+   * @param centerX the round chart center on X axis\r
+   * @param centerY the round chart center on Y axis\r
+   * @param shortRadius the short radius for the round chart\r
+   * @param longRadius the long radius for the round chart\r
+   * @param currentAngle the current angle\r
+   * @param angle the label extra angle\r
+   * @param left the left side\r
+   * @param right the right side\r
+   * @param color the label color\r
+   * @param paint the paint\r
+   * @param line if a line to the label should be drawn\r
+   */\r
+  protected void drawLabel(Canvas canvas, String labelText, DefaultRenderer renderer,\r
+      List<RectF> prevLabelsBounds, int centerX, int centerY, float shortRadius, float longRadius,\r
+      float currentAngle, float angle, int left, int right, int color, Paint paint, boolean line) {\r
+    if (renderer.isShowLabels()) {\r
+      paint.setColor(color);\r
+      double rAngle = Math.toRadians(90 - (currentAngle + angle / 2));\r
+      double sinValue = Math.sin(rAngle);\r
+      double cosValue = Math.cos(rAngle);\r
+      int x1 = Math.round(centerX + (float) (shortRadius * sinValue));\r
+      int y1 = Math.round(centerY + (float) (shortRadius * cosValue));\r
+      int x2 = Math.round(centerX + (float) (longRadius * sinValue));\r
+      int y2 = Math.round(centerY + (float) (longRadius * cosValue));\r
+\r
+      float size = renderer.getLabelsTextSize();\r
+      float extra = Math.max(size / 2, 10);\r
+      paint.setTextAlign(Align.LEFT);\r
+      if (x1 > x2) {\r
+        extra = -extra;\r
+        paint.setTextAlign(Align.RIGHT);\r
+      }\r
+      float xLabel = x2 + extra;\r
+      float yLabel = y2;\r
+      float width = right - xLabel;\r
+      if (x1 > x2) {\r
+        width = xLabel - left;\r
+      }\r
+      labelText = getFitText(labelText, width, paint);\r
+      float widthLabel = paint.measureText(labelText);\r
+      boolean okBounds = false;\r
+      while (!okBounds && line) {\r
+        boolean intersects = false;\r
+        int length = prevLabelsBounds.size();\r
+        for (int j = 0; j < length && !intersects; j++) {\r
+          RectF prevLabelBounds = prevLabelsBounds.get(j);\r
+          if (prevLabelBounds.intersects(xLabel, yLabel, xLabel + widthLabel, yLabel + size)) {\r
+            intersects = true;\r
+            yLabel = Math.max(yLabel, prevLabelBounds.bottom);\r
+          }\r
+        }\r
+        okBounds = !intersects;\r
+      }\r
+\r
+      if (line) {\r
+        y2 = (int) (yLabel - size / 2);\r
+        canvas.drawLine(x1, y1, x2, y2, paint);\r
+        canvas.drawLine(x2, y2, x2 + extra, y2, paint);\r
+      } else {\r
+        paint.setTextAlign(Align.CENTER);\r
+      }\r
+      canvas.drawText(labelText, xLabel, yLabel, paint);\r
+      if (line) {\r
+        prevLabelsBounds.add(new RectF(xLabel, yLabel, xLabel + widthLabel, yLabel + size));\r
+      }\r
+    }\r
+  }\r
+\r
+  public boolean isNullValue(double value) {\r
+    return Double.isNaN(value) || Double.isInfinite(value) || value == MathHelper.NULL_VALUE;\r
+  }\r
+\r
+  /**\r
+   * Given screen coordinates, returns the series and point indexes of a chart\r
+   * element. If there is no chart element (line, point, bar, etc) at those\r
+   * coordinates, null is returned.\r
+   * \r
+   * @param screenPoint\r
+   * @return the series and point indexes\r
+   */\r
+  public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {\r
+    return null;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/BarChart.java b/android-libraries/achartengine/src/org/achartengine/chart/BarChart.java
new file mode 100644 (file)
index 0000000..d5d0fb2
--- /dev/null
@@ -0,0 +1,329 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+import android.graphics.drawable.GradientDrawable;\r
+import android.graphics.drawable.GradientDrawable.Orientation;\r
+\r
+/**\r
+ * The bar chart rendering class.\r
+ */\r
+public class BarChart extends XYChart {\r
+  /** The constant to identify this chart type. */\r
+  public static final String TYPE = "Bar";\r
+  /** The legend shape width. */\r
+  private static final int SHAPE_WIDTH = 12;\r
+  /** The chart type. */\r
+  protected Type mType = Type.DEFAULT;\r
+\r
+  /**\r
+   * The bar chart type enum.\r
+   */\r
+  public enum Type {\r
+    DEFAULT, STACKED;\r
+  }\r
+\r
+  BarChart() {\r
+  }\r
+\r
+  BarChart(Type type) {\r
+    mType = type;\r
+  }\r
+\r
+  /**\r
+   * Builds a new bar chart instance.\r
+   * \r
+   * @param dataset the multiple series dataset\r
+   * @param renderer the multiple series renderer\r
+   * @param type the bar chart type\r
+   */\r
+  public BarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+    super(dataset, renderer);\r
+    mType = type;\r
+  }\r
+\r
+  @Override\r
+  protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+      float yAxisValue, int seriesIndex, int startIndex) {\r
+    int seriesNr = mDataset.getSeriesCount();\r
+    int length = points.length;\r
+    ClickableArea[] ret = new ClickableArea[length / 2];\r
+    float halfDiffX = getHalfDiffX(points, length, seriesNr);\r
+    for (int i = 0; i < length; i += 2) {\r
+      float x = points[i];\r
+      float y = points[i + 1];\r
+      if (mType == Type.STACKED) {\r
+        ret[i / 2] = new ClickableArea(new RectF(x - halfDiffX, y, x + halfDiffX, yAxisValue),\r
+            values[i], values[i + 1]);\r
+      } else {\r
+        float startX = x - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;\r
+        ret[i / 2] = new ClickableArea(new RectF(startX, y, startX + 2 * halfDiffX, yAxisValue),\r
+            values[i], values[i + 1]);\r
+      }\r
+    }\r
+    return ret;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a series.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesRenderer the series renderer\r
+   * @param yAxisValue the minimum value of the y axis\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+    int seriesNr = mDataset.getSeriesCount();\r
+    int length = points.length;\r
+    paint.setColor(seriesRenderer.getColor());\r
+    paint.setStyle(Style.FILL);\r
+    float halfDiffX = getHalfDiffX(points, length, seriesNr);\r
+    for (int i = 0; i < length; i += 2) {\r
+      float x = points[i];\r
+      float y = points[i + 1];\r
+      drawBar(canvas, x, yAxisValue, x, y, halfDiffX, seriesNr, seriesIndex, paint);\r
+    }\r
+    paint.setColor(seriesRenderer.getColor());\r
+  }\r
+\r
+  /**\r
+   * Draws a bar.\r
+   * \r
+   * @param canvas the canvas\r
+   * @param xMin the X axis minimum\r
+   * @param yMin the Y axis minimum\r
+   * @param xMax the X axis maximum\r
+   * @param yMax the Y axis maximum\r
+   * @param halfDiffX half the size of a bar\r
+   * @param seriesNr the total number of series\r
+   * @param seriesIndex the current series index\r
+   * @param paint the paint\r
+   */\r
+  protected void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax,\r
+      float halfDiffX, int seriesNr, int seriesIndex, Paint paint) {\r
+    int scale = mDataset.getSeriesAt(seriesIndex).getScaleNumber();\r
+    if (mType == Type.STACKED) {\r
+      drawBar(canvas, xMin - halfDiffX, yMax, xMax + halfDiffX, yMin, scale, seriesIndex, paint);\r
+    } else {\r
+      float startX = xMin - seriesNr * halfDiffX + seriesIndex * 2 * halfDiffX;\r
+      drawBar(canvas, startX, yMax, startX + 2 * halfDiffX, yMin, scale, seriesIndex, paint);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Draws a bar.\r
+   * \r
+   * @param canvas the canvas\r
+   * @param xMin the X axis minimum\r
+   * @param yMin the Y axis minimum\r
+   * @param xMax the X axis maximum\r
+   * @param yMax the Y axis maximum\r
+   * @param scale the scale index\r
+   * @param seriesIndex the current series index\r
+   * @param paint the paint\r
+   */\r
+  private void drawBar(Canvas canvas, float xMin, float yMin, float xMax, float yMax, int scale,\r
+      int seriesIndex, Paint paint) {\r
+    SimpleSeriesRenderer renderer = mRenderer.getSeriesRendererAt(seriesIndex);\r
+    if (renderer.isGradientEnabled()) {\r
+      float minY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStopValue() }, scale)[1];\r
+      float maxY = (float) toScreenPoint(new double[] { 0, renderer.getGradientStartValue() },\r
+          scale)[1];\r
+      float gradientMinY = Math.max(minY, Math.min(yMin, yMax));\r
+      float gradientMaxY = Math.min(maxY, Math.max(yMin, yMax));\r
+      int gradientMinColor = renderer.getGradientStopColor();\r
+      int gradientMaxColor = renderer.getGradientStartColor();\r
+      int gradientStartColor = gradientMaxColor;\r
+      int gradientStopColor = gradientMinColor;\r
+\r
+      if (yMin < minY) {\r
+        paint.setColor(gradientMinColor);\r
+        canvas.drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax),\r
+            Math.round(gradientMinY), paint);\r
+      } else {\r
+        gradientStopColor = getGradientPartialColor(gradientMinColor, gradientMaxColor,\r
+            (maxY - gradientMinY) / (maxY - minY));\r
+      }\r
+      if (yMax > maxY) {\r
+        paint.setColor(gradientMaxColor);\r
+        canvas.drawRect(Math.round(xMin), Math.round(gradientMaxY), Math.round(xMax),\r
+            Math.round(yMax), paint);\r
+      } else {\r
+        gradientStartColor = getGradientPartialColor(gradientMaxColor, gradientMinColor,\r
+            (gradientMaxY - minY) / (maxY - minY));\r
+      }\r
+      GradientDrawable gradient = new GradientDrawable(Orientation.BOTTOM_TOP, new int[] {\r
+          gradientStartColor, gradientStopColor });\r
+      gradient.setBounds(Math.round(xMin), Math.round(gradientMinY), Math.round(xMax),\r
+          Math.round(gradientMaxY));\r
+      gradient.draw(canvas);\r
+    } else {\r
+      if (Math.abs(yMin - yMax) < 1) {\r
+        if (yMin < yMax) {\r
+          yMax = yMin + 1;\r
+        } else {\r
+          yMax = yMin - 1;\r
+        }\r
+      }\r
+      canvas\r
+          .drawRect(Math.round(xMin), Math.round(yMin), Math.round(xMax), Math.round(yMax), paint);\r
+    }\r
+  }\r
+\r
+  private int getGradientPartialColor(int minColor, int maxColor, float fraction) {\r
+    int alpha = Math.round(fraction * Color.alpha(minColor) + (1 - fraction)\r
+        * Color.alpha(maxColor));\r
+    int r = Math.round(fraction * Color.red(minColor) + (1 - fraction) * Color.red(maxColor));\r
+    int g = Math.round(fraction * Color.green(minColor) + (1 - fraction) * Color.green(maxColor));\r
+    int b = Math.round(fraction * Color.blue(minColor) + (1 - fraction) * Color.blue((maxColor)));\r
+    return Color.argb(alpha, r, g, b);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the series values as text.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param series the series to be painted\r
+   * @param renderer the series renderer\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,\r
+      Paint paint, float[] points, int seriesIndex, int startIndex) {\r
+    int seriesNr = mDataset.getSeriesCount();\r
+    float halfDiffX = getHalfDiffX(points, points.length, seriesNr);\r
+    for (int i = 0; i < points.length; i += 2) {\r
+      int index = startIndex + i / 2;\r
+      double value = series.getY(index);\r
+      if (!isNullValue(value)) {\r
+        float x = points[i];\r
+        if (mType == Type.DEFAULT) {\r
+          x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;\r
+        }\r
+        if (value >= 0) {\r
+          drawText(canvas, getLabel(value), x, points[i + 1] - renderer.getChartValuesSpacing(),\r
+              paint, 0);\r
+        } else {\r
+          drawText(canvas, getLabel(value), x, points[i + 1] + renderer.getChartValuesTextSize()\r
+              + renderer.getChartValuesSpacing() - 3, paint, 0);\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns the legend shape width.\r
+   * \r
+   * @param seriesIndex the series index\r
+   * @return the legend shape width\r
+   */\r
+  public int getLegendShapeWidth(int seriesIndex) {\r
+    return SHAPE_WIDTH;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the legend shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param seriesIndex the series index\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+      int seriesIndex, Paint paint) {\r
+    float halfShapeWidth = SHAPE_WIDTH / 2;\r
+    canvas.drawRect(x, y - halfShapeWidth, x + SHAPE_WIDTH, y + halfShapeWidth, paint);\r
+  }\r
+\r
+  /**\r
+   * Calculates and returns the half-distance in the graphical representation of\r
+   * 2 consecutive points.\r
+   * \r
+   * @param points the points\r
+   * @param length the points length\r
+   * @param seriesNr the series number\r
+   * @return the calculated half-distance value\r
+   */\r
+  protected float getHalfDiffX(float[] points, int length, int seriesNr) {\r
+    int div = length;\r
+    if (length > 2) {\r
+      div = length - 2;\r
+    }\r
+    float halfDiffX = (points[length - 2] - points[0]) / div;\r
+    if (halfDiffX == 0) {\r
+      halfDiffX = 10;\r
+    }\r
+\r
+    if (mType != Type.STACKED) {\r
+      halfDiffX /= seriesNr;\r
+    }\r
+    return (float) (halfDiffX / (getCoeficient() * (1 + mRenderer.getBarSpacing())));\r
+  }\r
+\r
+  /**\r
+   * Returns the value of a constant used to calculate the half-distance.\r
+   * \r
+   * @return the constant value\r
+   */\r
+  protected float getCoeficient() {\r
+    return 1f;\r
+  }\r
+\r
+  /**\r
+   * Returns if the chart should display the null values.\r
+   * \r
+   * @return if null values should be rendered\r
+   */\r
+  protected boolean isRenderNullValues() {\r
+    return true;\r
+  }\r
+\r
+  /**\r
+   * Returns the default axis minimum.\r
+   * \r
+   * @return the default axis minimum\r
+   */\r
+  public double getDefaultMinimum() {\r
+    return 0;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public String getChartType() {\r
+    return TYPE;\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/BubbleChart.java b/android-libraries/achartengine/src/org/achartengine/chart/BubbleChart.java
new file mode 100644 (file)
index 0000000..f312571
--- /dev/null
@@ -0,0 +1,146 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYValueSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * The bubble chart rendering class.\r
+ */\r
+public class BubbleChart extends XYChart {\r
+  /** The constant to identify this chart type. */\r
+  public static final String TYPE = "Bubble";\r
+  /** The legend shape width. */\r
+  private static final int SHAPE_WIDTH = 10;\r
+  /** The minimum bubble size. */\r
+  private static final int MIN_BUBBLE_SIZE = 2;\r
+  /** The maximum bubble size. */\r
+  private static final int MAX_BUBBLE_SIZE = 20;\r
+\r
+  BubbleChart() {\r
+  }\r
+\r
+  /**\r
+   * Builds a new bubble chart instance.\r
+   * \r
+   * @param dataset the multiple series dataset\r
+   * @param renderer the multiple series renderer\r
+   */\r
+  public BubbleChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    super(dataset, renderer);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a series.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesRenderer the series renderer\r
+   * @param yAxisValue the minimum value of the y axis\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+    XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;\r
+    paint.setColor(renderer.getColor());\r
+    paint.setStyle(Style.FILL);\r
+    int length = points.length;\r
+    XYValueSeries series = (XYValueSeries) mDataset.getSeriesAt(seriesIndex);\r
+    double max = series.getMaxValue();\r
+    double coef = MAX_BUBBLE_SIZE / max;\r
+    for (int i = 0; i < length; i += 2) {\r
+      double size = series.getValue(startIndex + i / 2) * coef + MIN_BUBBLE_SIZE;\r
+      drawCircle(canvas, paint, points[i], points[i + 1], (float) size);\r
+    }\r
+  }\r
+\r
+  @Override\r
+  protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+      float yAxisValue, int seriesIndex, int startIndex) {\r
+    int length = points.length;\r
+    XYValueSeries series = (XYValueSeries) mDataset.getSeriesAt(seriesIndex);\r
+    double max = series.getMaxValue();\r
+    double coef = MAX_BUBBLE_SIZE / max;\r
+    ClickableArea[] ret = new ClickableArea[length / 2];\r
+    for (int i = 0; i < length; i += 2) {\r
+      double size = series.getValue(startIndex + i / 2) * coef + MIN_BUBBLE_SIZE;\r
+      ret[i / 2] = new ClickableArea(new RectF(points[i] - (float) size, points[i + 1]\r
+          - (float) size, points[i] + (float) size, points[i + 1] + (float) size), values[i],\r
+          values[i + 1]);\r
+    }\r
+    return ret;\r
+  }\r
+\r
+  /**\r
+   * Returns the legend shape width.\r
+   * \r
+   * @param seriesIndex the series index\r
+   * @return the legend shape width\r
+   */\r
+  public int getLegendShapeWidth(int seriesIndex) {\r
+    return SHAPE_WIDTH;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the legend shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param seriesIndex the series index\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+      int seriesIndex, Paint paint) {\r
+    paint.setStyle(Style.FILL);\r
+    drawCircle(canvas, paint, x + SHAPE_WIDTH, y, 3);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a circle point shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param radius the bubble radius\r
+   */\r
+  private void drawCircle(Canvas canvas, Paint paint, float x, float y, float radius) {\r
+    canvas.drawCircle(x, y, radius, paint);\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public String getChartType() {\r
+    return TYPE;\r
+  }\r
+\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/ClickableArea.java b/android-libraries/achartengine/src/org/achartengine/chart/ClickableArea.java
new file mode 100644 (file)
index 0000000..d2d306c
--- /dev/null
@@ -0,0 +1,44 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import android.graphics.RectF;\r
+\r
+public class ClickableArea {\r
+  private RectF rect;\r
+  private double x;\r
+  private double y;\r
+\r
+  public ClickableArea(RectF rect, double x, double y) {\r
+    super();\r
+    this.rect = rect;\r
+    this.x = x;\r
+    this.y = y;\r
+  }\r
+\r
+  public RectF getRect() {\r
+    return rect;\r
+  }\r
+\r
+  public double getX() {\r
+    return x;\r
+  }\r
+\r
+  public double getY() {\r
+    return y;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/CombinedXYChart.java b/android-libraries/achartengine/src/org/achartengine/chart/CombinedXYChart.java
new file mode 100644 (file)
index 0000000..d684c3a
--- /dev/null
@@ -0,0 +1,177 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.util.List;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+\r
+/**\r
+ * The combined XY chart rendering class.\r
+ */\r
+public class CombinedXYChart extends XYChart {\r
+  /** The embedded XY charts. */\r
+  private XYChart[] mCharts;\r
+  /** The supported charts for being combined. */\r
+  private Class[] xyChartTypes = new Class[] { TimeChart.class, LineChart.class,\r
+      CubicLineChart.class, BarChart.class, BubbleChart.class, ScatterChart.class,\r
+      RangeBarChart.class, RangeStackedBarChart.class };\r
+\r
+  /**\r
+   * Builds a new combined XY chart instance.\r
+   * \r
+   * @param dataset the multiple series dataset\r
+   * @param renderer the multiple series renderer\r
+   * @param types the XY chart types\r
+   */\r
+  public CombinedXYChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer,\r
+      String[] types) {\r
+    super(dataset, renderer);\r
+    int length = types.length;\r
+    mCharts = new XYChart[length];\r
+    for (int i = 0; i < length; i++) {\r
+      try {\r
+        mCharts[i] = getXYChart(types[i]);\r
+      } catch (Exception e) {\r
+        // ignore\r
+      }\r
+      if (mCharts[i] == null) {\r
+        throw new IllegalArgumentException("Unknown chart type " + types[i]);\r
+      } else {\r
+        XYMultipleSeriesDataset newDataset = new XYMultipleSeriesDataset();\r
+        newDataset.addSeries(dataset.getSeriesAt(i));\r
+        XYMultipleSeriesRenderer newRenderer = new XYMultipleSeriesRenderer();\r
+        // TODO: copy other parameters here\r
+        newRenderer.setBarSpacing(renderer.getBarSpacing());\r
+        newRenderer.setPointSize(renderer.getPointSize());\r
+        int scale = dataset.getSeriesAt(i).getScaleNumber();\r
+        if (renderer.isMinXSet(scale)) {\r
+          newRenderer.setXAxisMin(renderer.getXAxisMin(scale));\r
+        }\r
+        if (renderer.isMaxXSet(scale)) {\r
+          newRenderer.setXAxisMax(renderer.getXAxisMax(scale));\r
+        }\r
+        if (renderer.isMinYSet(scale)) {\r
+          newRenderer.setYAxisMin(renderer.getYAxisMin(scale));\r
+        }\r
+        if (renderer.isMaxYSet(scale)) {\r
+          newRenderer.setYAxisMax(renderer.getYAxisMax(scale));\r
+        }\r
+        newRenderer.addSeriesRenderer(renderer.getSeriesRendererAt(i));\r
+        mCharts[i].setDatasetRenderer(newDataset, newRenderer);\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns a chart instance based on the provided type.\r
+   * \r
+   * @param type the chart type\r
+   * @return an instance of a chart implementation\r
+   * @throws IllegalAccessException\r
+   * @throws InstantiationException\r
+   */\r
+  private XYChart getXYChart(String type) throws IllegalAccessException, InstantiationException {\r
+    XYChart chart = null;\r
+    int length = xyChartTypes.length;\r
+    for (int i = 0; i < length && chart == null; i++) {\r
+      XYChart newChart = (XYChart) xyChartTypes[i].newInstance();\r
+      if (type.equals(newChart.getChartType())) {\r
+        chart = newChart;\r
+      }\r
+    }\r
+    return chart;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a series.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesRenderer the series renderer\r
+   * @param yAxisValue the minimum value of the y axis\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+    mCharts[seriesIndex].setScreenR(getScreenR());\r
+    mCharts[seriesIndex].setCalcRange(getCalcRange(mDataset.getSeriesAt(seriesIndex)\r
+        .getScaleNumber()), 0);\r
+    mCharts[seriesIndex].drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, 0,\r
+        startIndex);\r
+  }\r
+\r
+  @Override\r
+  protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+      float yAxisValue, int seriesIndex, int startIndex) {\r
+    return mCharts[seriesIndex].clickableAreasForPoints(points, values, yAxisValue, 0, startIndex);\r
+  }\r
+\r
+  @Override\r
+  protected void drawSeries(XYSeries series, Canvas canvas, Paint paint, List<Float> pointsList,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, Orientation or,\r
+      int startIndex) {\r
+    mCharts[seriesIndex].setScreenR(getScreenR());\r
+    mCharts[seriesIndex].setCalcRange(getCalcRange(mDataset.getSeriesAt(seriesIndex)\r
+        .getScaleNumber()), 0);\r
+    mCharts[seriesIndex].drawSeries(series, canvas, paint, pointsList, seriesRenderer, yAxisValue,\r
+        0, or, startIndex);\r
+  }\r
+\r
+  /**\r
+   * Returns the legend shape width.\r
+   * \r
+   * @param seriesIndex the series index\r
+   * @return the legend shape width\r
+   */\r
+  public int getLegendShapeWidth(int seriesIndex) {\r
+    return mCharts[seriesIndex].getLegendShapeWidth(0);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the legend shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param seriesIndex the series index\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+      int seriesIndex, Paint paint) {\r
+    mCharts[seriesIndex].drawLegendShape(canvas, renderer, x, y, 0, paint);\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public String getChartType() {\r
+    return "Combined";\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/CubicLineChart.java b/android-libraries/achartengine/src/org/achartengine/chart/CubicLineChart.java
new file mode 100644 (file)
index 0000000..2011318
--- /dev/null
@@ -0,0 +1,120 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.Point;\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Path;\r
+\r
+/**\r
+ * The interpolated (cubic) line chart rendering class.\r
+ */\r
+public class CubicLineChart extends LineChart {\r
+  /** The chart type. */\r
+  public static final String TYPE = "Cubic";\r
+\r
+  private float firstMultiplier;\r
+\r
+  private float secondMultiplier;\r
+\r
+  private Point p1 = new Point();\r
+\r
+  private Point p2 = new Point();\r
+\r
+  private Point p3 = new Point();\r
+\r
+  public CubicLineChart() {\r
+    // default is to have first control point at about 33% of the distance,\r
+    firstMultiplier = 0.33f;\r
+    // and the next at 66% of the distance.\r
+    secondMultiplier = 1 - firstMultiplier;\r
+  }\r
+\r
+  /**\r
+   * Builds a cubic line chart.\r
+   * \r
+   * @param dataset the dataset\r
+   * @param renderer the renderer\r
+   * @param smoothness smoothness determines how smooth the curve should be,\r
+   *          range [0->0.5] super smooth, 0.5, means that it might not get\r
+   *          close to control points if you have random data // less smooth,\r
+   *          (close to 0) means that it will most likely touch all control //\r
+   *          points\r
+   */\r
+  public CubicLineChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer,\r
+      float smoothness) {\r
+    super(dataset, renderer);\r
+    firstMultiplier = smoothness;\r
+    secondMultiplier = 1 - firstMultiplier;\r
+  }\r
+\r
+  @Override\r
+  protected void drawPath(Canvas canvas, float[] points, Paint paint, boolean circular) {\r
+    Path p = new Path();\r
+    float x = points[0];\r
+    float y = points[1];\r
+    p.moveTo(x, y);\r
+\r
+    int length = points.length;\r
+    if (circular) {\r
+      length -= 4;\r
+    }\r
+\r
+    for (int i = 0; i < length; i += 2) {\r
+      int nextIndex = i + 2 < length ? i + 2 : i;\r
+      int nextNextIndex = i + 4 < length ? i + 4 : nextIndex;\r
+      calc(points, p1, i, nextIndex, secondMultiplier);\r
+      p2.setX(points[nextIndex]);\r
+      p2.setY(points[nextIndex + 1]);\r
+      calc(points, p3, nextIndex, nextNextIndex, firstMultiplier);\r
+      // From last point, approaching x1/y1 and x2/y2 and ends up at x3/y3\r
+      p.cubicTo(p1.getX(), p1.getY(), p2.getX(), p2.getY(), p3.getX(), p3.getY());\r
+    }\r
+    if (circular) {\r
+      for (int i = length; i < length + 4; i += 2) {\r
+        p.lineTo(points[i], points[i + 1]);\r
+      }\r
+      p.lineTo(points[0], points[1]);\r
+    }\r
+    canvas.drawPath(p, paint);\r
+  }\r
+\r
+  private void calc(float[] points, Point result, int index1, int index2, final float multiplier) {\r
+    float p1x = points[index1];\r
+    float p1y = points[index1 + 1];\r
+    float p2x = points[index2];\r
+    float p2y = points[index2 + 1];\r
+\r
+    float diffX = p2x - p1x; // p2.x - p1.x;\r
+    float diffY = p2y - p1y; // p2.y - p1.y;\r
+    result.setX(p1x + (diffX * multiplier));\r
+    result.setY(p1y + (diffY * multiplier));\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public String getChartType() {\r
+    return TYPE;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/DialChart.java b/android-libraries/achartengine/src/org/achartengine/chart/DialChart.java
new file mode 100644 (file)
index 0000000..ebfcbbb
--- /dev/null
@@ -0,0 +1,236 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.CategorySeries;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.DialRenderer;\r
+import org.achartengine.renderer.DialRenderer.Type;\r
+import org.achartengine.util.MathHelper;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Align;\r
+import android.graphics.Paint.Style;\r
+\r
+/**\r
+ * The dial chart rendering class.\r
+ */\r
+public class DialChart extends RoundChart {\r
+  /** The radius of the needle. */\r
+  private static final int NEEDLE_RADIUS = 10;\r
+  /** The series renderer. */\r
+  private DialRenderer mRenderer;\r
+\r
+  /**\r
+   * Builds a new dial chart instance.\r
+   * \r
+   * @param dataset the series dataset\r
+   * @param renderer the dial renderer\r
+   */\r
+  public DialChart(CategorySeries dataset, DialRenderer renderer) {\r
+    super(dataset, renderer);\r
+    mRenderer = renderer;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the dial chart.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param x the top left x value of the view to draw to\r
+   * @param y the top left y value of the view to draw to\r
+   * @param width the width of the view to draw to\r
+   * @param height the height of the view to draw to\r
+   * @param paint the paint\r
+   */\r
+  @Override\r
+  public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {\r
+    paint.setAntiAlias(mRenderer.isAntialiasing());\r
+    paint.setStyle(Style.FILL);\r
+    paint.setTextSize(mRenderer.getLabelsTextSize());\r
+    int legendSize = getLegendSize(mRenderer, height / 5, 0);\r
+    int left = x;\r
+    int top = y;\r
+    int right = x + width;\r
+\r
+    int sLength = mDataset.getItemCount();\r
+    String[] titles = new String[sLength];\r
+    for (int i = 0; i < sLength; i++) {\r
+      titles[i] = mDataset.getCategory(i);\r
+    }\r
+\r
+    if (mRenderer.isFitLegend()) {\r
+      legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,\r
+          paint, true);\r
+    }\r
+    int bottom = y + height - legendSize;\r
+    drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);\r
+\r
+    int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));\r
+    int radius = (int) (mRadius * 0.35 * mRenderer.getScale());\r
+    if (mCenterX == NO_VALUE) {\r
+      mCenterX = (left + right) / 2;\r
+    }\r
+    if (mCenterY == NO_VALUE) {\r
+      mCenterY = (bottom + top) / 2;\r
+    }\r
+    float shortRadius = radius * 0.9f;\r
+    float longRadius = radius * 1.1f;\r
+    double min = mRenderer.getMinValue();\r
+    double max = mRenderer.getMaxValue();\r
+    double angleMin = mRenderer.getAngleMin();\r
+    double angleMax = mRenderer.getAngleMax();\r
+    if (!mRenderer.isMinValueSet() || !mRenderer.isMaxValueSet()) {\r
+      int count = mRenderer.getSeriesRendererCount();\r
+      for (int i = 0; i < count; i++) {\r
+        double value = mDataset.getValue(i);\r
+        if (!mRenderer.isMinValueSet()) {\r
+          min = Math.min(min, value);\r
+        }\r
+        if (!mRenderer.isMaxValueSet()) {\r
+          max = Math.max(max, value);\r
+        }\r
+      }\r
+    }\r
+    if (min == max) {\r
+      min = min * 0.5;\r
+      max = max * 1.5;\r
+    }\r
+\r
+    paint.setColor(mRenderer.getLabelsColor());\r
+    double minorTicks = mRenderer.getMinorTicksSpacing();\r
+    double majorTicks = mRenderer.getMajorTicksSpacing();\r
+    if (minorTicks == MathHelper.NULL_VALUE) {\r
+      minorTicks = (max - min) / 30;\r
+    }\r
+    if (majorTicks == MathHelper.NULL_VALUE) {\r
+      majorTicks = (max - min) / 10;\r
+    }\r
+    drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, radius,\r
+        minorTicks, paint, false);\r
+    drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, shortRadius,\r
+        majorTicks, paint, true);\r
+\r
+    int count = mRenderer.getSeriesRendererCount();\r
+    for (int i = 0; i < count; i++) {\r
+      double angle = getAngleForValue(mDataset.getValue(i), angleMin, angleMax, min, max);\r
+      paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());\r
+      boolean type = mRenderer.getVisualTypeForIndex(i) == Type.ARROW;\r
+      drawNeedle(canvas, angle, mCenterX, mCenterY, shortRadius, type, paint);\r
+    }\r
+    drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);\r
+    drawTitle(canvas, x, y, width, paint);\r
+  }\r
+\r
+  /**\r
+   * Returns the angle for a specific chart value.\r
+   * \r
+   * @param value the chart value\r
+   * @param minAngle the minimum chart angle value\r
+   * @param maxAngle the maximum chart angle value\r
+   * @param min the minimum chart value\r
+   * @param max the maximum chart value\r
+   * @return the angle\r
+   */\r
+  private double getAngleForValue(double value, double minAngle, double maxAngle, double min,\r
+      double max) {\r
+    double angleDiff = maxAngle - minAngle;\r
+    double diff = max - min;\r
+    return Math.toRadians(minAngle + (value - min) * angleDiff / diff);\r
+  }\r
+\r
+  /**\r
+   * Draws the chart tick lines.\r
+   * \r
+   * @param canvas the canvas\r
+   * @param min the minimum chart value\r
+   * @param max the maximum chart value\r
+   * @param minAngle the minimum chart angle value\r
+   * @param maxAngle the maximum chart angle value\r
+   * @param centerX the center x value\r
+   * @param centerY the center y value\r
+   * @param longRadius the long radius\r
+   * @param shortRadius the short radius\r
+   * @param ticks the tick spacing\r
+   * @param paint the paint settings\r
+   * @param labels paint the labels\r
+   * @return the angle\r
+   */\r
+  private void drawTicks(Canvas canvas, double min, double max, double minAngle, double maxAngle,\r
+      int centerX, int centerY, double longRadius, double shortRadius, double ticks, Paint paint,\r
+      boolean labels) {\r
+    for (double i = min; i <= max; i += ticks) {\r
+      double angle = getAngleForValue(i, minAngle, maxAngle, min, max);\r
+      double sinValue = Math.sin(angle);\r
+      double cosValue = Math.cos(angle);\r
+      int x1 = Math.round(centerX + (float) (shortRadius * sinValue));\r
+      int y1 = Math.round(centerY + (float) (shortRadius * cosValue));\r
+      int x2 = Math.round(centerX + (float) (longRadius * sinValue));\r
+      int y2 = Math.round(centerY + (float) (longRadius * cosValue));\r
+      canvas.drawLine(x1, y1, x2, y2, paint);\r
+      if (labels) {\r
+        paint.setTextAlign(Align.LEFT);\r
+        if (x1 <= x2) {\r
+          paint.setTextAlign(Align.RIGHT);\r
+        }\r
+        String text = i + "";\r
+        if (Math.round(i) == (long) i) {\r
+          text = (long) i + "";\r
+        }\r
+        canvas.drawText(text, x1, y1, paint);\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns the angle for a specific chart value.\r
+   * \r
+   * @param canvas the canvas\r
+   * @param angle the needle angle value\r
+   * @param centerX the center x value\r
+   * @param centerY the center y value\r
+   * @param radius the radius\r
+   * @param arrow if a needle or an arrow to be painted\r
+   * @param paint the paint settings\r
+   * @return the angle\r
+   */\r
+  private void drawNeedle(Canvas canvas, double angle, int centerX, int centerY, double radius,\r
+      boolean arrow, Paint paint) {\r
+    double diff = Math.toRadians(90);\r
+    int needleSinValue = (int) (NEEDLE_RADIUS * Math.sin(angle - diff));\r
+    int needleCosValue = (int) (NEEDLE_RADIUS * Math.cos(angle - diff));\r
+    int needleX = (int) (radius * Math.sin(angle));\r
+    int needleY = (int) (radius * Math.cos(angle));\r
+    int needleCenterX = centerX + needleX;\r
+    int needleCenterY = centerY + needleY;\r
+    float[] points;\r
+    if (arrow) {\r
+      int arrowBaseX = centerX + (int) (radius * 0.85 * Math.sin(angle));\r
+      int arrowBaseY = centerY + (int) (radius * 0.85 * Math.cos(angle));\r
+      points = new float[] { arrowBaseX - needleSinValue, arrowBaseY - needleCosValue,\r
+          needleCenterX, needleCenterY, arrowBaseX + needleSinValue, arrowBaseY + needleCosValue };\r
+      float width = paint.getStrokeWidth();\r
+      paint.setStrokeWidth(5);\r
+      canvas.drawLine(centerX, centerY, needleCenterX, needleCenterY, paint);\r
+      paint.setStrokeWidth(width);\r
+    } else {\r
+      points = new float[] { centerX - needleSinValue, centerY - needleCosValue, needleCenterX,\r
+          needleCenterY, centerX + needleSinValue, centerY + needleCosValue };\r
+    }\r
+    drawPath(canvas, points, paint, true);\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/DoughnutChart.java b/android-libraries/achartengine/src/org/achartengine/chart/DoughnutChart.java
new file mode 100644 (file)
index 0000000..ad67b07
--- /dev/null
@@ -0,0 +1,162 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.achartengine.model.MultipleCategorySeries;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Color;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * The doughnut chart rendering class.\r
+ */\r
+public class DoughnutChart extends RoundChart {\r
+  /** The series dataset. */\r
+  private MultipleCategorySeries mDataset;\r
+  /** A step variable to control the size of the legend shape. */\r
+  private int mStep;\r
+\r
+  /**\r
+   * Builds a new doughnut chart instance.\r
+   * \r
+   * @param dataset the series dataset\r
+   * @param renderer the series renderer\r
+   */\r
+  public DoughnutChart(MultipleCategorySeries dataset, DefaultRenderer renderer) {\r
+    super(null, renderer);\r
+    mDataset = dataset;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the doughnut chart.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param x the top left x value of the view to draw to\r
+   * @param y the top left y value of the view to draw to\r
+   * @param width the width of the view to draw to\r
+   * @param height the height of the view to draw to\r
+   * @param paint the paint\r
+   */\r
+  @Override\r
+  public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {\r
+    paint.setAntiAlias(mRenderer.isAntialiasing());\r
+    paint.setStyle(Style.FILL);\r
+    paint.setTextSize(mRenderer.getLabelsTextSize());\r
+    int legendSize = getLegendSize(mRenderer, height / 5, 0);\r
+    int left = x;\r
+    int top = y;\r
+    int right = x + width;\r
+    int cLength = mDataset.getCategoriesCount();\r
+    String[] categories = new String[cLength];\r
+    for (int category = 0; category < cLength; category++) {\r
+      categories[category] = mDataset.getCategory(category);\r
+    }\r
+    if (mRenderer.isFitLegend()) {\r
+      legendSize = drawLegend(canvas, mRenderer, categories, left, right, y, width, height,\r
+          legendSize, paint, true);\r
+    }\r
+\r
+    int bottom = y + height - legendSize;\r
+    drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);\r
+    mStep = SHAPE_WIDTH * 3 / 4;\r
+\r
+    int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));\r
+    double rCoef = 0.35 * mRenderer.getScale();\r
+    double decCoef = 0.2 / cLength;\r
+    int radius = (int) (mRadius * rCoef);\r
+    if (mCenterX == NO_VALUE) {\r
+      mCenterX = (left + right) / 2;\r
+    }\r
+    if (mCenterY == NO_VALUE) {\r
+      mCenterY = (bottom + top) / 2;\r
+    }\r
+    float shortRadius = radius * 0.9f;\r
+    float longRadius = radius * 1.1f;\r
+    List<RectF> prevLabelsBounds = new ArrayList<RectF>();\r
+    for (int category = 0; category < cLength; category++) {\r
+      int sLength = mDataset.getItemCount(category);\r
+      double total = 0;\r
+      String[] titles = new String[sLength];\r
+      for (int i = 0; i < sLength; i++) {\r
+        total += mDataset.getValues(category)[i];\r
+        titles[i] = mDataset.getTitles(category)[i];\r
+      }\r
+      float currentAngle = mRenderer.getStartAngle();\r
+      RectF oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY\r
+          + radius);\r
+      for (int i = 0; i < sLength; i++) {\r
+        paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());\r
+        float value = (float) mDataset.getValues(category)[i];\r
+        float angle = (float) (value / total * 360);\r
+        canvas.drawArc(oval, currentAngle, angle, true, paint);\r
+        drawLabel(canvas, mDataset.getTitles(category)[i], mRenderer, prevLabelsBounds, mCenterX,\r
+            mCenterY, shortRadius, longRadius, currentAngle, angle, left, right,\r
+            mRenderer.getLabelsColor(), paint, true);\r
+        currentAngle += angle;\r
+      }\r
+      radius -= (int) mRadius * decCoef;\r
+      shortRadius -= mRadius * decCoef - 2;\r
+      if (mRenderer.getBackgroundColor() != 0) {\r
+        paint.setColor(mRenderer.getBackgroundColor());\r
+      } else {\r
+        paint.setColor(Color.WHITE);\r
+      }\r
+      paint.setStyle(Style.FILL);\r
+      oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY + radius);\r
+      canvas.drawArc(oval, 0, 360, true, paint);\r
+      radius -= 1;\r
+    }\r
+    prevLabelsBounds.clear();\r
+    drawLegend(canvas, mRenderer, categories, left, right, y, width, height, legendSize, paint,\r
+        false);\r
+    drawTitle(canvas, x, y, width, paint);\r
+  }\r
+\r
+  /**\r
+   * Returns the legend shape width.\r
+   * \r
+   * @param seriesIndex the series index\r
+   * @return the legend shape width\r
+   */\r
+  public int getLegendShapeWidth(int seriesIndex) {\r
+    return SHAPE_WIDTH;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the legend shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param seriesIndex the series index\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+      int seriesIndex, Paint paint) {\r
+    mStep--;\r
+    canvas.drawCircle(x + SHAPE_WIDTH - mStep, y, mStep, paint);\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/LineChart.java b/android-libraries/achartengine/src/org/achartengine/chart/LineChart.java
new file mode 100644 (file)
index 0000000..2c45898
--- /dev/null
@@ -0,0 +1,175 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * The line chart rendering class.\r
+ */\r
+public class LineChart extends XYChart {\r
+  /** The constant to identify this chart type. */\r
+  public static final String TYPE = "Line";\r
+  /** The legend shape width. */\r
+  private static final int SHAPE_WIDTH = 30;\r
+  /** The scatter chart to be used to draw the data points. */\r
+  private ScatterChart pointsChart;\r
+\r
+  LineChart() {\r
+  }\r
+\r
+  /**\r
+   * Builds a new line chart instance.\r
+   * \r
+   * @param dataset the multiple series dataset\r
+   * @param renderer the multiple series renderer\r
+   */\r
+  public LineChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    super(dataset, renderer);\r
+    pointsChart = new ScatterChart(dataset, renderer);\r
+  }\r
+\r
+  /**\r
+   * Sets the series and the renderer.\r
+   * \r
+   * @param dataset the series dataset\r
+   * @param renderer the series renderer\r
+   */\r
+  protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer) {\r
+    super.setDatasetRenderer(dataset, renderer);\r
+    pointsChart = new ScatterChart(dataset, renderer);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a series.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesRenderer the series renderer\r
+   * @param yAxisValue the minimum value of the y axis\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+    int length = points.length;\r
+    XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;\r
+    float lineWidth = paint.getStrokeWidth();\r
+    paint.setStrokeWidth(renderer.getLineWidth());\r
+    if (renderer.isFillBelowLine()) {\r
+      paint.setColor(renderer.getFillBelowLineColor());\r
+      int pLength = points.length;\r
+      float[] fillPoints = new float[pLength + 4];\r
+      System.arraycopy(points, 0, fillPoints, 0, length);\r
+      fillPoints[0] = points[0] + 1;\r
+      fillPoints[length] = fillPoints[length - 2];\r
+      fillPoints[length + 1] = yAxisValue;\r
+      fillPoints[length + 2] = fillPoints[0];\r
+      fillPoints[length + 3] = fillPoints[length + 1];\r
+      for (int i = 0; i < length + 4; i += 2) {\r
+        if (fillPoints[i + 1] < 0) {\r
+          fillPoints[i + 1] = 0;\r
+        }\r
+      }\r
+      paint.setStyle(Style.FILL);\r
+      drawPath(canvas, fillPoints, paint, true);\r
+    }\r
+    paint.setColor(seriesRenderer.getColor());\r
+    paint.setStyle(Style.STROKE);\r
+    drawPath(canvas, points, paint, false);\r
+    paint.setStrokeWidth(lineWidth);\r
+  }\r
+\r
+  @Override\r
+  protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+      float yAxisValue, int seriesIndex, int startIndex) {\r
+    int length = points.length;\r
+    ClickableArea[] ret = new ClickableArea[length / 2];\r
+    for (int i = 0; i < length; i += 2) {\r
+      int selectableBuffer = mRenderer.getSelectableBuffer();\r
+      ret[i / 2] = new ClickableArea(new RectF(points[i] - selectableBuffer, points[i + 1]\r
+          - selectableBuffer, points[i] + selectableBuffer, points[i + 1] + selectableBuffer),\r
+          values[i], values[i + 1]);\r
+    }\r
+    return ret;\r
+  }\r
+\r
+  /**\r
+   * Returns the legend shape width.\r
+   * \r
+   * @param seriesIndex the series index\r
+   * @return the legend shape width\r
+   */\r
+  public int getLegendShapeWidth(int seriesIndex) {\r
+    return SHAPE_WIDTH;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the legend shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param seriesIndex the series index\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+      int seriesIndex, Paint paint) {\r
+    canvas.drawLine(x, y, x + SHAPE_WIDTH, y, paint);\r
+    if (isRenderPoints(renderer)) {\r
+      pointsChart.drawLegendShape(canvas, renderer, x + 5, y, seriesIndex, paint);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns if the chart should display the points as a certain shape.\r
+   * \r
+   * @param renderer the series renderer\r
+   */\r
+  public boolean isRenderPoints(SimpleSeriesRenderer renderer) {\r
+    return ((XYSeriesRenderer) renderer).getPointStyle() != PointStyle.POINT;\r
+  }\r
+\r
+  /**\r
+   * Returns the scatter chart to be used for drawing the data points.\r
+   * \r
+   * @return the data points scatter chart\r
+   */\r
+  public ScatterChart getPointsChart() {\r
+    return pointsChart;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public String getChartType() {\r
+    return TYPE;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/PieChart.java b/android-libraries/achartengine/src/org/achartengine/chart/PieChart.java
new file mode 100644 (file)
index 0000000..d656a95
--- /dev/null
@@ -0,0 +1,136 @@
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.chart;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.achartengine.model.CategorySeries;
+import org.achartengine.model.Point;
+import org.achartengine.model.SeriesSelection;
+import org.achartengine.renderer.DefaultRenderer;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.RectF;
+
+/**
+ * The pie chart rendering class.
+ */
+public class PieChart extends RoundChart {
+  /** Handles returning values when tapping on PieChart. */
+  private PieMapper mPieMapper;
+
+  /**
+   * Builds a new pie chart instance.
+   * 
+   * @param dataset the series dataset
+   * @param renderer the series renderer
+   */
+  public PieChart(CategorySeries dataset, DefaultRenderer renderer) {
+    super(dataset, renderer);
+    mPieMapper = new PieMapper();
+  }
+
+  /**
+   * The graphical representation of the pie chart.
+   * 
+   * @param canvas the canvas to paint to
+   * @param x the top left x value of the view to draw to
+   * @param y the top left y value of the view to draw to
+   * @param width the width of the view to draw to
+   * @param height the height of the view to draw to
+   * @param paint the paint
+   */
+  @Override
+  public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {
+    paint.setAntiAlias(mRenderer.isAntialiasing());
+    paint.setStyle(Style.FILL);
+    paint.setTextSize(mRenderer.getLabelsTextSize());
+    int legendSize = getLegendSize(mRenderer, height / 5, 0);
+    int left = x;
+    int top = y;
+    int right = x + width;
+    int sLength = mDataset.getItemCount();
+    double total = 0;
+    String[] titles = new String[sLength];
+    for (int i = 0; i < sLength; i++) {
+      total += mDataset.getValue(i);
+      titles[i] = mDataset.getCategory(i);
+    }
+    if (mRenderer.isFitLegend()) {
+      legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,
+          paint, true);
+    }
+    int bottom = y + height - legendSize;
+    drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);
+
+    float currentAngle = mRenderer.getStartAngle();
+    int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));
+    int radius = (int) (mRadius * 0.35 * mRenderer.getScale());
+
+    if (mCenterX == NO_VALUE) {
+      mCenterX = (left + right) / 2;
+    }
+    if (mCenterY == NO_VALUE) {
+      mCenterY = (bottom + top) / 2;
+    }
+
+    // Hook in clip detection after center has been calculated
+    mPieMapper.setDimensions(radius, mCenterX, mCenterY);
+    boolean loadPieCfg = !mPieMapper.areAllSegmentPresent(sLength);
+    if (loadPieCfg) {
+      mPieMapper.clearPieSegments();
+    }
+
+    float shortRadius = radius * 0.9f;
+    float longRadius = radius * 1.1f;
+
+    RectF oval = new RectF(mCenterX - radius, mCenterY - radius, mCenterX + radius, mCenterY
+        + radius);
+    List<RectF> prevLabelsBounds = new ArrayList<RectF>();
+
+    for (int i = 0; i < sLength; i++) {
+      paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());
+      float value = (float) mDataset.getValue(i);
+      float angle = (float) (value / total * 360);
+      canvas.drawArc(oval, currentAngle, angle, true, paint);
+      drawLabel(canvas, mDataset.getCategory(i), mRenderer, prevLabelsBounds, mCenterX, mCenterY,
+          shortRadius, longRadius, currentAngle, angle, left, right, mRenderer.getLabelsColor(),
+          paint, true);
+      if (mRenderer.isDisplayValues()) {
+        drawLabel(canvas, getLabel(mDataset.getValue(i)), mRenderer, prevLabelsBounds, mCenterX,
+            mCenterY, shortRadius / 2, longRadius / 2, currentAngle, angle, left, right,
+            mRenderer.getLabelsColor(), paint, false);
+      }
+
+      // Save details for getSeries functionality
+      if (loadPieCfg) {
+        mPieMapper.addPieSegment(i, value, currentAngle, angle);
+      }
+      currentAngle += angle;
+    }
+    prevLabelsBounds.clear();
+    drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);
+    drawTitle(canvas, x, y, width, paint);
+  }
+
+  public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
+    return mPieMapper.getSeriesAndPointForScreenCoordinate(screenPoint);
+  }
+
+}
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/PieMapper.java b/android-libraries/achartengine/src/org/achartengine/chart/PieMapper.java
new file mode 100644 (file)
index 0000000..6e4b715
--- /dev/null
@@ -0,0 +1,139 @@
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.chart;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.achartengine.model.Point;
+import org.achartengine.model.SeriesSelection;
+
+/**
+ * PieChart Segment Selection Management.
+ */
+public class PieMapper implements Serializable {
+
+  private List<PieSegment> mPieSegmentList = new ArrayList<PieSegment>();
+
+  private int mPieChartRadius;
+
+  private int mCenterX, mCenterY;
+
+  /**
+   * Set PieChart location on screen.
+   * 
+   * @param pieRadius
+   * @param centerX
+   * @param centerY
+   */
+  public void setDimensions(int pieRadius, int centerX, int centerY) {
+    mPieChartRadius = pieRadius;
+    mCenterX = centerX;
+    mCenterY = centerY;
+  }
+
+  /**
+   * If we have all PieChart Config then there is no point in reloading it
+   * 
+   * @param datasetSize
+   * @return true if cfg for each segment is present
+   */
+  public boolean areAllSegmentPresent(int datasetSize) {
+    return mPieSegmentList.size() == datasetSize;
+  }
+  
+  /**
+   * Add configuration for a PieChart Segment
+   * 
+   * @param dataIndex
+   * @param value
+   * @param startAngle
+   * @param angle
+   */
+  public void addPieSegment(int dataIndex, float value, float startAngle, float angle) {
+    mPieSegmentList.add(new PieSegment(dataIndex, value, startAngle, angle));
+  }
+  
+  /**
+   * Clears the pie segments list.
+   */
+  public void clearPieSegments() {
+    mPieSegmentList.clear();
+  }
+
+  /**
+   * Fetches angle relative to pie chart center point where 3 O'Clock is 0 and
+   * 12 O'Clock is 270degrees
+   * 
+   * @param screenPoint
+   * @return angle in degress from 0-360.
+   */
+  public double getAngle(Point screenPoint) {
+    double dx = screenPoint.getX() - mCenterX;
+    // Minus to correct for coord re-mapping
+    double dy = -(screenPoint.getY() - mCenterY);
+
+    double inRads = Math.atan2(dy, dx);
+
+    // We need to map to coord system when 0 degree is at 3 O'clock, 270 at 12
+    // O'clock
+    if (inRads < 0)
+      inRads = Math.abs(inRads);
+    else
+      inRads = 2 * Math.PI - inRads;
+
+    return Math.toDegrees(inRads);
+  }
+
+  /**
+   * Checks if Point falls within PieChart
+   * 
+   * @param screenPoint
+   * @return true if in PieChart
+   */
+  public boolean isOnPieChart(Point screenPoint) {
+    // Using a bit of Pythagoras
+    // inside circle if (x-center_x)**2 + (y-center_y)**2 <= radius**2:
+
+    double sqValue = (Math.pow(mCenterX - screenPoint.getX(), 2) + Math.pow(
+        mCenterY - screenPoint.getY(), 2));
+
+    double radiusSquared = mPieChartRadius * mPieChartRadius;
+    boolean isOnPieChart = sqValue <= radiusSquared;
+    return isOnPieChart;
+  }
+
+  /**
+   * Fetches the SeriesSelection for the PieSegment selected.
+   * 
+   * @param screenPoint - the user tap location
+   * @return null if screen point is not in PieChart or its config if it is
+   */
+  public SeriesSelection getSeriesAndPointForScreenCoordinate(Point screenPoint) {
+    if (isOnPieChart(screenPoint)) {
+      double angleFromPieCenter = getAngle(screenPoint);
+
+      for (PieSegment pieSeg : mPieSegmentList) {
+        if (pieSeg.isInSegment(angleFromPieCenter)) {
+          return new SeriesSelection(0, pieSeg.getDataIndex(), pieSeg.getValue(),
+              pieSeg.getValue());
+        }
+      }
+    }
+    return null;
+  }
+}
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/PieSegment.java b/android-libraries/achartengine/src/org/achartengine/chart/PieSegment.java
new file mode 100644 (file)
index 0000000..0fb0a2e
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.chart;
+
+import java.io.Serializable;
+
+/**
+ * Holds An PieChart Segment
+ */
+public class PieSegment implements Serializable {
+  private float mStartAngle;
+
+  private float mEndAngle;
+
+  private int mDataIndex;
+
+  private float mValue;
+
+  public PieSegment(int dataIndex, float value, float startAngle, float angle) {
+    mStartAngle = startAngle;
+    mEndAngle = angle + startAngle;
+    mDataIndex = dataIndex;
+    mValue = value;
+  }
+
+  /**
+   * Checks if angle falls in segment.
+   * 
+   * @param angle
+   * @return true if in segment, false otherwise.
+   */
+  public boolean isInSegment(double angle) {
+    return angle >= mStartAngle && angle <= mEndAngle;
+  }
+
+  protected float getStartAngle() {
+    return mStartAngle;
+  }
+
+  protected float getEndAngle() {
+    return mEndAngle;
+  }
+
+  protected int getDataIndex() {
+    return mDataIndex;
+  }
+
+  protected float getValue() {
+    return mValue;
+  }
+
+  public String toString() {
+    return "mDataIndex=" + mDataIndex + ",mValue=" + mValue + ",mStartAngle=" + mStartAngle
+        + ",mEndAngle=" + mEndAngle;
+  }
+
+}
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/PointStyle.java b/android-libraries/achartengine/src/org/achartengine/chart/PointStyle.java
new file mode 100644 (file)
index 0000000..29a2311
--- /dev/null
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.chart;
+
+/**
+ * The chart point style enumerator.
+ */
+public enum PointStyle {
+  X("x"), CIRCLE("circle"), TRIANGLE("triangle"), SQUARE("square"), DIAMOND("diamond"), POINT(
+      "point");
+
+  /** The point shape name. */
+  private String mName;
+
+  /**
+   * The point style enum constructor.
+   * 
+   * @param name the name
+   */
+  private PointStyle(String name) {
+    mName = name;
+  }
+
+  /**
+   * Returns the point shape name.
+   * 
+   * @return the point shape name
+   */
+  public String getName() {
+    return mName;
+  }
+
+  /**
+   * Returns the point shape name.
+   * 
+   * @return the point shape name
+   */
+  public String toString() {
+    return getName();
+  }
+
+  /**
+   * Return the point shape that has the provided symbol.
+   * 
+   * @param name the point style name
+   * @return the point shape
+   */
+  public static PointStyle getPointStyleForName(String name) {
+    PointStyle pointStyle = null;
+    PointStyle[] styles = values();
+    int length = styles.length;
+    for (int i = 0; i < length && pointStyle == null; i++) {
+      if (styles[i].mName.equals(name)) {
+        pointStyle = styles[i];
+      }
+    }
+    return pointStyle;
+  }
+
+  /**
+   * Returns the point shape index based on the given name.
+   * 
+   * @return the point shape index
+   */
+  public static int getIndexForName(String name) {
+    int index = -1;
+    PointStyle[] styles = values();
+    int length = styles.length;
+    for (int i = 0; i < length && index < 0; i++) {
+      if (styles[i].mName.equals(name)) {
+        index = i;
+      }
+    }
+    return Math.max(0, index);
+  }
+
+}
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/RangeBarChart.java b/android-libraries/achartengine/src/org/achartengine/chart/RangeBarChart.java
new file mode 100644 (file)
index 0000000..105f509
--- /dev/null
@@ -0,0 +1,145 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+\r
+/**\r
+ * The range bar chart rendering class.\r
+ */\r
+public class RangeBarChart extends BarChart {\r
+  /** The chart type. */\r
+  public static final String TYPE = "RangeBar";\r
+\r
+  RangeBarChart() {\r
+  }\r
+\r
+  RangeBarChart(Type type) {\r
+    super(type);\r
+  }\r
+\r
+  /**\r
+   * Builds a new range bar chart instance.\r
+   * \r
+   * @param dataset the multiple series dataset\r
+   * @param renderer the multiple series renderer\r
+   * @param type the range bar chart type\r
+   */\r
+  public RangeBarChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer, Type type) {\r
+    super(dataset, renderer, type);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a series.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesRenderer the series renderer\r
+   * @param yAxisValue the minimum value of the y axis\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+    int seriesNr = mDataset.getSeriesCount();\r
+    int length = points.length;\r
+    paint.setColor(seriesRenderer.getColor());\r
+    paint.setStyle(Style.FILL);\r
+    float halfDiffX = getHalfDiffX(points, length, seriesNr);\r
+    int start = 0;\r
+    if (startIndex > 0) {\r
+      start = 2;\r
+    }\r
+    for (int i = start; i < length; i += 4) {\r
+      if (points.length > i + 3) {\r
+        float xMin = points[i];\r
+        float yMin = points[i + 1];\r
+        // xMin = xMax\r
+        float xMax = points[i + 2];\r
+        float yMax = points[i + 3];\r
+        drawBar(canvas, xMin, yMin, xMax, yMax, halfDiffX, seriesNr, seriesIndex, paint);\r
+      }\r
+    }\r
+    paint.setColor(seriesRenderer.getColor());\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the series values as text.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param series the series to be painted\r
+   * @param renderer the series renderer\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,\r
+      Paint paint, float[] points, int seriesIndex, int startIndex) {\r
+    int seriesNr = mDataset.getSeriesCount();\r
+    float halfDiffX = getHalfDiffX(points, points.length, seriesNr);\r
+    int start = 0;\r
+    if (startIndex > 0) {\r
+      start = 2;\r
+    }\r
+    for (int i = start; i < points.length; i += 4) {\r
+      int index = startIndex + i / 2;\r
+      float x = points[i];\r
+      if (mType == Type.DEFAULT) {\r
+        x += seriesIndex * 2 * halfDiffX - (seriesNr - 1.5f) * halfDiffX;\r
+      }\r
+\r
+      if (!isNullValue(series.getY(index + 1)) && points.length > i + 3) {\r
+        // draw the maximum value\r
+        drawText(canvas, getLabel(series.getY(index + 1)), x,\r
+            points[i + 3] - renderer.getChartValuesSpacing(), paint, 0);\r
+      }\r
+      if (!isNullValue(series.getY(index)) && points.length > i + 1) {\r
+        // draw the minimum value\r
+        drawText(canvas, getLabel(series.getY(index)), x,\r
+            points[i + 1] + renderer.getChartValuesTextSize() + renderer.getChartValuesSpacing()\r
+                - 3, paint, 0);\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns the value of a constant used to calculate the half-distance.\r
+   * \r
+   * @return the constant value\r
+   */\r
+  protected float getCoeficient() {\r
+    return 0.5f;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public String getChartType() {\r
+    return TYPE;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/RangeStackedBarChart.java b/android-libraries/achartengine/src/org/achartengine/chart/RangeStackedBarChart.java
new file mode 100644 (file)
index 0000000..4da4f00
--- /dev/null
@@ -0,0 +1,29 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+public class RangeStackedBarChart extends RangeBarChart {\r
+  /** The chart type. */\r
+  public static final String TYPE = "RangeStackedBar";\r
+\r
+  RangeStackedBarChart() {\r
+    super(Type.STACKED);\r
+  }\r
+\r
+  public String getChartType() {\r
+    return TYPE;\r
+  }\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/RoundChart.java b/android-libraries/achartengine/src/org/achartengine/chart/RoundChart.java
new file mode 100644 (file)
index 0000000..1a2121d
--- /dev/null
@@ -0,0 +1,143 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.CategorySeries;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Align;\r
+\r
+/**\r
+ * An abstract class to be extended by round like chart rendering classes.\r
+ */\r
+public abstract class RoundChart extends AbstractChart {\r
+  /** The legend shape width. */\r
+  protected static final int SHAPE_WIDTH = 10;\r
+  /** The series dataset. */\r
+  protected CategorySeries mDataset;\r
+  /** The series renderer. */\r
+  protected DefaultRenderer mRenderer;\r
+  /** A no value constant. */\r
+  protected static final int NO_VALUE = Integer.MAX_VALUE;\r
+  /** The chart center X axis. */\r
+  protected int mCenterX = NO_VALUE;\r
+  /** The chart center y axis. */\r
+  protected int mCenterY = NO_VALUE;\r
+\r
+  /**\r
+   * Round chart.\r
+   * \r
+   * @param dataset the series dataset\r
+   * @param renderer the series renderer\r
+   */\r
+  public RoundChart(CategorySeries dataset, DefaultRenderer renderer) {\r
+    mDataset = dataset;\r
+    mRenderer = renderer;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the round chart title.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param x the top left x value of the view to draw to\r
+   * @param y the top left y value of the view to draw to\r
+   * @param width the width of the view to draw to\r
+   * @param paint the paint\r
+   */\r
+  public void drawTitle(Canvas canvas, int x, int y, int width, Paint paint) {\r
+    if (mRenderer.isShowLabels()) {\r
+      paint.setColor(mRenderer.getLabelsColor());\r
+      paint.setTextAlign(Align.CENTER);\r
+      paint.setTextSize(mRenderer.getChartTitleTextSize());\r
+      drawString(canvas, mRenderer.getChartTitle(), x + width / 2,\r
+          y + mRenderer.getChartTitleTextSize(), paint);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns the legend shape width.\r
+   * \r
+   * @param seriesIndex the series index\r
+   * @return the legend shape width\r
+   */\r
+  public int getLegendShapeWidth(int seriesIndex) {\r
+    return SHAPE_WIDTH;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the legend shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param seriesIndex the series index\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+      int seriesIndex, Paint paint) {\r
+    canvas.drawRect(x, y - SHAPE_WIDTH / 2, x + SHAPE_WIDTH, y + SHAPE_WIDTH / 2, paint);\r
+  }\r
+\r
+  /**\r
+   * Returns the renderer.\r
+   * \r
+   * @return the renderer\r
+   */\r
+  public DefaultRenderer getRenderer() {\r
+    return mRenderer;\r
+  }\r
+\r
+  /**\r
+   * Returns the center on X axis.\r
+   * \r
+   * @return the center on X axis\r
+   */\r
+  public int getCenterX() {\r
+    return mCenterX;\r
+  }\r
+\r
+  /**\r
+   * Returns the center on Y axis.\r
+   * \r
+   * @return the center on Y axis\r
+   */\r
+  public int getCenterY() {\r
+    return mCenterY;\r
+  }\r
+\r
+  /**\r
+   * Sets a new center on X axis.\r
+   * \r
+   * @param centerX center on X axis\r
+   */\r
+  public void setCenterX(int centerX) {\r
+    mCenterX = centerX;\r
+  }\r
+\r
+  /**\r
+   * Sets a new center on Y axis.\r
+   * \r
+   * @param centerY center on Y axis\r
+   */\r
+  public void setCenterY(int centerY) {\r
+    mCenterY = centerY;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/ScatterChart.java b/android-libraries/achartengine/src/org/achartengine/chart/ScatterChart.java
new file mode 100644 (file)
index 0000000..1d3b2a1
--- /dev/null
@@ -0,0 +1,266 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.RectF;\r
+\r
+/**\r
+ * The scatter chart rendering class.\r
+ */\r
+public class ScatterChart extends XYChart {\r
+  /** The constant to identify this chart type. */\r
+  public static final String TYPE = "Scatter";\r
+  /** The default point shape size. */\r
+  private static final float SIZE = 3;\r
+  /** The legend shape width. */\r
+  private static final int SHAPE_WIDTH = 10;\r
+  /** The point shape size. */\r
+  private float size = SIZE;\r
+\r
+  ScatterChart() {\r
+  }\r
+\r
+  /**\r
+   * Builds a new scatter chart instance.\r
+   * \r
+   * @param dataset the multiple series dataset\r
+   * @param renderer the multiple series renderer\r
+   */\r
+  public ScatterChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    super(dataset, renderer);\r
+    size = renderer.getPointSize();\r
+  }\r
+\r
+  // TODO: javadoc\r
+  protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer) {\r
+    super.setDatasetRenderer(dataset, renderer);\r
+    size = renderer.getPointSize();\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a series.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesRenderer the series renderer\r
+   * @param yAxisValue the minimum value of the y axis\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  public void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex) {\r
+    XYSeriesRenderer renderer = (XYSeriesRenderer) seriesRenderer;\r
+    paint.setColor(renderer.getColor());\r
+    if (renderer.isFillPoints()) {\r
+      paint.setStyle(Style.FILL);\r
+    } else {\r
+      paint.setStyle(Style.STROKE);\r
+    }\r
+    int length = points.length;\r
+    switch (renderer.getPointStyle()) {\r
+    case X:\r
+      for (int i = 0; i < length; i += 2) {\r
+        drawX(canvas, paint, points[i], points[i + 1]);\r
+      }\r
+      break;\r
+    case CIRCLE:\r
+      for (int i = 0; i < length; i += 2) {\r
+        drawCircle(canvas, paint, points[i], points[i + 1]);\r
+      }\r
+      break;\r
+    case TRIANGLE:\r
+      float[] path = new float[6];\r
+      for (int i = 0; i < length; i += 2) {\r
+        drawTriangle(canvas, paint, path, points[i], points[i + 1]);\r
+      }\r
+      break;\r
+    case SQUARE:\r
+      for (int i = 0; i < length; i += 2) {\r
+        drawSquare(canvas, paint, points[i], points[i + 1]);\r
+      }\r
+      break;\r
+    case DIAMOND:\r
+      path = new float[8];\r
+      for (int i = 0; i < length; i += 2) {\r
+        drawDiamond(canvas, paint, path, points[i], points[i + 1]);\r
+      }\r
+      break;\r
+    case POINT:\r
+      canvas.drawPoints(points, paint);\r
+      break;\r
+    }\r
+  }\r
+\r
+  @Override\r
+  protected ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+      float yAxisValue, int seriesIndex, int startIndex) {\r
+    int length = points.length;\r
+    ClickableArea[] ret = new ClickableArea[length / 2];\r
+    for (int i = 0; i < length; i += 2) {\r
+      int selectableBuffer = mRenderer.getSelectableBuffer();\r
+      ret[i / 2] = new ClickableArea(new RectF(points[i] - selectableBuffer, points[i + 1]\r
+          - selectableBuffer, points[i] + selectableBuffer, points[i + 1] + selectableBuffer),\r
+          values[i], values[i + 1]);\r
+    }\r
+    return ret;\r
+  }\r
+\r
+  /**\r
+   * Returns the legend shape width.\r
+   * \r
+   * @param seriesIndex the series index\r
+   * @return the legend shape width\r
+   */\r
+  public int getLegendShapeWidth(int seriesIndex) {\r
+    return SHAPE_WIDTH;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the legend shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param renderer the series renderer\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   * @param seriesIndex the series index\r
+   * @param paint the paint to be used for drawing\r
+   */\r
+  public void drawLegendShape(Canvas canvas, SimpleSeriesRenderer renderer, float x, float y,\r
+      int seriesIndex, Paint paint) {\r
+    if (((XYSeriesRenderer) renderer).isFillPoints()) {\r
+      paint.setStyle(Style.FILL);\r
+    } else {\r
+      paint.setStyle(Style.STROKE);\r
+    }\r
+    switch (((XYSeriesRenderer) renderer).getPointStyle()) {\r
+    case X:\r
+      drawX(canvas, paint, x + SHAPE_WIDTH, y);\r
+      break;\r
+    case CIRCLE:\r
+      drawCircle(canvas, paint, x + SHAPE_WIDTH, y);\r
+      break;\r
+    case TRIANGLE:\r
+      drawTriangle(canvas, paint, new float[6], x + SHAPE_WIDTH, y);\r
+      break;\r
+    case SQUARE:\r
+      drawSquare(canvas, paint, x + SHAPE_WIDTH, y);\r
+      break;\r
+    case DIAMOND:\r
+      drawDiamond(canvas, paint, new float[8], x + SHAPE_WIDTH, y);\r
+      break;\r
+    case POINT:\r
+      canvas.drawPoint(x + SHAPE_WIDTH, y, paint);\r
+      break;\r
+    }\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of an X point shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   */\r
+  private void drawX(Canvas canvas, Paint paint, float x, float y) {\r
+    canvas.drawLine(x - size, y - size, x + size, y + size, paint);\r
+    canvas.drawLine(x + size, y - size, x - size, y + size, paint);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a circle point shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   */\r
+  private void drawCircle(Canvas canvas, Paint paint, float x, float y) {\r
+    canvas.drawCircle(x, y, size, paint);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a triangle point shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param path the triangle path\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   */\r
+  private void drawTriangle(Canvas canvas, Paint paint, float[] path, float x, float y) {\r
+    path[0] = x;\r
+    path[1] = y - size - size / 2;\r
+    path[2] = x - size;\r
+    path[3] = y + size;\r
+    path[4] = x + size;\r
+    path[5] = path[3];\r
+    drawPath(canvas, path, paint, true);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a square point shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   */\r
+  private void drawSquare(Canvas canvas, Paint paint, float x, float y) {\r
+    canvas.drawRect(x - size, y - size, x + size, y + size, paint);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a diamond point shape.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param path the diamond path\r
+   * @param x the x value of the point the shape should be drawn at\r
+   * @param y the y value of the point the shape should be drawn at\r
+   */\r
+  private void drawDiamond(Canvas canvas, Paint paint, float[] path, float x, float y) {\r
+    path[0] = x;\r
+    path[1] = y - size;\r
+    path[2] = x - size;\r
+    path[3] = y;\r
+    path[4] = x;\r
+    path[5] = y + size;\r
+    path[6] = x + size;\r
+    path[7] = y;\r
+    drawPath(canvas, path, paint, true);\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public String getChartType() {\r
+    return TYPE;\r
+  }\r
+\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/TimeChart.java b/android-libraries/achartengine/src/org/achartengine/chart/TimeChart.java
new file mode 100644 (file)
index 0000000..ba201de
--- /dev/null
@@ -0,0 +1,226 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.text.DateFormat;\r
+import java.text.SimpleDateFormat;\r
+import java.util.ArrayList;\r
+import java.util.Date;\r
+import java.util.List;\r
+\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.Paint;\r
+\r
+/**\r
+ * The time chart rendering class.\r
+ */\r
+public class TimeChart extends LineChart {\r
+  /** The constant to identify this chart type. */\r
+  public static final String TYPE = "Time";\r
+  /** The number of milliseconds in a day. */\r
+  public static final long DAY = 24 * 60 * 60 * 1000;\r
+  /** The date format pattern to be used in formatting the X axis labels. */\r
+  private String mDateFormat;\r
+  /** The starting point for labels. */\r
+  private Double mStartPoint;\r
+\r
+  TimeChart() {\r
+  }\r
+\r
+  /**\r
+   * Builds a new time chart instance.\r
+   * \r
+   * @param dataset the multiple series dataset\r
+   * @param renderer the multiple series renderer\r
+   */\r
+  public TimeChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    super(dataset, renderer);\r
+  }\r
+\r
+  /**\r
+   * Returns the date format pattern to be used for formatting the X axis\r
+   * labels.\r
+   * \r
+   * @return the date format pattern for the X axis labels\r
+   */\r
+  public String getDateFormat() {\r
+    return mDateFormat;\r
+  }\r
+\r
+  /**\r
+   * Sets the date format pattern to be used for formatting the X axis labels.\r
+   * \r
+   * @param format the date format pattern for the X axis labels. If null, an\r
+   *          appropriate default format will be used.\r
+   */\r
+  public void setDateFormat(String format) {\r
+    mDateFormat = format;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the labels on the X axis.\r
+   * \r
+   * @param xLabels the X labels values\r
+   * @param xTextLabelLocations the X text label locations\r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param left the left value of the labels area\r
+   * @param top the top value of the labels area\r
+   * @param bottom the bottom value of the labels area\r
+   * @param xPixelsPerUnit the amount of pixels per one unit in the chart labels\r
+   * @param minX the minimum value on the X axis in the chart\r
+   * @param maxX the maximum value on the X axis in the chart\r
+   */\r
+  @Override\r
+  protected void drawXLabels(List<Double> xLabels, Double[] xTextLabelLocations, Canvas canvas,\r
+      Paint paint, int left, int top, int bottom, double xPixelsPerUnit, double minX, double maxX) {\r
+    int length = xLabels.size();\r
+    if (length > 0) {\r
+      boolean showLabels = mRenderer.isShowLabels();\r
+      boolean showGridY = mRenderer.isShowGridY();\r
+      DateFormat format = getDateFormat(xLabels.get(0), xLabels.get(length - 1));\r
+      for (int i = 0; i < length; i++) {\r
+        long label = Math.round(xLabels.get(i));\r
+        float xLabel = (float) (left + xPixelsPerUnit * (label - minX));\r
+        if (showLabels) {\r
+          paint.setColor(mRenderer.getXLabelsColor());\r
+          canvas\r
+              .drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);\r
+          drawText(canvas, format.format(new Date(label)), xLabel,\r
+              bottom + mRenderer.getLabelsTextSize() * 4 / 3, paint, mRenderer.getXLabelsAngle());\r
+        }\r
+        if (showGridY) {\r
+          paint.setColor(mRenderer.getGridColor());\r
+          canvas.drawLine(xLabel, bottom, xLabel, top, paint);\r
+        }\r
+      }\r
+    }\r
+    drawXTextLabels(xTextLabelLocations, canvas, paint, true, left, top, bottom, xPixelsPerUnit,\r
+        minX, maxX);\r
+  }\r
+\r
+  /**\r
+   * Returns the date format pattern to be used, based on the date range.\r
+   * \r
+   * @param start the start date in milliseconds\r
+   * @param end the end date in milliseconds\r
+   * @return the date format\r
+   */\r
+  private DateFormat getDateFormat(double start, double end) {\r
+    if (mDateFormat != null) {\r
+      SimpleDateFormat format = null;\r
+      try {\r
+        format = new SimpleDateFormat(mDateFormat);\r
+        return format;\r
+      } catch (Exception e) {\r
+        // do nothing here\r
+      }\r
+    }\r
+    DateFormat format = SimpleDateFormat.getDateInstance(SimpleDateFormat.MEDIUM);\r
+    double diff = end - start;\r
+    if (diff > DAY && diff < 5 * DAY) {\r
+      format = SimpleDateFormat.getDateTimeInstance(SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);\r
+    } else if (diff < DAY) {\r
+      format = SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM);\r
+    }\r
+    return format;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public String getChartType() {\r
+    return TYPE;\r
+  }\r
+\r
+  protected List<Double> getXLabels(double min, double max, int count) {\r
+    final List<Double> result = new ArrayList<Double>();\r
+    if (!mRenderer.isXRoundedLabels()) {\r
+      if (mDataset.getSeriesCount() > 0) {\r
+        XYSeries series = mDataset.getSeriesAt(0);\r
+        int length = series.getItemCount();\r
+        int intervalLength = 0;\r
+        int startIndex = -1;\r
+        for (int i = 0; i < length; i++) {\r
+          double value = series.getX(i);\r
+          if (min <= value && value <= max) {\r
+            intervalLength++;\r
+            if (startIndex < 0) {\r
+              startIndex = i;\r
+            }\r
+          }\r
+        }\r
+        if (intervalLength < count) {\r
+          for (int i = startIndex; i < startIndex + intervalLength; i++) {\r
+            result.add(series.getX(i));\r
+          }\r
+        } else {\r
+          float step = (float) intervalLength / count;\r
+          int intervalCount = 0;\r
+          for (int i = 0; i < length && intervalCount < count; i++) {\r
+            double value = series.getX(Math.round(i * step));\r
+            if (min <= value && value <= max) {\r
+              result.add(value);\r
+              intervalCount++;\r
+            }\r
+          }\r
+        }\r
+        return result;\r
+      } else {\r
+        return super.getXLabels(min, max, count);\r
+      }\r
+    }\r
+    if (mStartPoint == null) {\r
+      mStartPoint = min - (min % DAY) + DAY + new Date(Math.round(min)).getTimezoneOffset() * 60\r
+          * 1000;\r
+    }\r
+    if (count > 25) {\r
+      count = 25;\r
+    }\r
+\r
+    \r
+    final double cycleMath = (max - min) / count;\r
+    if (cycleMath <= 0) {\r
+      return result;\r
+    }\r
+    double cycle = DAY;\r
+\r
+    if (cycleMath <= DAY) {\r
+      while (cycleMath < cycle / 2) {\r
+        cycle = cycle / 2;\r
+      }\r
+    } else {\r
+      while (cycleMath > cycle) {\r
+        cycle = cycle * 2;\r
+      }\r
+    }\r
+\r
+    double val = mStartPoint - Math.floor((mStartPoint - min) / cycle) * cycle;\r
+    int i = 0;\r
+    while (val < max && i++ <= count) {\r
+      result.add(val);\r
+      val += cycle;\r
+    }\r
+\r
+    return result;\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/XYChart.java b/android-libraries/achartengine/src/org/achartengine/chart/XYChart.java
new file mode 100644 (file)
index 0000000..6b531d6
--- /dev/null
@@ -0,0 +1,905 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.chart;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.HashMap;\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Map.Entry;\r
+import java.util.SortedMap;\r
+\r
+import org.achartengine.model.Point;\r
+import org.achartengine.model.SeriesSelection;\r
+import org.achartengine.model.XYMultipleSeriesDataset;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.BasicStroke;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.renderer.SimpleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer.Orientation;\r
+import org.achartengine.util.MathHelper;\r
+\r
+import android.graphics.Canvas;\r
+import android.graphics.DashPathEffect;\r
+import android.graphics.Paint;\r
+import android.graphics.Paint.Align;\r
+import android.graphics.Paint.Cap;\r
+import android.graphics.Paint.Join;\r
+import android.graphics.Paint.Style;\r
+import android.graphics.PathEffect;\r
+import android.graphics.Rect;\r
+import android.graphics.RectF;\r
+import android.graphics.Typeface;\r
+\r
+/**\r
+ * The XY chart rendering class.\r
+ */\r
+public abstract class XYChart extends AbstractChart {\r
+  /** The multiple series dataset. */\r
+  protected XYMultipleSeriesDataset mDataset;\r
+  /** The multiple series renderer. */\r
+  protected XYMultipleSeriesRenderer mRenderer;\r
+  /** The current scale value. */\r
+  private float mScale;\r
+  /** The current translate value. */\r
+  private float mTranslate;\r
+  /** The canvas center point. */\r
+  private Point mCenter;\r
+  /** The visible chart area, in screen coordinates. */\r
+  private Rect mScreenR;\r
+  /** The calculated range. */\r
+  private final Map<Integer, double[]> mCalcRange = new HashMap<Integer, double[]>();\r
+\r
+  /**\r
+   * The clickable areas for all points. The array index is the series index,\r
+   * and the RectF list index is the point index in that series.\r
+   */\r
+  private Map<Integer, List<ClickableArea>> clickableAreas = new HashMap<Integer, List<ClickableArea>>();\r
+\r
+  protected XYChart() {\r
+  }\r
+\r
+  /**\r
+   * Builds a new XY chart instance.\r
+   * \r
+   * @param dataset the multiple series dataset\r
+   * @param renderer the multiple series renderer\r
+   */\r
+  public XYChart(XYMultipleSeriesDataset dataset, XYMultipleSeriesRenderer renderer) {\r
+    mDataset = dataset;\r
+    mRenderer = renderer;\r
+  }\r
+\r
+  // TODO: javadoc\r
+  protected void setDatasetRenderer(XYMultipleSeriesDataset dataset,\r
+      XYMultipleSeriesRenderer renderer) {\r
+    mDataset = dataset;\r
+    mRenderer = renderer;\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the XY chart.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param x the top left x value of the view to draw to\r
+   * @param y the top left y value of the view to draw to\r
+   * @param width the width of the view to draw to\r
+   * @param height the height of the view to draw to\r
+   * @param paint the paint\r
+   */\r
+  public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {\r
+    paint.setAntiAlias(mRenderer.isAntialiasing());\r
+    int legendSize = getLegendSize(mRenderer, height / 5, mRenderer.getAxisTitleTextSize());\r
+    int[] margins = mRenderer.getMargins();\r
+    int left = x + margins[1];\r
+    int top = y + margins[0];\r
+    int right = x + width - margins[3];\r
+    int sLength = mDataset.getSeriesCount();\r
+    String[] titles = new String[sLength];\r
+    for (int i = 0; i < sLength; i++) {\r
+      titles[i] = mDataset.getSeriesAt(i).getTitle();\r
+    }\r
+    if (mRenderer.isFitLegend() && mRenderer.isShowLegend()) {\r
+      legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,\r
+          paint, true);\r
+    }\r
+    int bottom = y + height - margins[2] - legendSize;\r
+    if (mScreenR == null) {\r
+      mScreenR = new Rect();\r
+    }\r
+    mScreenR.set(left, top, right, bottom);\r
+    drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);\r
+\r
+    if (paint.getTypeface() == null\r
+        || !paint.getTypeface().toString().equals(mRenderer.getTextTypefaceName())\r
+        || paint.getTypeface().getStyle() != mRenderer.getTextTypefaceStyle()) {\r
+      paint.setTypeface(Typeface.create(mRenderer.getTextTypefaceName(),\r
+          mRenderer.getTextTypefaceStyle()));\r
+    }\r
+    Orientation or = mRenderer.getOrientation();\r
+    if (or == Orientation.VERTICAL) {\r
+      right -= legendSize;\r
+      bottom += legendSize - 20;\r
+    }\r
+    int angle = or.getAngle();\r
+    boolean rotate = angle == 90;\r
+    mScale = (float) (height) / width;\r
+    mTranslate = Math.abs(width - height) / 2;\r
+    if (mScale < 1) {\r
+      mTranslate *= -1;\r
+    }\r
+    mCenter = new Point((x + width) / 2, (y + height) / 2);\r
+    if (rotate) {\r
+      transform(canvas, angle, false);\r
+    }\r
+\r
+    int maxScaleNumber = -Integer.MAX_VALUE;\r
+    for (int i = 0; i < sLength; i++) {\r
+      maxScaleNumber = Math.max(maxScaleNumber, mDataset.getSeriesAt(i).getScaleNumber());\r
+    }\r
+    maxScaleNumber++;\r
+    if (maxScaleNumber < 0) {\r
+      return;\r
+    }\r
+    double[] minX = new double[maxScaleNumber];\r
+    double[] maxX = new double[maxScaleNumber];\r
+    double[] minY = new double[maxScaleNumber];\r
+    double[] maxY = new double[maxScaleNumber];\r
+    boolean[] isMinXSet = new boolean[maxScaleNumber];\r
+    boolean[] isMaxXSet = new boolean[maxScaleNumber];\r
+    boolean[] isMinYSet = new boolean[maxScaleNumber];\r
+    boolean[] isMaxYSet = new boolean[maxScaleNumber];\r
+\r
+    for (int i = 0; i < maxScaleNumber; i++) {\r
+      minX[i] = mRenderer.getXAxisMin(i);\r
+      maxX[i] = mRenderer.getXAxisMax(i);\r
+      minY[i] = mRenderer.getYAxisMin(i);\r
+      maxY[i] = mRenderer.getYAxisMax(i);\r
+      isMinXSet[i] = mRenderer.isMinXSet(i);\r
+      isMaxXSet[i] = mRenderer.isMaxXSet(i);\r
+      isMinYSet[i] = mRenderer.isMinYSet(i);\r
+      isMaxYSet[i] = mRenderer.isMaxYSet(i);\r
+      if (mCalcRange.get(i) == null) {\r
+        mCalcRange.put(i, new double[4]);\r
+      }\r
+    }\r
+    double[] xPixelsPerUnit = new double[maxScaleNumber];\r
+    double[] yPixelsPerUnit = new double[maxScaleNumber];\r
+    for (int i = 0; i < sLength; i++) {\r
+      XYSeries series = mDataset.getSeriesAt(i);\r
+      int scale = series.getScaleNumber();\r
+      if (series.getItemCount() == 0) {\r
+        continue;\r
+      }\r
+      if (!isMinXSet[scale]) {\r
+        double minimumX = series.getMinX();\r
+        minX[scale] = Math.min(minX[scale], minimumX);\r
+        mCalcRange.get(scale)[0] = minX[scale];\r
+      }\r
+      if (!isMaxXSet[scale]) {\r
+        double maximumX = series.getMaxX();\r
+        maxX[scale] = Math.max(maxX[scale], maximumX);\r
+        mCalcRange.get(scale)[1] = maxX[scale];\r
+      }\r
+      if (!isMinYSet[scale]) {\r
+        double minimumY = series.getMinY();\r
+        minY[scale] = Math.min(minY[scale], (float) minimumY);\r
+        mCalcRange.get(scale)[2] = minY[scale];\r
+      }\r
+      if (!isMaxYSet[scale]) {\r
+        double maximumY = series.getMaxY();\r
+        maxY[scale] = Math.max(maxY[scale], (float) maximumY);\r
+        mCalcRange.get(scale)[3] = maxY[scale];\r
+      }\r
+    }\r
+    for (int i = 0; i < maxScaleNumber; i++) {\r
+      if (maxX[i] - minX[i] != 0) {\r
+        xPixelsPerUnit[i] = (right - left) / (maxX[i] - minX[i]);\r
+      }\r
+      if (maxY[i] - minY[i] != 0) {\r
+        yPixelsPerUnit[i] = (float) ((bottom - top) / (maxY[i] - minY[i]));\r
+      }\r
+    }\r
+\r
+    boolean hasValues = false;\r
+    // use a linked list for these reasons:\r
+    // 1) Avoid a large contiguous memory allocation\r
+    // 2) We don't need random seeking, only sequential reading/writing, so\r
+    // linked list makes sense\r
+    clickableAreas = new HashMap<Integer, List<ClickableArea>>();\r
+    for (int i = 0; i < sLength; i++) {\r
+      XYSeries series = mDataset.getSeriesAt(i);\r
+      int scale = series.getScaleNumber();\r
+      if (series.getItemCount() == 0) {\r
+        continue;\r
+      }\r
+\r
+      hasValues = true;\r
+      SimpleSeriesRenderer seriesRenderer = mRenderer.getSeriesRendererAt(i);\r
+\r
+      // int originalValuesLength = series.getItemCount();\r
+      // int valuesLength = originalValuesLength;\r
+      // int length = valuesLength * 2;\r
+\r
+      List<Float> points = new ArrayList<Float>();\r
+      List<Double> values = new ArrayList<Double>();\r
+      float yAxisValue = Math.min(bottom, (float) (bottom + yPixelsPerUnit[scale] * minY[scale]));\r
+      LinkedList<ClickableArea> clickableArea = new LinkedList<ClickableArea>();\r
+\r
+      clickableAreas.put(i, clickableArea);\r
+\r
+      SortedMap<Double, Double> range = series.getRange(minX[scale], maxX[scale], 1);\r
+      int startIndex = -1;\r
+\r
+      for (Entry<Double, Double> value : range.entrySet()) {\r
+\r
+        double xValue = value.getKey();\r
+        double yValue = value.getValue();\r
+        if (startIndex < 0) {\r
+          startIndex = series.getIndexForKey(xValue);\r
+        }\r
+\r
+        // points.add((float) (left + xPixelsPerUnit[scale]\r
+        // * (value.getKey().floatValue() - minX[scale])));\r
+        // points.add((float) (bottom - yPixelsPerUnit[scale]\r
+        // * (value.getValue().floatValue() - minY[scale])));\r
+        values.add(value.getKey());\r
+        values.add(value.getValue());\r
+\r
+        if (!isNullValue(yValue)) {\r
+          points.add((float) (left + xPixelsPerUnit[scale] * (xValue - minX[scale])));\r
+          points.add((float) (bottom - yPixelsPerUnit[scale] * (yValue - minY[scale])));\r
+        } else if (isRenderNullValues()) {\r
+          points.add((float) (left + xPixelsPerUnit[scale] * (xValue - minX[scale])));\r
+          points.add((float) (bottom - yPixelsPerUnit[scale] * (-minY[scale])));\r
+        } else {\r
+          if (points.size() > 0) {\r
+            drawSeries(series, canvas, paint, points, seriesRenderer, yAxisValue, i, or, startIndex);\r
+            ClickableArea[] clickableAreasForSubSeries = clickableAreasForPoints(\r
+                MathHelper.getFloats(points), MathHelper.getDoubles(values), yAxisValue, i,\r
+                startIndex);\r
+            clickableArea.addAll(Arrays.asList(clickableAreasForSubSeries));\r
+            points.clear();\r
+            values.clear();\r
+          }\r
+          clickableArea.add(null);\r
+        }\r
+      }\r
+\r
+      if (points.size() > 0) {\r
+        drawSeries(series, canvas, paint, points, seriesRenderer, yAxisValue, i, or, startIndex);\r
+        ClickableArea[] clickableAreasForSubSeries = clickableAreasForPoints(\r
+            MathHelper.getFloats(points), MathHelper.getDoubles(values), yAxisValue, i, startIndex);\r
+        clickableArea.addAll(Arrays.asList(clickableAreasForSubSeries));\r
+      }\r
+    }\r
+\r
+    // draw stuff over the margins such as data doesn't render on these areas\r
+    drawBackground(mRenderer, canvas, x, bottom, width, height - bottom, paint, true,\r
+        mRenderer.getMarginsColor());\r
+    drawBackground(mRenderer, canvas, x, y, width, margins[0], paint, true,\r
+        mRenderer.getMarginsColor());\r
+    if (or == Orientation.HORIZONTAL) {\r
+      drawBackground(mRenderer, canvas, x, y, left - x, height - y, paint, true,\r
+          mRenderer.getMarginsColor());\r
+      drawBackground(mRenderer, canvas, right, y, margins[3], height - y, paint, true,\r
+          mRenderer.getMarginsColor());\r
+    } else if (or == Orientation.VERTICAL) {\r
+      drawBackground(mRenderer, canvas, right, y, width - right, height - y, paint, true,\r
+          mRenderer.getMarginsColor());\r
+      drawBackground(mRenderer, canvas, x, y, left - x, height - y, paint, true,\r
+          mRenderer.getMarginsColor());\r
+    }\r
+\r
+    boolean showLabels = mRenderer.isShowLabels() && hasValues;\r
+    boolean showGridX = mRenderer.isShowGridX();\r
+    boolean showCustomTextGrid = mRenderer.isShowCustomTextGrid();\r
+    if (showLabels || showGridX) {\r
+      List<Double> xLabels = getValidLabels(getXLabels(minX[0], maxX[0], mRenderer.getXLabels()));\r
+      Map<Integer, List<Double>> allYLabels = getYLabels(minY, maxY, maxScaleNumber);\r
+\r
+      int xLabelsLeft = left;\r
+      if (showLabels) {\r
+        paint.setColor(mRenderer.getXLabelsColor());\r
+        paint.setTextSize(mRenderer.getLabelsTextSize());\r
+        paint.setTextAlign(mRenderer.getXLabelsAlign());\r
+        if (mRenderer.getXLabelsAlign() == Align.LEFT) {\r
+          xLabelsLeft += mRenderer.getLabelsTextSize() / 4;\r
+        }\r
+      }\r
+      drawXLabels(xLabels, mRenderer.getXTextLabelLocations(), canvas, paint, xLabelsLeft, top,\r
+          bottom, xPixelsPerUnit[0], minX[0], maxX[0]);\r
+      drawYLabels(allYLabels, canvas, paint, maxScaleNumber, left, right, bottom, yPixelsPerUnit,\r
+          minY);\r
+\r
+      if (showLabels) {\r
+        paint.setColor(mRenderer.getLabelsColor());\r
+        for (int i = 0; i < maxScaleNumber; i++) {\r
+          Align axisAlign = mRenderer.getYAxisAlign(i);\r
+          Double[] yTextLabelLocations = mRenderer.getYTextLabelLocations(i);\r
+          for (Double location : yTextLabelLocations) {\r
+            if (minY[i] <= location && location <= maxY[i]) {\r
+              float yLabel = (float) (bottom - yPixelsPerUnit[i]\r
+                  * (location.doubleValue() - minY[i]));\r
+              String label = mRenderer.getYTextLabel(location, i);\r
+              paint.setColor(mRenderer.getYLabelsColor(i));\r
+              paint.setTextAlign(mRenderer.getYLabelsAlign(i));\r
+              if (or == Orientation.HORIZONTAL) {\r
+                if (axisAlign == Align.LEFT) {\r
+                  canvas.drawLine(left + getLabelLinePos(axisAlign), yLabel, left, yLabel, paint);\r
+                  drawText(canvas, label, left, yLabel - 2, paint, mRenderer.getYLabelsAngle());\r
+                } else {\r
+                  canvas.drawLine(right, yLabel, right + getLabelLinePos(axisAlign), yLabel, paint);\r
+                  drawText(canvas, label, right, yLabel - 2, paint, mRenderer.getYLabelsAngle());\r
+                }\r
+                \r
+                if (showCustomTextGrid) {\r
+                  paint.setColor(mRenderer.getGridColor());\r
+                  canvas.drawLine(left, yLabel, right, yLabel, paint);\r
+                }\r
+              } else {\r
+                canvas.drawLine(right - getLabelLinePos(axisAlign), yLabel, right, yLabel, paint);\r
+                drawText(canvas, label, right + 10, yLabel - 2, paint, mRenderer.getYLabelsAngle());\r
+                if (showCustomTextGrid) {\r
+                  paint.setColor(mRenderer.getGridColor());\r
+                  canvas.drawLine(right, yLabel, left, yLabel, paint);\r
+                }\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+\r
+      if (showLabels) {\r
+        paint.setColor(mRenderer.getLabelsColor());\r
+        float size = mRenderer.getAxisTitleTextSize();\r
+        paint.setTextSize(size);\r
+        paint.setTextAlign(Align.CENTER);\r
+        if (or == Orientation.HORIZONTAL) {\r
+          drawText(canvas, mRenderer.getXTitle(), x + width / 2,\r
+              bottom + mRenderer.getLabelsTextSize() * 4 / 3 + size, paint, 0);\r
+          for (int i = 0; i < maxScaleNumber; i++) {\r
+            Align axisAlign = mRenderer.getYAxisAlign(i);\r
+            if (axisAlign == Align.LEFT) {\r
+              drawText(canvas, mRenderer.getYTitle(i), x + size, y + height / 2, paint, -90);\r
+            } else {\r
+              drawText(canvas, mRenderer.getYTitle(i), x + width, y + height / 2, paint, -90);\r
+            }\r
+          }\r
+          paint.setTextSize(mRenderer.getChartTitleTextSize());\r
+          drawText(canvas, mRenderer.getChartTitle(), x + width / 2,\r
+              y + mRenderer.getChartTitleTextSize(), paint, 0);\r
+        } else if (or == Orientation.VERTICAL) {\r
+          drawText(canvas, mRenderer.getXTitle(), x + width / 2, y + height - size, paint, -90);\r
+          drawText(canvas, mRenderer.getYTitle(), right + 20, y + height / 2, paint, 0);\r
+          paint.setTextSize(mRenderer.getChartTitleTextSize());\r
+          drawText(canvas, mRenderer.getChartTitle(), x + size, top + height / 2, paint, 0);\r
+        }\r
+      }\r
+    }\r
+    if (or == Orientation.HORIZONTAL) {\r
+      drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);\r
+    } else if (or == Orientation.VERTICAL) {\r
+      transform(canvas, angle, true);\r
+      drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);\r
+      transform(canvas, angle, false);\r
+    }\r
+    if (mRenderer.isShowAxes()) {\r
+      paint.setColor(mRenderer.getAxesColor());\r
+      canvas.drawLine(left, bottom, right, bottom, paint);\r
+      boolean rightAxis = false;\r
+      for (int i = 0; i < maxScaleNumber && !rightAxis; i++) {\r
+        rightAxis = mRenderer.getYAxisAlign(i) == Align.RIGHT;\r
+      }\r
+      if (or == Orientation.HORIZONTAL) {\r
+        canvas.drawLine(left, top, left, bottom, paint);\r
+        if (rightAxis) {\r
+          canvas.drawLine(right, top, right, bottom, paint);\r
+        }\r
+      } else if (or == Orientation.VERTICAL) {\r
+        canvas.drawLine(right, top, right, bottom, paint);\r
+      }\r
+    }\r
+    if (rotate) {\r
+      transform(canvas, angle, true);\r
+    }\r
+  }\r
+\r
+  protected List<Double> getXLabels(double min, double max, int count) {\r
+    return MathHelper.getLabels(min, max, count);\r
+  }\r
+\r
+  protected Map<Integer, List<Double>> getYLabels(double[] minY, double[] maxY, int maxScaleNumber) {\r
+    Map<Integer, List<Double>> allYLabels = new HashMap<Integer, List<Double>>();\r
+    for (int i = 0; i < maxScaleNumber; i++) {\r
+      allYLabels.put(i,\r
+          getValidLabels(MathHelper.getLabels(minY[i], maxY[i], mRenderer.getYLabels())));\r
+    }\r
+    return allYLabels;\r
+  }\r
+\r
+  protected Rect getScreenR() {\r
+    return mScreenR;\r
+  }\r
+\r
+  protected void setScreenR(Rect screenR) {\r
+    mScreenR = screenR;\r
+  }\r
+\r
+  private List<Double> getValidLabels(List<Double> labels) {\r
+    List<Double> result = new ArrayList<Double>(labels);\r
+    for (Double label : labels) {\r
+      if (label.isNaN()) {\r
+        result.remove(label);\r
+      }\r
+    }\r
+    return result;\r
+  }\r
+\r
+  /**\r
+   * Draws the series.\r
+   * \r
+   * @param series the series\r
+   * @param canvas the canvas\r
+   * @param paint the paint object\r
+   * @param pointsList the points to be rendered\r
+   * @param seriesRenderer the series renderer\r
+   * @param yAxisValue the y axis value in pixels\r
+   * @param seriesIndex the series index\r
+   * @param or the orientation\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  protected void drawSeries(XYSeries series, Canvas canvas, Paint paint, List<Float> pointsList,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, Orientation or,\r
+      int startIndex) {\r
+    BasicStroke stroke = seriesRenderer.getStroke();\r
+    Cap cap = paint.getStrokeCap();\r
+    Join join = paint.getStrokeJoin();\r
+    float miter = paint.getStrokeMiter();\r
+    PathEffect pathEffect = paint.getPathEffect();\r
+    Style style = paint.getStyle();\r
+    if (stroke != null) {\r
+      PathEffect effect = null;\r
+      if (stroke.getIntervals() != null) {\r
+        effect = new DashPathEffect(stroke.getIntervals(), stroke.getPhase());\r
+      }\r
+      setStroke(stroke.getCap(), stroke.getJoin(), stroke.getMiter(), Style.FILL_AND_STROKE,\r
+          effect, paint);\r
+    }\r
+    float[] points = MathHelper.getFloats(pointsList);\r
+    drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, seriesIndex, startIndex);\r
+    if (isRenderPoints(seriesRenderer)) {\r
+      ScatterChart pointsChart = getPointsChart();\r
+      if (pointsChart != null) {\r
+        pointsChart.drawSeries(canvas, paint, points, seriesRenderer, yAxisValue, seriesIndex,\r
+            startIndex);\r
+      }\r
+    }\r
+    paint.setTextSize(seriesRenderer.getChartValuesTextSize());\r
+    if (or == Orientation.HORIZONTAL) {\r
+      paint.setTextAlign(Align.CENTER);\r
+    } else {\r
+      paint.setTextAlign(Align.LEFT);\r
+    }\r
+    if (seriesRenderer.isDisplayChartValues()) {\r
+      paint.setTextAlign(seriesRenderer.getChartValuesTextAlign());\r
+      drawChartValuesText(canvas, series, seriesRenderer, paint, points, seriesIndex, startIndex);\r
+    }\r
+    if (stroke != null) {\r
+      setStroke(cap, join, miter, style, pathEffect, paint);\r
+    }\r
+  }\r
+\r
+  private void setStroke(Cap cap, Join join, float miter, Style style, PathEffect pathEffect,\r
+      Paint paint) {\r
+    paint.setStrokeCap(cap);\r
+    paint.setStrokeJoin(join);\r
+    paint.setStrokeMiter(miter);\r
+    paint.setPathEffect(pathEffect);\r
+    paint.setStyle(style);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the series values as text.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param series the series to be painted\r
+   * @param renderer the series renderer\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  protected void drawChartValuesText(Canvas canvas, XYSeries series, SimpleSeriesRenderer renderer,\r
+      Paint paint, float[] points, int seriesIndex, int startIndex) {\r
+    if (points.length > 1) { // there are more than one point\r
+      // record the first point's position\r
+      float previousPointX = points[0];\r
+      float previousPointY = points[1];\r
+      for (int k = 0; k < points.length; k += 2) {\r
+        if (k == 2) { // decide whether to display first two points' values or not\r
+          if (Math.abs(points[2]- points[0]) > 100 || Math.abs(points[3] - points[1]) > 100) {\r
+            // first point\r
+            drawText(canvas, getLabel(series.getY(startIndex)), points[0], points[1]\r
+                - renderer.getChartValuesSpacing(), paint, 0);\r
+            // second point\r
+            drawText(canvas, getLabel(series.getY(startIndex + 1)), points[2], points[3]\r
+                - renderer.getChartValuesSpacing(), paint, 0);\r
+\r
+            previousPointX = points[2];\r
+            previousPointY = points[3];\r
+          }\r
+        } else if (k > 2) {\r
+          // compare current point's position with the previous point's, if they are not too close, display\r
+          if (Math.abs(points[k]- previousPointX) > 100 || Math.abs(points[k+1] - previousPointY) > 100) {\r
+            drawText(canvas, getLabel(series.getY(startIndex + k / 2)), points[k], points[k + 1]\r
+                - renderer.getChartValuesSpacing(), paint, 0);\r
+            previousPointX = points[k];\r
+            previousPointY = points[k+1];\r
+          }\r
+        }\r
+      }\r
+    } else { // if only one point, display it\r
+      for (int k = 0; k < points.length; k += 2) {\r
+        drawText(canvas, getLabel(series.getY(startIndex + k / 2)), points[k], points[k + 1]\r
+            - renderer.getChartValuesSpacing(), paint, 0);\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a text, to handle both HORIZONTAL and\r
+   * VERTICAL orientations and extra rotation angles.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param text the text to be rendered\r
+   * @param x the X axis location of the text\r
+   * @param y the Y axis location of the text\r
+   * @param paint the paint to be used for drawing\r
+   * @param extraAngle the text angle\r
+   */\r
+  protected void drawText(Canvas canvas, String text, float x, float y, Paint paint,\r
+      float extraAngle) {\r
+    float angle = -mRenderer.getOrientation().getAngle() + extraAngle;\r
+    if (angle != 0) {\r
+      // canvas.scale(1 / mScale, mScale);\r
+      canvas.rotate(angle, x, y);\r
+    }\r
+    drawString(canvas, text, x, y, paint);\r
+    if (angle != 0) {\r
+      canvas.rotate(-angle, x, y);\r
+      // canvas.scale(mScale, 1 / mScale);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Transform the canvas such as it can handle both HORIZONTAL and VERTICAL\r
+   * orientations.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param angle the angle of rotation\r
+   * @param inverse if the inverse transform needs to be applied\r
+   */\r
+  private void transform(Canvas canvas, float angle, boolean inverse) {\r
+    if (inverse) {\r
+      canvas.scale(1 / mScale, mScale);\r
+      canvas.translate(mTranslate, -mTranslate);\r
+      canvas.rotate(-angle, mCenter.getX(), mCenter.getY());\r
+    } else {\r
+      canvas.rotate(angle, mCenter.getX(), mCenter.getY());\r
+      canvas.translate(-mTranslate, mTranslate);\r
+      canvas.scale(mScale, 1 / mScale);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the labels on the X axis.\r
+   * \r
+   * @param xLabels the X labels values\r
+   * @param xTextLabelLocations the X text label locations\r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param left the left value of the labels area\r
+   * @param top the top value of the labels area\r
+   * @param bottom the bottom value of the labels area\r
+   * @param xPixelsPerUnit the amount of pixels per one unit in the chart labels\r
+   * @param minX the minimum value on the X axis in the chart\r
+   * @param maxX the maximum value on the X axis in the chart\r
+   */\r
+  protected void drawXLabels(List<Double> xLabels, Double[] xTextLabelLocations, Canvas canvas,\r
+      Paint paint, int left, int top, int bottom, double xPixelsPerUnit, double minX, double maxX) {\r
+    int length = xLabels.size();\r
+    boolean showLabels = mRenderer.isShowLabels();\r
+    boolean showGridY = mRenderer.isShowGridY();\r
+    for (int i = 0; i < length; i++) {\r
+      double label = xLabels.get(i);\r
+      float xLabel = (float) (left + xPixelsPerUnit * (label - minX));\r
+      if (showLabels) {\r
+        paint.setColor(mRenderer.getXLabelsColor());\r
+        canvas.drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);\r
+        drawText(canvas, getLabel(label), xLabel, bottom + mRenderer.getLabelsTextSize() * 4 / 3,\r
+            paint, mRenderer.getXLabelsAngle());\r
+      }\r
+      if (showGridY) {\r
+        paint.setColor(mRenderer.getGridColor());\r
+        canvas.drawLine(xLabel, bottom, xLabel, top, paint);\r
+      }\r
+    }\r
+    drawXTextLabels(xTextLabelLocations, canvas, paint, showLabels, left, top, bottom,\r
+        xPixelsPerUnit, minX, maxX);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the labels on the X axis.\r
+   * \r
+   * @param allYLabels the Y labels values\r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param maxScaleNumber the maximum scale number\r
+   * @param left the left value of the labels area\r
+   * @param right the right value of the labels area\r
+   * @param bottom the bottom value of the labels area\r
+   * @param yPixelsPerUnit the amount of pixels per one unit in the chart labels\r
+   * @param minY the minimum value on the Y axis in the chart\r
+   */\r
+  protected void drawYLabels(Map<Integer, List<Double>> allYLabels, Canvas canvas, Paint paint,\r
+      int maxScaleNumber, int left, int right, int bottom, double[] yPixelsPerUnit, double[] minY) {\r
+    Orientation or = mRenderer.getOrientation();\r
+    boolean showGridX = mRenderer.isShowGridX();\r
+    boolean showLabels = mRenderer.isShowLabels();\r
+    for (int i = 0; i < maxScaleNumber; i++) {\r
+      paint.setTextAlign(mRenderer.getYLabelsAlign(i));\r
+      List<Double> yLabels = allYLabels.get(i);\r
+      int length = yLabels.size();\r
+      for (int j = 0; j < length; j++) {\r
+        double label = yLabels.get(j);\r
+        Align axisAlign = mRenderer.getYAxisAlign(i);\r
+        boolean textLabel = mRenderer.getYTextLabel(label, i) != null;\r
+        float yLabel = (float) (bottom - yPixelsPerUnit[i] * (label - minY[i]));\r
+        if (or == Orientation.HORIZONTAL) {\r
+          if (showLabels && !textLabel) {\r
+            paint.setColor(mRenderer.getYLabelsColor(i));\r
+            if (axisAlign == Align.LEFT) {\r
+              canvas.drawLine(left + getLabelLinePos(axisAlign), yLabel, left, yLabel, paint);\r
+              drawText(canvas, getLabel(label), left, yLabel - 2, paint,\r
+                  mRenderer.getYLabelsAngle());\r
+            } else {\r
+              canvas.drawLine(right, yLabel, right + getLabelLinePos(axisAlign), yLabel, paint);\r
+              drawText(canvas, getLabel(label), right, yLabel - 2, paint,\r
+                  mRenderer.getYLabelsAngle());\r
+            }\r
+          }\r
+          if (showGridX) {\r
+            paint.setColor(mRenderer.getGridColor());\r
+            canvas.drawLine(left, yLabel, right, yLabel, paint);\r
+          }\r
+        } else if (or == Orientation.VERTICAL) {\r
+          if (showLabels && !textLabel) {\r
+            paint.setColor(mRenderer.getYLabelsColor(i));\r
+            canvas.drawLine(right - getLabelLinePos(axisAlign), yLabel, right, yLabel, paint);\r
+            drawText(canvas, getLabel(label), right + 10, yLabel - 2, paint,\r
+                mRenderer.getYLabelsAngle());\r
+          }\r
+          if (showGridX) {\r
+            paint.setColor(mRenderer.getGridColor());\r
+            canvas.drawLine(right, yLabel, left, yLabel, paint);\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of the text labels on the X axis.\r
+   * \r
+   * @param xTextLabelLocations the X text label locations\r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param left the left value of the labels area\r
+   * @param top the top value of the labels area\r
+   * @param bottom the bottom value of the labels area\r
+   * @param xPixelsPerUnit the amount of pixels per one unit in the chart labels\r
+   * @param minX the minimum value on the X axis in the chart\r
+   * @param maxX the maximum value on the X axis in the chart\r
+   */\r
+  protected void drawXTextLabels(Double[] xTextLabelLocations, Canvas canvas, Paint paint,\r
+      boolean showLabels, int left, int top, int bottom, double xPixelsPerUnit, double minX,\r
+      double maxX) {\r
+    boolean showCustomTextGrid = mRenderer.isShowCustomTextGrid();\r
+    if (showLabels) {\r
+      paint.setColor(mRenderer.getXLabelsColor());\r
+      for (Double location : xTextLabelLocations) {\r
+        if (minX <= location && location <= maxX) {\r
+          float xLabel = (float) (left + xPixelsPerUnit * (location.doubleValue() - minX));\r
+          paint.setColor(mRenderer.getXLabelsColor());\r
+          canvas\r
+          .drawLine(xLabel, bottom, xLabel, bottom + mRenderer.getLabelsTextSize() / 3, paint);\r
+          drawText(canvas, mRenderer.getXTextLabel(location), xLabel,\r
+              bottom + mRenderer.getLabelsTextSize() * 4 / 3, paint, mRenderer.getXLabelsAngle());\r
+          if (showCustomTextGrid) {\r
+            paint.setColor(mRenderer.getGridColor());\r
+            canvas.drawLine(xLabel, bottom, xLabel, top, paint);\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  // TODO: docs\r
+  public XYMultipleSeriesRenderer getRenderer() {\r
+    return mRenderer;\r
+  }\r
+\r
+  public XYMultipleSeriesDataset getDataset() {\r
+    return mDataset;\r
+  }\r
+\r
+  public double[] getCalcRange(int scale) {\r
+    return mCalcRange.get(scale);\r
+  }\r
+\r
+  public void setCalcRange(double[] range, int scale) {\r
+    mCalcRange.put(scale, range);\r
+  }\r
+\r
+  public double[] toRealPoint(float screenX, float screenY) {\r
+    return toRealPoint(screenX, screenY, 0);\r
+  }\r
+\r
+  public double[] toScreenPoint(double[] realPoint) {\r
+    return toScreenPoint(realPoint, 0);\r
+  }\r
+\r
+  private int getLabelLinePos(Align align) {\r
+    int pos = 4;\r
+    if (align == Align.LEFT) {\r
+      pos = -pos;\r
+    }\r
+    return pos;\r
+  }\r
+\r
+  /**\r
+   * Transforms a screen point to a real coordinates point.\r
+   * \r
+   * @param screenX the screen x axis value\r
+   * @param screenY the screen y axis value\r
+   * @return the real coordinates point\r
+   */\r
+  public double[] toRealPoint(float screenX, float screenY, int scale) {\r
+    double realMinX = mRenderer.getXAxisMin(scale);\r
+    double realMaxX = mRenderer.getXAxisMax(scale);\r
+    double realMinY = mRenderer.getYAxisMin(scale);\r
+    double realMaxY = mRenderer.getYAxisMax(scale);\r
+    return new double[] {\r
+        (screenX - mScreenR.left) * (realMaxX - realMinX) / mScreenR.width() + realMinX,\r
+        (mScreenR.top + mScreenR.height() - screenY) * (realMaxY - realMinY) / mScreenR.height()\r
+            + realMinY };\r
+  }\r
+\r
+  public double[] toScreenPoint(double[] realPoint, int scale) {\r
+    double realMinX = mRenderer.getXAxisMin(scale);\r
+    double realMaxX = mRenderer.getXAxisMax(scale);\r
+    double realMinY = mRenderer.getYAxisMin(scale);\r
+    double realMaxY = mRenderer.getYAxisMax(scale);\r
+    if (!mRenderer.isMinXSet(scale) || !mRenderer.isMaxXSet(scale) || !mRenderer.isMinXSet(scale)\r
+        || !mRenderer.isMaxYSet(scale)) {\r
+      double[] calcRange = getCalcRange(scale);\r
+      realMinX = calcRange[0];\r
+      realMaxX = calcRange[1];\r
+      realMinY = calcRange[2];\r
+      realMaxY = calcRange[3];\r
+    }\r
+    return new double[] {\r
+        (realPoint[0] - realMinX) * mScreenR.width() / (realMaxX - realMinX) + mScreenR.left,\r
+        (realMaxY - realPoint[1]) * mScreenR.height() / (realMaxY - realMinY) + mScreenR.top };\r
+  }\r
+\r
+  public SeriesSelection getSeriesAndPointForScreenCoordinate(final Point screenPoint) {\r
+    if (clickableAreas != null)\r
+      for (int seriesIndex = clickableAreas.size() - 1; seriesIndex >= 0; seriesIndex--) {\r
+        // series 0 is drawn first. Then series 1 is drawn on top, and series 2\r
+        // on top of that.\r
+        // we want to know what the user clicked on, so traverse them in the\r
+        // order they appear on the screen.\r
+        int pointIndex = 0;\r
+        if (clickableAreas.get(seriesIndex) != null) {\r
+          RectF rectangle;\r
+          for (ClickableArea area : clickableAreas.get(seriesIndex)) {\r
+            rectangle = area.getRect();\r
+            if (rectangle != null && rectangle.contains(screenPoint.getX(), screenPoint.getY())) {\r
+              return new SeriesSelection(seriesIndex, pointIndex, area.getX(), area.getY());\r
+            }\r
+            pointIndex++;\r
+          }\r
+        }\r
+      }\r
+    return super.getSeriesAndPointForScreenCoordinate(screenPoint);\r
+  }\r
+\r
+  /**\r
+   * The graphical representation of a series.\r
+   * \r
+   * @param canvas the canvas to paint to\r
+   * @param paint the paint to be used for drawing\r
+   * @param points the array of points to be used for drawing the series\r
+   * @param seriesRenderer the series renderer\r
+   * @param yAxisValue the minimum value of the y axis\r
+   * @param seriesIndex the index of the series currently being drawn\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  public abstract void drawSeries(Canvas canvas, Paint paint, float[] points,\r
+      SimpleSeriesRenderer seriesRenderer, float yAxisValue, int seriesIndex, int startIndex);\r
+\r
+  /**\r
+   * Returns the clickable areas for all passed points\r
+   * \r
+   * @param points the array of points\r
+   * @param values the array of values of each point\r
+   * @param yAxisValue the minimum value of the y axis\r
+   * @param seriesIndex the index of the series to which the points belong\r
+   * @return an array of rectangles with the clickable area\r
+   * @param startIndex the start index of the rendering points\r
+   */\r
+  protected abstract ClickableArea[] clickableAreasForPoints(float[] points, double[] values,\r
+      float yAxisValue, int seriesIndex, int startIndex);\r
+\r
+  /**\r
+   * Returns if the chart should display the null values.\r
+   * \r
+   * @return if null values should be rendered\r
+   */\r
+  protected boolean isRenderNullValues() {\r
+    return false;\r
+  }\r
+\r
+  /**\r
+   * Returns if the chart should display the points as a certain shape.\r
+   * \r
+   * @param renderer the series renderer\r
+   */\r
+  public boolean isRenderPoints(SimpleSeriesRenderer renderer) {\r
+    return false;\r
+  }\r
+\r
+  /**\r
+   * Returns the default axis minimum.\r
+   * \r
+   * @return the default axis minimum\r
+   */\r
+  public double getDefaultMinimum() {\r
+    return MathHelper.NULL_VALUE;\r
+  }\r
+\r
+  /**\r
+   * Returns the scatter chart to be used for drawing the data points.\r
+   * \r
+   * @return the data points scatter chart\r
+   */\r
+  public ScatterChart getPointsChart() {\r
+    return null;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart type identifier.\r
+   * \r
+   * @return the chart type\r
+   */\r
+  public abstract String getChartType();\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/chart/package.html b/android-libraries/achartengine/src/org/achartengine/chart/package.html
new file mode 100644 (file)
index 0000000..2c5fbec
--- /dev/null
@@ -0,0 +1,6 @@
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+Provides the classes that handle the actual rendering / drawing of the charts, based on the provided model and renderer.\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/image/zoom-1.png b/android-libraries/achartengine/src/org/achartengine/image/zoom-1.png
new file mode 100644 (file)
index 0000000..8265f27
Binary files /dev/null and b/android-libraries/achartengine/src/org/achartengine/image/zoom-1.png differ
diff --git a/android-libraries/achartengine/src/org/achartengine/image/zoom_in.png b/android-libraries/achartengine/src/org/achartengine/image/zoom_in.png
new file mode 100644 (file)
index 0000000..1ac4864
Binary files /dev/null and b/android-libraries/achartengine/src/org/achartengine/image/zoom_in.png differ
diff --git a/android-libraries/achartengine/src/org/achartengine/image/zoom_out.png b/android-libraries/achartengine/src/org/achartengine/image/zoom_out.png
new file mode 100644 (file)
index 0000000..d67a87d
Binary files /dev/null and b/android-libraries/achartengine/src/org/achartengine/image/zoom_out.png differ
diff --git a/android-libraries/achartengine/src/org/achartengine/model/CategorySeries.java b/android-libraries/achartengine/src/org/achartengine/model/CategorySeries.java
new file mode 100644 (file)
index 0000000..ae31c7d
--- /dev/null
@@ -0,0 +1,143 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * A series for the category charts like the pie ones.\r
+ */\r
+public class CategorySeries implements Serializable {\r
+  /** The series title. */\r
+  private String mTitle;\r
+  /** The series categories. */\r
+  private List<String> mCategories = new ArrayList<String>();\r
+  /** The series values. */\r
+  private List<Double> mValues = new ArrayList<Double>();\r
+\r
+  /**\r
+   * Builds a new category series.\r
+   * \r
+   * @param title the series title\r
+   */\r
+  public CategorySeries(String title) {\r
+    mTitle = title;\r
+  }\r
+\r
+  /**\r
+   * Returns the series title.\r
+   * \r
+   * @return the series title\r
+   */\r
+  public String getTitle() {\r
+    return mTitle;\r
+  }\r
+\r
+  /**\r
+   * Adds a new value to the series\r
+   * \r
+   * @param value the new value\r
+   */\r
+  public synchronized void add(double value) {\r
+    add(mCategories.size() + "", value);\r
+  }\r
+\r
+  /**\r
+   * Adds a new value to the series.\r
+   * \r
+   * @param category the category\r
+   * @param value the new value\r
+   */\r
+  public synchronized void add(String category, double value) {\r
+    mCategories.add(category);\r
+    mValues.add(value);\r
+  }\r
+\r
+  /**\r
+   * Replaces the value at the specific index in the series.\r
+   * \r
+   * @param index the index in the series\r
+   * @param category the category\r
+   * @param value the new value\r
+   */\r
+  public synchronized void set(int index, String category, double value) {\r
+    mCategories.set(index, category);\r
+    mValues.set(index, value);\r
+  }\r
+\r
+  /**\r
+   * Removes an existing value from the series.\r
+   * \r
+   * @param index the index in the series of the value to remove\r
+   */\r
+  public synchronized void remove(int index) {\r
+    mCategories.remove(index);\r
+    mValues.remove(index);\r
+  }\r
+\r
+  /**\r
+   * Removes all the existing values from the series.\r
+   */\r
+  public synchronized void clear() {\r
+    mCategories.clear();\r
+    mValues.clear();\r
+  }\r
+\r
+  /**\r
+   * Returns the value at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the value at the index\r
+   */\r
+  public synchronized double getValue(int index) {\r
+    return mValues.get(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the category name at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the category name at the index\r
+   */\r
+  public synchronized String getCategory(int index) {\r
+    return mCategories.get(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the series item count.\r
+   * \r
+   * @return the series item count\r
+   */\r
+  public synchronized int getItemCount() {\r
+    return mCategories.size();\r
+  }\r
+\r
+  /**\r
+   * Transforms the category series to an XY series.\r
+   * \r
+   * @return the XY series\r
+   */\r
+  public XYSeries toXYSeries() {\r
+    XYSeries xySeries = new XYSeries(mTitle);\r
+    int k = 0;\r
+    for (double value : mValues) {\r
+      xySeries.add(++k, value);\r
+    }\r
+    return xySeries;\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/model/MultipleCategorySeries.java b/android-libraries/achartengine/src/org/achartengine/model/MultipleCategorySeries.java
new file mode 100644 (file)
index 0000000..992db4c
--- /dev/null
@@ -0,0 +1,145 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * A series for the multiple category charts like the doughnut.\r
+ */\r
+public class MultipleCategorySeries implements Serializable {\r
+  /** The series title. */\r
+  private String mTitle;\r
+  /** The series local keys. */\r
+  private List<String> mCategories = new ArrayList<String>();\r
+  /** The series name. */\r
+  private List<String[]> mTitles = new ArrayList<String[]>();\r
+  /** The series values. */\r
+  private List<double[]> mValues = new ArrayList<double[]>();\r
+\r
+  /**\r
+   * Builds a new category series.\r
+   * \r
+   * @param title the series title\r
+   */\r
+  public MultipleCategorySeries(String title) {\r
+    mTitle = title;\r
+  }\r
+\r
+  /**\r
+   * Adds a new value to the series\r
+   * \r
+   * @param titles the titles to be used as labels\r
+   * @param values the new value\r
+   */\r
+  public void add(String[] titles, double[] values) {\r
+    add(mCategories.size() + "", titles, values);\r
+  }\r
+\r
+  /**\r
+   * Adds a new value to the series.\r
+   * \r
+   * @param category the category name\r
+   * @param titles the titles to be used as labels\r
+   * @param values the new value\r
+   */\r
+  public void add(String category, String[] titles, double[] values) {\r
+    mCategories.add(category);\r
+    mTitles.add(titles);\r
+    mValues.add(values);\r
+  }\r
+\r
+  /**\r
+   * Removes an existing value from the series.\r
+   * \r
+   * @param index the index in the series of the value to remove\r
+   */\r
+  public void remove(int index) {\r
+    mCategories.remove(index);\r
+    mTitles.remove(index);\r
+    mValues.remove(index);\r
+  }\r
+\r
+  /**\r
+   * Removes all the existing values from the series.\r
+   */\r
+  public void clear() {\r
+    mCategories.clear();\r
+    mTitles.clear();\r
+    mValues.clear();\r
+  }\r
+\r
+  /**\r
+   * Returns the values at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the value at the index\r
+   */\r
+  public double[] getValues(int index) {\r
+    return mValues.get(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the category name at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the category name at the index\r
+   */\r
+  public String getCategory(int index) {\r
+    return mCategories.get(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the categories count.\r
+   * \r
+   * @return the categories count\r
+   */\r
+  public int getCategoriesCount() {\r
+    return mCategories.size();\r
+  }\r
+\r
+  /**\r
+   * Returns the series item count.\r
+   * \r
+   * @param index the index\r
+   * @return the series item count\r
+   */\r
+  public int getItemCount(int index) {\r
+    return mValues.get(index).length;\r
+  }\r
+\r
+  /**\r
+   * Returns the series titles.\r
+   * \r
+   * @param index the index\r
+   * @return the series titles\r
+   */\r
+  public String[] getTitles(int index) {\r
+    return mTitles.get(index);\r
+  }\r
+\r
+  /**\r
+   * Transforms the category series to an XY series.\r
+   * \r
+   * @return the XY series\r
+   */\r
+  public XYSeries toXYSeries() {\r
+    XYSeries xySeries = new XYSeries(mTitle);\r
+    return xySeries;\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/model/Point.java b/android-libraries/achartengine/src/org/achartengine/model/Point.java
new file mode 100644 (file)
index 0000000..4d2767c
--- /dev/null
@@ -0,0 +1,52 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+\r
+/**\r
+ * A class to encapsulate the definition of a point.\r
+ */\r
+public final class Point implements Serializable {\r
+  /** The X axis coordinate value. */\r
+  private float mX;\r
+  /** The Y axis coordinate value. */\r
+  private float mY;\r
+  \r
+  public Point() {\r
+  }\r
+  \r
+  public Point(float x, float y) {\r
+    mX = x;\r
+    mY = y;\r
+  }\r
+  \r
+  public float getX() {\r
+    return mX;\r
+  }\r
+\r
+  public float getY() {\r
+    return mY;\r
+  }\r
+  \r
+  public void setX(float x) {\r
+    mX = x;\r
+  }\r
+  \r
+  public void setY(float y) {\r
+    mY = y;\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/model/RangeCategorySeries.java b/android-libraries/achartengine/src/org/achartengine/model/RangeCategorySeries.java
new file mode 100644 (file)
index 0000000..c004fa1
--- /dev/null
@@ -0,0 +1,111 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+/**\r
+ * A series for the range category charts like the range bar.\r
+ */\r
+public class RangeCategorySeries extends CategorySeries {\r
+  /** The series values. */\r
+  private List<Double> mMaxValues = new ArrayList<Double>();\r
+  /**\r
+   * Builds a new category series.\r
+   * \r
+   * @param title the series title\r
+   */\r
+  public RangeCategorySeries(String title) {\r
+    super(title);\r
+  }\r
+  /**\r
+   * Adds new values to the series\r
+   * \r
+   * @param minValue the new minimum value\r
+   * @param maxValue the new maximum value\r
+   */\r
+  public synchronized void add(double minValue, double maxValue) {\r
+    super.add(minValue);\r
+    mMaxValues.add(maxValue);\r
+  }\r
+\r
+  /**\r
+   * Adds new values to the series.\r
+   * \r
+   * @param category the category\r
+   * @param minValue the new minimum value\r
+   * @param maxValue the new maximum value\r
+   */\r
+  public synchronized void add(String category, double minValue, double maxValue) {\r
+    super.add(category, minValue);\r
+    mMaxValues.add(maxValue);\r
+  }\r
+\r
+  /**\r
+   * Removes existing values from the series.\r
+   * \r
+   * @param index the index in the series of the values to remove\r
+   */\r
+  public synchronized void remove(int index) {\r
+    super.remove(index);\r
+    mMaxValues.remove(index);\r
+  }\r
+\r
+  /**\r
+   * Removes all the existing values from the series.\r
+   */\r
+  public synchronized void clear() {\r
+    super.clear();\r
+    mMaxValues.clear();\r
+  }\r
+\r
+  /**\r
+   * Returns the minimum value at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the minimum value at the index\r
+   */\r
+  public double getMinimumValue(int index) {\r
+    return getValue(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the maximum value at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the maximum value at the index\r
+   */\r
+  public double getMaximumValue(int index) {\r
+    return mMaxValues.get(index);\r
+  }\r
+\r
+  /**\r
+   * Transforms the range category series to an XY series.\r
+   * \r
+   * @return the XY series\r
+   */\r
+  public XYSeries toXYSeries() {\r
+    XYSeries xySeries = new XYSeries(getTitle());\r
+    int length = getItemCount();\r
+    for (int k = 0; k < length; k++) {\r
+      xySeries.add(k + 1, getMinimumValue(k));\r
+      // the new fast XYSeries implementation doesn't allow 2 values at the same X,\r
+      // so I had to do a hack until I find a better solution\r
+      xySeries.add(k + 1.000001, getMaximumValue(k));\r
+    }\r
+    return xySeries;\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/model/SeriesSelection.java b/android-libraries/achartengine/src/org/achartengine/model/SeriesSelection.java
new file mode 100644 (file)
index 0000000..4319c74
--- /dev/null
@@ -0,0 +1,49 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+public class SeriesSelection {\r
+  private int mSeriesIndex;\r
+\r
+  private int mPointIndex;\r
+\r
+  private double mXValue;\r
+\r
+  private double mValue;\r
+\r
+  public SeriesSelection(int seriesIndex, int pointIndex, double xValue, double value) {\r
+    mSeriesIndex = seriesIndex;\r
+    mPointIndex = pointIndex;\r
+    mXValue = xValue;\r
+    mValue = value;\r
+  }\r
+\r
+  public int getSeriesIndex() {\r
+    return mSeriesIndex;\r
+  }\r
+\r
+  public int getPointIndex() {\r
+    return mPointIndex;\r
+  }\r
+\r
+  public double getXValue() {\r
+    return mXValue;\r
+  }\r
+\r
+  public double getValue() {\r
+    return mValue;\r
+  }\r
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/model/TimeSeries.java b/android-libraries/achartengine/src/org/achartengine/model/TimeSeries.java
new file mode 100644 (file)
index 0000000..6b9a18e
--- /dev/null
@@ -0,0 +1,43 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.util.Date;\r
+\r
+/**\r
+ * A series for the date / time charts.\r
+ */\r
+public class TimeSeries extends XYSeries {\r
+\r
+  /**\r
+   * Builds a new date / time series.\r
+   * \r
+   * @param title the series title\r
+   */\r
+  public TimeSeries(String title) {\r
+    super(title);\r
+  }\r
+\r
+  /**\r
+   * Adds a new value to the series.\r
+   * \r
+   * @param x the date / time value for the X axis\r
+   * @param y the value for the Y axis\r
+   */\r
+  public synchronized void add(Date x, double y) {\r
+    super.add(x.getTime(), y);\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/model/XYMultipleSeriesDataset.java b/android-libraries/achartengine/src/org/achartengine/model/XYMultipleSeriesDataset.java
new file mode 100644 (file)
index 0000000..6ac6a6d
--- /dev/null
@@ -0,0 +1,94 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * A series that includes 0 to many XYSeries.\r
+ */\r
+public class XYMultipleSeriesDataset implements Serializable {\r
+  /** The included series. */\r
+  private List<XYSeries> mSeries = new ArrayList<XYSeries>();\r
+\r
+  /**\r
+   * Adds a new XY series to the list.\r
+   * \r
+   * @param series the XY series to ass\r
+   */\r
+  public synchronized void addSeries(XYSeries series) {\r
+    mSeries.add(series);\r
+  }\r
+\r
+  /**\r
+   * Adds a new XY series to the list.\r
+   * \r
+   * @param index the index in the series list\r
+   * @param series the XY series to ass\r
+   */\r
+  public synchronized void addSeries(int index, XYSeries series) {\r
+    mSeries.add(index, series);\r
+  }\r
+\r
+  /**\r
+   * Removes the XY series from the list.\r
+   * \r
+   * @param index the index in the series list of the series to remove\r
+   */\r
+  public synchronized void removeSeries(int index) {\r
+    mSeries.remove(index);\r
+  }\r
+\r
+  /**\r
+   * Removes the XY series from the list.\r
+   * \r
+   * @param series the XY series to be removed\r
+   */\r
+  public synchronized void removeSeries(XYSeries series) {\r
+    mSeries.remove(series);\r
+  }\r
+\r
+  /**\r
+   * Returns the XY series at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the XY series at the index\r
+   */\r
+  public synchronized XYSeries getSeriesAt(int index) {\r
+    return mSeries.get(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the XY series count.\r
+   * \r
+   * @return the XY series count\r
+   */\r
+  public synchronized int getSeriesCount() {\r
+    return mSeries.size();\r
+  }\r
+\r
+  /**\r
+   * Returns an array of the XY series.\r
+   * \r
+   * @return the XY series array\r
+   */\r
+  public synchronized XYSeries[] getSeries() {\r
+    return mSeries.toArray(new XYSeries[0]);\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/model/XYSeries.java b/android-libraries/achartengine/src/org/achartengine/model/XYSeries.java
new file mode 100644 (file)
index 0000000..56063b7
--- /dev/null
@@ -0,0 +1,255 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.io.Serializable;\r
+import java.util.Iterator;\r
+import java.util.SortedMap;\r
+\r
+import org.achartengine.util.IndexXYMap;\r
+import org.achartengine.util.MathHelper;\r
+import org.achartengine.util.XYEntry;\r
+\r
+/**\r
+ * An XY series encapsulates values for XY charts like line, time, area,\r
+ * scatter... charts.\r
+ */\r
+public class XYSeries implements Serializable {\r
+  /** The series title. */\r
+  private String mTitle;\r
+  /** A map to contain values for X and Y axes and index for each bundle */\r
+  private final IndexXYMap<Double, Double> mXY = new IndexXYMap<Double, Double>();\r
+  /** The minimum value for the X axis. */\r
+  private double mMinX = MathHelper.NULL_VALUE;\r
+  /** The maximum value for the X axis. */\r
+  private double mMaxX = -MathHelper.NULL_VALUE;\r
+  /** The minimum value for the Y axis. */\r
+  private double mMinY = MathHelper.NULL_VALUE;\r
+  /** The maximum value for the Y axis. */\r
+  private double mMaxY = -MathHelper.NULL_VALUE;\r
+  /** The scale number for this series. */\r
+  private final int mScaleNumber;\r
+\r
+  /**\r
+   * Builds a new XY series.\r
+   * \r
+   * @param title the series title.\r
+   */\r
+  public XYSeries(String title) {\r
+    this(title, 0);\r
+  }\r
+\r
+  /**\r
+   * Builds a new XY series.\r
+   * \r
+   * @param title the series title.\r
+   * @param scaleNumber the series scale number\r
+   */\r
+  public XYSeries(String title, int scaleNumber) {\r
+    mTitle = title;\r
+    mScaleNumber = scaleNumber;\r
+    initRange();\r
+  }\r
+\r
+  public int getScaleNumber() {\r
+    return mScaleNumber;\r
+  }\r
+\r
+  /**\r
+   * Initializes the range for both axes.\r
+   */\r
+  private void initRange() {\r
+    mMinX = MathHelper.NULL_VALUE;\r
+    mMaxX = -MathHelper.NULL_VALUE;\r
+    mMinY = MathHelper.NULL_VALUE;\r
+    mMaxY = -MathHelper.NULL_VALUE;\r
+    int length = getItemCount();\r
+    for (int k = 0; k < length; k++) {\r
+      double x = getX(k);\r
+      double y = getY(k);\r
+      updateRange(x, y);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Updates the range on both axes.\r
+   * \r
+   * @param x the new x value\r
+   * @param y the new y value\r
+   */\r
+  private void updateRange(double x, double y) {\r
+    mMinX = Math.min(mMinX, x);\r
+    mMaxX = Math.max(mMaxX, x);\r
+    mMinY = Math.min(mMinY, y);\r
+    mMaxY = Math.max(mMaxY, y);\r
+  }\r
+\r
+  /**\r
+   * Returns the series title.\r
+   * \r
+   * @return the series title\r
+   */\r
+  public String getTitle() {\r
+    return mTitle;\r
+  }\r
+\r
+  /**\r
+   * Sets the series title.\r
+   * \r
+   * @param title the series title\r
+   */\r
+  public void setTitle(String title) {\r
+    mTitle = title;\r
+  }\r
+\r
+  /**\r
+   * Adds a new value to the series.\r
+   * \r
+   * @param x the value for the X axis\r
+   * @param y the value for the Y axis\r
+   */\r
+  public synchronized void add(double x, double y) {\r
+    mXY.put(x, y);\r
+    updateRange(x, y);\r
+  }\r
+\r
+  /**\r
+   * Removes an existing value from the series.\r
+   * \r
+   * @param index the index in the series of the value to remove\r
+   */\r
+  public synchronized void remove(int index) {\r
+    XYEntry<Double, Double> removedEntry = mXY.removeByIndex(index);\r
+    double removedX = removedEntry.getKey();\r
+    double removedY = removedEntry.getValue();\r
+    if (removedX == mMinX || removedX == mMaxX || removedY == mMinY || removedY == mMaxY) {\r
+      initRange();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Removes all the existing values from the series.\r
+   */\r
+  public synchronized void clear() {\r
+    mXY.clear();\r
+    initRange();\r
+  }\r
+\r
+  /**\r
+   * Returns the X axis value at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the X value\r
+   */\r
+  public synchronized double getX(int index) {\r
+    return mXY.getXByIndex(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the Y axis value at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the Y value\r
+   */\r
+  public synchronized double getY(int index) {\r
+    return mXY.getYByIndex(index);\r
+  }\r
+\r
+  /**\r
+   * Returns submap of x and y values according to the given start and end\r
+   * \r
+   * @param start start x value\r
+   * @param stop stop x value\r
+   * @return a submap of x and y values\r
+   */\r
+  public synchronized SortedMap<Double, Double> getRange(double start, double stop,\r
+      int beforeAfterPoints) {\r
+    // we need to add one point before the start and one point after the end (if\r
+    // there are any)\r
+    // to ensure that line doesn't end before the end of the screen\r
+\r
+    // this would be simply: start = mXY.lowerKey(start) but NavigableMap is\r
+    // available since API 9\r
+    SortedMap<Double, Double> headMap = mXY.headMap(start);\r
+    if (!headMap.isEmpty()) {\r
+      start = headMap.lastKey();\r
+    }\r
+\r
+    // this would be simply: end = mXY.higherKey(end) but NavigableMap is\r
+    // available since API 9\r
+    // so we have to do this hack in order to support older versions\r
+    SortedMap<Double, Double> tailMap = mXY.tailMap(stop);\r
+    if (!tailMap.isEmpty()) {\r
+      Iterator<Double> tailIterator = tailMap.keySet().iterator();\r
+      Double next = tailIterator.next();\r
+      if (tailIterator.hasNext()) {\r
+        stop = tailIterator.next();\r
+      } else {\r
+        stop += next;\r
+      }\r
+    }\r
+    return mXY.subMap(start, stop);\r
+  }\r
+\r
+  public int getIndexForKey(double key) {\r
+    return mXY.getIndexForKey(key);\r
+  }\r
+\r
+  /**\r
+   * Returns the series item count.\r
+   * \r
+   * @return the series item count\r
+   */\r
+  public synchronized int getItemCount() {\r
+    return mXY.size();\r
+  }\r
+\r
+  /**\r
+   * Returns the minimum value on the X axis.\r
+   * \r
+   * @return the X axis minimum value\r
+   */\r
+  public double getMinX() {\r
+    return mMinX;\r
+  }\r
+\r
+  /**\r
+   * Returns the minimum value on the Y axis.\r
+   * \r
+   * @return the Y axis minimum value\r
+   */\r
+  public double getMinY() {\r
+    return mMinY;\r
+  }\r
+\r
+  /**\r
+   * Returns the maximum value on the X axis.\r
+   * \r
+   * @return the X axis maximum value\r
+   */\r
+  public double getMaxX() {\r
+    return mMaxX;\r
+  }\r
+\r
+  /**\r
+   * Returns the maximum value on the Y axis.\r
+   * \r
+   * @return the Y axis maximum value\r
+   */\r
+  public double getMaxY() {\r
+    return mMaxY;\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/model/XYValueSeries.java b/android-libraries/achartengine/src/org/achartengine/model/XYValueSeries.java
new file mode 100644 (file)
index 0000000..81aff28
--- /dev/null
@@ -0,0 +1,139 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.model;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.achartengine.util.MathHelper;\r
+\r
+/**\r
+ * An extension of the XY series which adds a third dimension. It is used for XY\r
+ * charts like bubble.\r
+ */\r
+public class XYValueSeries extends XYSeries {\r
+  /** A list to contain the series values. */\r
+  private List<Double> mValue = new ArrayList<Double>();\r
+  /** The minimum value. */\r
+  private double mMinValue = MathHelper.NULL_VALUE;\r
+  /** The maximum value. */\r
+  private double mMaxValue = -MathHelper.NULL_VALUE;\r
+\r
+  /**\r
+   * Builds a new XY value series.\r
+   * \r
+   * @param title the series title.\r
+   */\r
+  public XYValueSeries(String title) {\r
+    super(title);\r
+  }\r
+\r
+  /**\r
+   * Adds a new value to the series.\r
+   * \r
+   * @param x the value for the X axis\r
+   * @param y the value for the Y axis\r
+   * @param value the value\r
+   */\r
+  public synchronized void add(double x, double y, double value) {\r
+    super.add(x, y);\r
+    mValue.add(value);\r
+    updateRange(value);\r
+  }\r
+\r
+  /**\r
+   * Initializes the values range.\r
+   */\r
+  private void initRange() {\r
+    mMinValue = MathHelper.NULL_VALUE;\r
+    mMaxValue = MathHelper.NULL_VALUE;\r
+    int length = getItemCount();\r
+    for (int k = 0; k < length; k++) {\r
+      updateRange(getValue(k));\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Updates the values range.\r
+   * \r
+   * @param value the new value\r
+   */\r
+  private void updateRange(double value) {\r
+    mMinValue = Math.min(mMinValue, value);\r
+    mMaxValue = Math.max(mMaxValue, value);\r
+  }\r
+\r
+  /**\r
+   * Adds a new value to the series.\r
+   * \r
+   * @param x the value for the X axis\r
+   * @param y the value for the Y axis\r
+   */\r
+  public synchronized void add(double x, double y) {\r
+    add(x, y, 0d);\r
+  }\r
+\r
+  /**\r
+   * Removes an existing value from the series.\r
+   * \r
+   * @param index the index in the series of the value to remove\r
+   */\r
+  public synchronized void remove(int index) {\r
+    super.remove(index);\r
+    double removedValue = mValue.remove(index);\r
+    if (removedValue == mMinValue || removedValue == mMaxValue) {\r
+      initRange();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Removes all the values from the series.\r
+   */\r
+  public synchronized void clear() {\r
+    super.clear();\r
+    mValue.clear();\r
+    initRange();\r
+  }\r
+\r
+  /**\r
+   * Returns the value at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the value\r
+   */\r
+  public synchronized double getValue(int index) {\r
+    return mValue.get(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the minimum value.\r
+   * \r
+   * @return the minimum value\r
+   */\r
+  public double getMinValue() {\r
+    return mMinValue;\r
+  }\r
+\r
+  /**\r
+   * Returns the maximum value.\r
+   * \r
+   * @return the maximum value\r
+   */\r
+  public double getMaxValue() {\r
+    return mMaxValue;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/model/package.html b/android-libraries/achartengine/src/org/achartengine/model/package.html
new file mode 100644 (file)
index 0000000..6135d29
--- /dev/null
@@ -0,0 +1,6 @@
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+Provides the classes that handle the data values (data model) to be used by displaying the charts.\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/package.html b/android-libraries/achartengine/src/org/achartengine/package.html
new file mode 100644 (file)
index 0000000..b26cf25
--- /dev/null
@@ -0,0 +1,6 @@
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+The main classes, including the ChartFactory, GraphicalActivity and GraphicalView.\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/renderer/BasicStroke.java b/android-libraries/achartengine/src/org/achartengine/renderer/BasicStroke.java
new file mode 100644 (file)
index 0000000..3ac93d5
--- /dev/null
@@ -0,0 +1,107 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.io.Serializable;\r
+\r
+import android.graphics.Paint.Cap;\r
+import android.graphics.Paint.Join;\r
+\r
+/**\r
+ * A descriptor for the stroke style.\r
+ */\r
+public class BasicStroke implements Serializable {\r
+  /** The solid line style. */\r
+  public static final BasicStroke SOLID = new BasicStroke(Cap.BUTT, Join.MITER, 4, null, 0);\r
+  /** The dashed line style. */\r
+  public static final BasicStroke DASHED = new BasicStroke(Cap.ROUND, Join.BEVEL, 10, new float[] {\r
+      10, 10 }, 1);\r
+  /** The dot line style. */\r
+  public static final BasicStroke DOTTED = new BasicStroke(Cap.ROUND, Join.BEVEL, 5, new float[] {\r
+      2, 10 }, 1);\r
+  /** The stroke cap. */\r
+  private Cap mCap;\r
+  /** The stroke join. */\r
+  private Join mJoin;\r
+  /** The stroke miter. */\r
+  private float mMiter;\r
+  /** The path effect intervals. */\r
+  private float[] mIntervals;\r
+  /** The path effect phase. */\r
+  private float mPhase;\r
+\r
+  /**\r
+   * Build a new basic stroke style.\r
+   * \r
+   * @param cap the stroke cap\r
+   * @param join the stroke join\r
+   * @param miter the stroke miter\r
+   * @param intervals the path effect intervals\r
+   * @param phase the path effect phase\r
+   */\r
+  public BasicStroke(Cap cap, Join join, float miter, float[] intervals, float phase) {\r
+    mCap = cap;\r
+    mJoin = join;\r
+    mMiter = miter;\r
+    mIntervals = intervals;\r
+  }\r
+\r
+  /**\r
+   * Returns the stroke cap.\r
+   * \r
+   * @return the stroke cap\r
+   */\r
+  public Cap getCap() {\r
+    return mCap;\r
+  }\r
+\r
+  /**\r
+   * Returns the stroke join.\r
+   * \r
+   * @return the stroke join\r
+   */\r
+  public Join getJoin() {\r
+    return mJoin;\r
+  }\r
+\r
+  /**\r
+   * Returns the stroke miter.\r
+   * \r
+   * @return the stroke miter\r
+   */\r
+  public float getMiter() {\r
+    return mMiter;\r
+  }\r
+\r
+  /**\r
+   * Returns the path effect intervals.\r
+   * \r
+   * @return the path effect intervals\r
+   */\r
+  public float[] getIntervals() {\r
+    return mIntervals;\r
+  }\r
+\r
+  /**\r
+   * Returns the path effect phase.\r
+   * \r
+   * @return the path effect phase\r
+   */\r
+  public float getPhase() {\r
+    return mPhase;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/renderer/DefaultRenderer.java b/android-libraries/achartengine/src/org/achartengine/renderer/DefaultRenderer.java
new file mode 100644 (file)
index 0000000..4dbb254
--- /dev/null
@@ -0,0 +1,750 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.io.Serializable;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import android.graphics.Color;\r
+import android.graphics.Typeface;\r
+\r
+/**\r
+ * An abstract renderer to be extended by the multiple series classes.\r
+ */\r
+public class DefaultRenderer implements Serializable {\r
+  /** The chart title. */\r
+  private String mChartTitle = "";\r
+  /** The chart title text size. */\r
+  private float mChartTitleTextSize = 15;\r
+  /** A no color constant. */\r
+  public static final int NO_COLOR = 0;\r
+  /** The default background color. */\r
+  public static final int BACKGROUND_COLOR = Color.BLACK;\r
+  /** The default color for text. */\r
+  public static final int TEXT_COLOR = Color.LTGRAY;\r
+  /** A text font for regular text, like the chart labels. */\r
+  private static final Typeface REGULAR_TEXT_FONT = Typeface\r
+      .create(Typeface.SERIF, Typeface.NORMAL);\r
+  /** The typeface name for the texts. */\r
+  private String mTextTypefaceName = REGULAR_TEXT_FONT.toString();\r
+  /** The typeface style for the texts. */\r
+  private int mTextTypefaceStyle = Typeface.NORMAL;\r
+  /** The chart background color. */\r
+  private int mBackgroundColor;\r
+  /** If the background color is applied. */\r
+  private boolean mApplyBackgroundColor;\r
+  /** If the axes are visible. */\r
+  private boolean mShowAxes = true;\r
+  /** The axes color. */\r
+  private int mAxesColor = TEXT_COLOR;\r
+  /** If the labels are visible. */\r
+  private boolean mShowLabels = true;\r
+  /** The labels color. */\r
+  private int mLabelsColor = TEXT_COLOR;\r
+  /** The labels text size. */\r
+  private float mLabelsTextSize = 10;\r
+  /** If the legend is visible. */\r
+  private boolean mShowLegend = true;\r
+  /** The legend text size. */\r
+  private float mLegendTextSize = 12;\r
+  /** If the legend should size to fit. */\r
+  private boolean mFitLegend = false;\r
+  /** If the X axis grid should be displayed. */\r
+  private boolean mShowGridX = false;\r
+  /** If the Y axis grid should be displayed. */\r
+  private boolean mShowGridY = false;\r
+  /** If the custom text grid should be displayed. */\r
+  private boolean mShowCustomTextGrid = false;\r
+  /** The simple renderers that are included in this multiple series renderer. */\r
+  private List<SimpleSeriesRenderer> mRenderers = new ArrayList<SimpleSeriesRenderer>();\r
+  /** The antialiasing flag. */\r
+  private boolean mAntialiasing = true;\r
+  /** The legend height. */\r
+  private int mLegendHeight = 0;\r
+  /** The margins size. */\r
+  private int[] mMargins = new int[] { 20, 30, 10, 20 };\r
+  /** A value to be used for scaling the chart. */\r
+  private float mScale = 1;\r
+  /** A flag for enabling the pan. */\r
+  private boolean mPanEnabled = true;\r
+  /** A flag for enabling the zoom. */\r
+  private boolean mZoomEnabled = true;\r
+  /** A flag for enabling the visibility of the zoom buttons. */\r
+  private boolean mZoomButtonsVisible = false;\r
+  /** The zoom rate. */\r
+  private float mZoomRate = 1.5f;\r
+  /** A flag for enabling the external zoom. */\r
+  private boolean mExternalZoomEnabled = false;\r
+  /** The original chart scale. */\r
+  private float mOriginalScale = mScale;\r
+  /** A flag for enabling the click on elements. */\r
+  private boolean mClickEnabled = false;\r
+  /** The selectable radius around a clickable point. */\r
+  private int selectableBuffer = 15;\r
+  /** If the chart should display the values (available for pie chart). */\r
+  private boolean mDisplayValues;\r
+\r
+  /**\r
+   * A flag to be set if the chart is inside a scroll and doesn't need to shrink\r
+   * when not enough space.\r
+   */\r
+  private boolean mInScroll;\r
+  /** The start angle for circular charts such as pie, doughnut, etc. */\r
+  private float mStartAngle = 0;\r
+\r
+  /**\r
+   * Returns the chart title.\r
+   * \r
+   * @return the chart title\r
+   */\r
+  public String getChartTitle() {\r
+    return mChartTitle;\r
+  }\r
+\r
+  /**\r
+   * Sets the chart title.\r
+   * \r
+   * @param title the chart title\r
+   */\r
+  public void setChartTitle(String title) {\r
+    mChartTitle = title;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart title text size.\r
+   * \r
+   * @return the chart title text size\r
+   */\r
+  public float getChartTitleTextSize() {\r
+    return mChartTitleTextSize;\r
+  }\r
+\r
+  /**\r
+   * Sets the chart title text size.\r
+   * \r
+   * @param textSize the chart title text size\r
+   */\r
+  public void setChartTitleTextSize(float textSize) {\r
+    mChartTitleTextSize = textSize;\r
+  }\r
+\r
+  /**\r
+   * Adds a simple renderer to the multiple renderer.\r
+   * \r
+   * @param renderer the renderer to be added\r
+   */\r
+  public void addSeriesRenderer(SimpleSeriesRenderer renderer) {\r
+    mRenderers.add(renderer);\r
+  }\r
+\r
+  /**\r
+   * Adds a simple renderer to the multiple renderer.\r
+   * \r
+   * @param index the index in the renderers list\r
+   * @param renderer the renderer to be added\r
+   */\r
+  public void addSeriesRenderer(int index, SimpleSeriesRenderer renderer) {\r
+    mRenderers.add(index, renderer);\r
+  }\r
+\r
+  /**\r
+   * Removes a simple renderer from the multiple renderer.\r
+   * \r
+   * @param renderer the renderer to be removed\r
+   */\r
+  public void removeSeriesRenderer(SimpleSeriesRenderer renderer) {\r
+    mRenderers.remove(renderer);\r
+  }\r
+\r
+  /**\r
+   * Removes all renderers from the multiple renderer.\r
+   */\r
+  public void removeAllRenderers() {\r
+    mRenderers.clear();\r
+  }\r
+\r
+  /**\r
+   * Returns the simple renderer from the multiple renderer list.\r
+   * \r
+   * @param index the index in the simple renderers list\r
+   * @return the simple renderer at the specified index\r
+   */\r
+  public SimpleSeriesRenderer getSeriesRendererAt(int index) {\r
+    return mRenderers.get(index);\r
+  }\r
+\r
+  /**\r
+   * Returns the simple renderers count in the multiple renderer list.\r
+   * \r
+   * @return the simple renderers count\r
+   */\r
+  public int getSeriesRendererCount() {\r
+    return mRenderers.size();\r
+  }\r
+\r
+  /**\r
+   * Returns an array of the simple renderers in the multiple renderer list.\r
+   * \r
+   * @return the simple renderers array\r
+   */\r
+  public SimpleSeriesRenderer[] getSeriesRenderers() {\r
+    return mRenderers.toArray(new SimpleSeriesRenderer[0]);\r
+  }\r
+\r
+  /**\r
+   * Returns the background color.\r
+   * \r
+   * @return the background color\r
+   */\r
+  public int getBackgroundColor() {\r
+    return mBackgroundColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the background color.\r
+   * \r
+   * @param color the background color\r
+   */\r
+  public void setBackgroundColor(int color) {\r
+    mBackgroundColor = color;\r
+  }\r
+\r
+  /**\r
+   * Returns if the background color should be applied.\r
+   * \r
+   * @return the apply flag for the background color.\r
+   */\r
+  public boolean isApplyBackgroundColor() {\r
+    return mApplyBackgroundColor;\r
+  }\r
+\r
+  /**\r
+   * Sets if the background color should be applied.\r
+   * \r
+   * @param apply the apply flag for the background color\r
+   */\r
+  public void setApplyBackgroundColor(boolean apply) {\r
+    mApplyBackgroundColor = apply;\r
+  }\r
+\r
+  /**\r
+   * Returns the axes color.\r
+   * \r
+   * @return the axes color\r
+   */\r
+  public int getAxesColor() {\r
+    return mAxesColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the axes color.\r
+   * \r
+   * @param color the axes color\r
+   */\r
+  public void setAxesColor(int color) {\r
+    mAxesColor = color;\r
+  }\r
+\r
+  /**\r
+   * Returns the labels color.\r
+   * \r
+   * @return the labels color\r
+   */\r
+  public int getLabelsColor() {\r
+    return mLabelsColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the labels color.\r
+   * \r
+   * @param color the labels color\r
+   */\r
+  public void setLabelsColor(int color) {\r
+    mLabelsColor = color;\r
+  }\r
+\r
+  /**\r
+   * Returns the labels text size.\r
+   * \r
+   * @return the labels text size\r
+   */\r
+  public float getLabelsTextSize() {\r
+    return mLabelsTextSize;\r
+  }\r
+\r
+  /**\r
+   * Sets the labels text size.\r
+   * \r
+   * @param textSize the labels text size\r
+   */\r
+  public void setLabelsTextSize(float textSize) {\r
+    mLabelsTextSize = textSize;\r
+  }\r
+\r
+  /**\r
+   * Returns if the axes should be visible.\r
+   * \r
+   * @return the visibility flag for the axes\r
+   */\r
+  public boolean isShowAxes() {\r
+    return mShowAxes;\r
+  }\r
+\r
+  /**\r
+   * Sets if the axes should be visible.\r
+   * \r
+   * @param showAxes the visibility flag for the axes\r
+   */\r
+  public void setShowAxes(boolean showAxes) {\r
+    mShowAxes = showAxes;\r
+  }\r
+\r
+  /**\r
+   * Returns if the labels should be visible.\r
+   * \r
+   * @return the visibility flag for the labels\r
+   */\r
+  public boolean isShowLabels() {\r
+    return mShowLabels;\r
+  }\r
+\r
+  /**\r
+   * Sets if the labels should be visible.\r
+   * \r
+   * @param showLabels the visibility flag for the labels\r
+   */\r
+  public void setShowLabels(boolean showLabels) {\r
+    mShowLabels = showLabels;\r
+  }\r
+\r
+  /**\r
+   * Returns if the X axis grid should be visible.\r
+   * \r
+   * @return the visibility flag for the X axis grid\r
+   */\r
+  public boolean isShowGridX() {\r
+    return mShowGridX;\r
+  }\r
+\r
+  /**\r
+   * Returns if the Y axis grid should be visible.\r
+   * \r
+   * @return the visibility flag for the Y axis grid\r
+   */\r
+  public boolean isShowGridY() {\r
+    return mShowGridY;\r
+  }\r
+\r
+  /**\r
+   * Sets if the X axis grid should be visible.\r
+   * \r
+   * @param showGrid the visibility flag for the X axis grid\r
+   */\r
+  public void setShowGridX(boolean showGrid) {\r
+    mShowGridX = showGrid;\r
+  }\r
+\r
+  /**\r
+   * Sets if the Y axis grid should be visible.\r
+   * \r
+   * @param showGrid the visibility flag for the Y axis grid\r
+   */\r
+  public void setShowGridY(boolean showGrid) {\r
+    mShowGridY = showGrid;\r
+  }\r
+\r
+  /**\r
+   * Sets if the grid should be visible.\r
+   * \r
+   * @param showGrid the visibility flag for the grid\r
+   */\r
+  public void setShowGrid(boolean showGrid) {\r
+    setShowGridX(showGrid);\r
+    setShowGridY(showGrid);\r
+  }\r
+\r
+  /**\r
+   * Returns if the grid should be visible for custom X or Y labels.\r
+   * \r
+   * @return the visibility flag for the custom text grid\r
+   */\r
+  public boolean isShowCustomTextGrid() {\r
+    return mShowCustomTextGrid;\r
+  }\r
+\r
+  /**\r
+   * Sets if the grid for custom X or Y labels should be visible.\r
+   * \r
+   * @param showGrid the visibility flag for the custom text grid\r
+   */\r
+  public void setShowCustomTextGrid(boolean showGrid) {\r
+    mShowCustomTextGrid = showGrid;\r
+  }\r
+\r
+  /**\r
+   * Returns if the legend should be visible.\r
+   * \r
+   * @return the visibility flag for the legend\r
+   */\r
+  public boolean isShowLegend() {\r
+    return mShowLegend;\r
+  }\r
+\r
+  /**\r
+   * Sets if the legend should be visible.\r
+   * \r
+   * @param showLegend the visibility flag for the legend\r
+   */\r
+  public void setShowLegend(boolean showLegend) {\r
+    mShowLegend = showLegend;\r
+  }\r
+\r
+  /**\r
+   * Returns if the legend should size to fit.\r
+   * \r
+   * @return the fit behavior\r
+   */\r
+  public boolean isFitLegend() {\r
+    return mFitLegend;\r
+  }\r
+\r
+  /**\r
+   * Sets if the legend should size to fit.\r
+   * \r
+   * @param fit the fit behavior\r
+   */\r
+  public void setFitLegend(boolean fit) {\r
+    mFitLegend = fit;\r
+  }\r
+\r
+  /**\r
+   * Returns the text typeface name.\r
+   * \r
+   * @return the text typeface name\r
+   */\r
+  public String getTextTypefaceName() {\r
+    return mTextTypefaceName;\r
+  }\r
+\r
+  /**\r
+   * Returns the text typeface style.\r
+   * \r
+   * @return the text typeface style\r
+   */\r
+  public int getTextTypefaceStyle() {\r
+    return mTextTypefaceStyle;\r
+  }\r
+\r
+  /**\r
+   * Returns the legend text size.\r
+   * \r
+   * @return the legend text size\r
+   */\r
+  public float getLegendTextSize() {\r
+    return mLegendTextSize;\r
+  }\r
+\r
+  /**\r
+   * Sets the legend text size.\r
+   * \r
+   * @param textSize the legend text size\r
+   */\r
+  public void setLegendTextSize(float textSize) {\r
+    mLegendTextSize = textSize;\r
+  }\r
+\r
+  /**\r
+   * Sets the text typeface name and style.\r
+   * \r
+   * @param typefaceName the text typeface name\r
+   * @param style the text typeface style\r
+   */\r
+  public void setTextTypeface(String typefaceName, int style) {\r
+    mTextTypefaceName = typefaceName;\r
+    mTextTypefaceStyle = style;\r
+  }\r
+\r
+  /**\r
+   * Returns the antialiasing flag value.\r
+   * \r
+   * @return the antialiasing value\r
+   */\r
+  public boolean isAntialiasing() {\r
+    return mAntialiasing;\r
+  }\r
+\r
+  /**\r
+   * Sets the antialiasing value.\r
+   * \r
+   * @param antialiasing the antialiasing\r
+   */\r
+  public void setAntialiasing(boolean antialiasing) {\r
+    mAntialiasing = antialiasing;\r
+  }\r
+\r
+  /**\r
+   * Returns the value to be used for scaling the chart.\r
+   * \r
+   * @return the scale value\r
+   */\r
+  public float getScale() {\r
+    return mScale;\r
+  }\r
+\r
+  /**\r
+   * Returns the original value to be used for scaling the chart.\r
+   * \r
+   * @return the original scale value\r
+   */\r
+  public float getOriginalScale() {\r
+    return mOriginalScale;\r
+  }\r
+\r
+  /**\r
+   * Sets the value to be used for scaling the chart. It works on some charts\r
+   * like pie, doughnut, dial.\r
+   * \r
+   * @param scale the scale value\r
+   */\r
+  public void setScale(float scale) {\r
+    mScale = scale;\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the zoom.\r
+   * \r
+   * @return if zoom is enabled\r
+   */\r
+  public boolean isZoomEnabled() {\r
+    return mZoomEnabled;\r
+  }\r
+\r
+  /**\r
+   * Sets the enabled state of the zoom.\r
+   * \r
+   * @param enabled zoom enabled\r
+   */\r
+  public void setZoomEnabled(boolean enabled) {\r
+    mZoomEnabled = enabled;\r
+  }\r
+\r
+  /**\r
+   * Returns the visible state of the zoom buttons.\r
+   * \r
+   * @return if zoom buttons are visible\r
+   */\r
+  public boolean isZoomButtonsVisible() {\r
+    return mZoomButtonsVisible;\r
+  }\r
+\r
+  /**\r
+   * Sets the visible state of the zoom buttons.\r
+   * \r
+   * @param visible if the zoom buttons are visible\r
+   */\r
+  public void setZoomButtonsVisible(boolean visible) {\r
+    mZoomButtonsVisible = visible;\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the external (application implemented) zoom.\r
+   * \r
+   * @return if external zoom is enabled\r
+   */\r
+  public boolean isExternalZoomEnabled() {\r
+    return mExternalZoomEnabled;\r
+  }\r
+\r
+  /**\r
+   * Sets the enabled state of the external (application implemented) zoom.\r
+   * \r
+   * @param enabled external zoom enabled\r
+   */\r
+  public void setExternalZoomEnabled(boolean enabled) {\r
+    mExternalZoomEnabled = enabled;\r
+  }\r
+\r
+  /**\r
+   * Returns the zoom rate.\r
+   * \r
+   * @return the zoom rate\r
+   */\r
+  public float getZoomRate() {\r
+    return mZoomRate;\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the pan.\r
+   * \r
+   * @return if pan is enabled\r
+   */\r
+  public boolean isPanEnabled() {\r
+    return mPanEnabled;\r
+  }\r
+\r
+  /**\r
+   * Sets the enabled state of the pan.\r
+   * \r
+   * @param enabled pan enabled\r
+   */\r
+  public void setPanEnabled(boolean enabled) {\r
+    mPanEnabled = enabled;\r
+  }\r
+\r
+  /**\r
+   * Sets the zoom rate.\r
+   * \r
+   * @param rate the zoom rate\r
+   */\r
+  public void setZoomRate(float rate) {\r
+    mZoomRate = rate;\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the click.\r
+   * \r
+   * @return if click is enabled\r
+   */\r
+  public boolean isClickEnabled() {\r
+    return mClickEnabled;\r
+  }\r
+\r
+  /**\r
+   * Sets the enabled state of the click.\r
+   * \r
+   * @param enabled click enabled\r
+   */\r
+  public void setClickEnabled(boolean enabled) {\r
+    mClickEnabled = enabled;\r
+  }\r
+\r
+  /**\r
+   * Returns the selectable radius value around clickable points.\r
+   * \r
+   * @return the selectable radius\r
+   */\r
+  public int getSelectableBuffer() {\r
+    return selectableBuffer;\r
+  }\r
+\r
+  /**\r
+   * Sets the selectable radius value around clickable points.\r
+   * \r
+   * @param buffer the selectable radius\r
+   */\r
+  public void setSelectableBuffer(int buffer) {\r
+    selectableBuffer = buffer;\r
+  }\r
+\r
+  /**\r
+   * Returns the legend height.\r
+   * \r
+   * @return the legend height\r
+   */\r
+  public int getLegendHeight() {\r
+    return mLegendHeight;\r
+  }\r
+\r
+  /**\r
+   * Sets the legend height, in pixels.\r
+   * \r
+   * @param height the legend height\r
+   */\r
+  public void setLegendHeight(int height) {\r
+    mLegendHeight = height;\r
+  }\r
+\r
+  /**\r
+   * Returns the margin sizes. An array containing the margins in this order:\r
+   * top, left, bottom, right\r
+   * \r
+   * @return the margin sizes\r
+   */\r
+  public int[] getMargins() {\r
+    return mMargins;\r
+  }\r
+\r
+  /**\r
+   * Sets the margins, in pixels.\r
+   * \r
+   * @param margins an array containing the margin size values, in this order:\r
+   *          top, left, bottom, right\r
+   */\r
+  public void setMargins(int[] margins) {\r
+    mMargins = margins;\r
+  }\r
+\r
+  /**\r
+   * Returns if the chart is inside a scroll view and doesn't need to shrink.\r
+   * \r
+   * @return if it is inside a scroll view\r
+   */\r
+  public boolean isInScroll() {\r
+    return mInScroll;\r
+  }\r
+\r
+  /**\r
+   * To be set if the chart is inside a scroll view and doesn't need to shrink\r
+   * when not enough space.\r
+   * \r
+   * @param inScroll if it is inside a scroll view\r
+   */\r
+  public void setInScroll(boolean inScroll) {\r
+    mInScroll = inScroll;\r
+  }\r
+\r
+  /**\r
+   * Returns the start angle for circular charts such as pie, doughnut. An angle\r
+   * of 0 degrees correspond to the geometric angle of 0 degrees (3 o'clock on a\r
+   * watch.)\r
+   * \r
+   * @return the start angle in degrees\r
+   */\r
+  public float getStartAngle() {\r
+    return mStartAngle;\r
+  }\r
+\r
+  /**\r
+   * Sets the start angle for circular charts such as pie, doughnut, etc. An\r
+   * angle of 0 degrees correspond to the geometric angle of 0 degrees (3\r
+   * o'clock on a watch.)\r
+   * \r
+   * @param startAngle the start angle in degrees\r
+   */\r
+  public void setStartAngle(float startAngle) {\r
+    mStartAngle = startAngle;\r
+  }\r
+\r
+  /**\r
+   * Returns if the values should be displayed as text.\r
+   * \r
+   * @return if the values should be displayed as text\r
+   */\r
+  public boolean isDisplayValues() {\r
+    return mDisplayValues;\r
+  }\r
+\r
+  /**\r
+   * Sets if the values should be displayed as text (supported by pie chart).\r
+   * \r
+   * @param display if the values should be displayed as text\r
+   */\r
+  public void setDisplayValues(boolean display) {\r
+    mDisplayValues = display;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/renderer/DialRenderer.java b/android-libraries/achartengine/src/org/achartengine/renderer/DialRenderer.java
new file mode 100644 (file)
index 0000000..1ed8461
--- /dev/null
@@ -0,0 +1,196 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Arrays;\r
+import java.util.List;\r
+\r
+import org.achartengine.util.MathHelper;\r
+\r
+/**\r
+ * Dial chart renderer.\r
+ */\r
+public class DialRenderer extends DefaultRenderer {\r
+  /** The start angle in the dial range. */\r
+  private double mAngleMin = 330;\r
+  /** The end angle in the dial range. */\r
+  private double mAngleMax = 30;\r
+  /** The start value in dial range. */\r
+  private double mMinValue = MathHelper.NULL_VALUE;\r
+  /** The end value in dial range. */\r
+  private double mMaxValue = -MathHelper.NULL_VALUE;\r
+  /** The spacing for the minor ticks. */\r
+  private double mMinorTickSpacing = MathHelper.NULL_VALUE;\r
+  /** The spacing for the major ticks. */\r
+  private double mMajorTickSpacing = MathHelper.NULL_VALUE;\r
+  /** An array of the renderers types (default is NEEDLE). */\r
+  private List<Type> mVisualTypes = new ArrayList<Type>();\r
+\r
+  public enum Type {\r
+    NEEDLE, ARROW;\r
+  }\r
+\r
+  /**\r
+   * Returns the start angle value of the dial.\r
+   * \r
+   * @return the angle start value\r
+   */\r
+  public double getAngleMin() {\r
+    return mAngleMin;\r
+  }\r
+\r
+  /**\r
+   * Sets the start angle value of the dial.\r
+   * \r
+   * @param min the dial angle start value\r
+   */\r
+  public void setAngleMin(double min) {\r
+    mAngleMin = min;\r
+  }\r
+\r
+  /**\r
+   * Returns the end angle value of the dial.\r
+   * \r
+   * @return the angle end value\r
+   */\r
+  public double getAngleMax() {\r
+    return mAngleMax;\r
+  }\r
+\r
+  /**\r
+   * Sets the end angle value of the dial.\r
+   * \r
+   * @param max the dial angle end value\r
+   */\r
+  public void setAngleMax(double max) {\r
+    mAngleMax = max;\r
+  }\r
+\r
+  /**\r
+   * Returns the start value to be rendered on the dial.\r
+   * \r
+   * @return the start value on dial\r
+   */\r
+  public double getMinValue() {\r
+    return mMinValue;\r
+  }\r
+\r
+  /**\r
+   * Sets the start value to be rendered on the dial.\r
+   * \r
+   * @param min the start value on the dial\r
+   */\r
+  public void setMinValue(double min) {\r
+    mMinValue = min;\r
+  }\r
+\r
+  /**\r
+   * Returns if the minimum dial value was set.\r
+   * \r
+   * @return the minimum dial value was set or not\r
+   */\r
+  public boolean isMinValueSet() {\r
+    return mMinValue != MathHelper.NULL_VALUE;\r
+  }\r
+\r
+  /**\r
+   * Returns the end value to be rendered on the dial.\r
+   * \r
+   * @return the end value on the dial\r
+   */\r
+  public double getMaxValue() {\r
+    return mMaxValue;\r
+  }\r
+\r
+  /**\r
+   * Sets the end value to be rendered on the dial.\r
+   * \r
+   * @param max the end value on the dial\r
+   */\r
+  public void setMaxValue(double max) {\r
+    mMaxValue = max;\r
+  }\r
+\r
+  /**\r
+   * Returns if the maximum dial value was set.\r
+   * \r
+   * @return the maximum dial was set or not\r
+   */\r
+  public boolean isMaxValueSet() {\r
+    return mMaxValue != -MathHelper.NULL_VALUE;\r
+  }\r
+\r
+  /**\r
+   * Returns the minor ticks spacing.\r
+   * \r
+   * @return the minor ticks spacing\r
+   */\r
+  public double getMinorTicksSpacing() {\r
+    return mMinorTickSpacing;\r
+  }\r
+\r
+  /**\r
+   * Sets the minor ticks spacing.\r
+   * \r
+   * @param spacing the minor ticks spacing\r
+   */\r
+  public void setMinorTicksSpacing(double spacing) {\r
+    mMinorTickSpacing = spacing;\r
+  }\r
+\r
+  /**\r
+   * Returns the major ticks spacing.\r
+   * \r
+   * @return the major ticks spacing\r
+   */\r
+  public double getMajorTicksSpacing() {\r
+    return mMajorTickSpacing;\r
+  }\r
+\r
+  /**\r
+   * Sets the major ticks spacing.\r
+   * \r
+   * @param spacing the major ticks spacing\r
+   */\r
+  public void setMajorTicksSpacing(double spacing) {\r
+    mMajorTickSpacing = spacing;\r
+  }\r
+\r
+  /**\r
+   * Returns the visual type at the specified index.\r
+   * \r
+   * @param index the index\r
+   * @return the visual type\r
+   */\r
+  public Type getVisualTypeForIndex(int index) {\r
+    if (index < mVisualTypes.size()) {\r
+      return mVisualTypes.get(index);\r
+    }\r
+    return Type.NEEDLE;\r
+  }\r
+\r
+  /**\r
+   * Sets the visual types.\r
+   * \r
+   * @param types the visual types\r
+   */\r
+  public void setVisualTypes(Type[] types) {\r
+    mVisualTypes.clear();\r
+    mVisualTypes.addAll(Arrays.asList(types));\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/renderer/SimpleSeriesRenderer.java b/android-libraries/achartengine/src/org/achartengine/renderer/SimpleSeriesRenderer.java
new file mode 100644 (file)
index 0000000..0763fc5
--- /dev/null
@@ -0,0 +1,235 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.io.Serializable;\r
+\r
+import android.graphics.Color;\r
+import android.graphics.Paint.Align;\r
+\r
+/**\r
+ * A simple series renderer.\r
+ */\r
+public class SimpleSeriesRenderer implements Serializable {\r
+  /** The series color. */\r
+  private int mColor = Color.BLUE;\r
+  /** If the values should be displayed above the chart points. */\r
+  private boolean mDisplayChartValues;\r
+  /** The chart values text size. */\r
+  private float mChartValuesTextSize = 10;\r
+  /** The chart values text alignment. */\r
+  private Align mChartValuesTextAlign = Align.CENTER;\r
+  /** The chart values spacing from the data point. */\r
+  private float mChartValuesSpacing = 5f;\r
+  /** The stroke style. */\r
+  private BasicStroke mStroke;\r
+  /** If gradient is enabled. */\r
+  private boolean mGradientEnabled = false;\r
+  /** The gradient start value. */\r
+  private double mGradientStartValue;\r
+  /** The gradient start color. */\r
+  private int mGradientStartColor;\r
+  /** The gradient stop value. */\r
+  private double mGradientStopValue;\r
+  /** The gradient stop color. */\r
+  private int mGradientStopColor;\r
+\r
+  /**\r
+   * Returns the series color.\r
+   * \r
+   * @return the series color\r
+   */\r
+  public int getColor() {\r
+    return mColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the series color.\r
+   * \r
+   * @param color the series color\r
+   */\r
+  public void setColor(int color) {\r
+    mColor = color;\r
+  }\r
+\r
+  /**\r
+   * Returns if the chart point values should be displayed as text.\r
+   * \r
+   * @return if the chart point values should be displayed as text\r
+   */\r
+  public boolean isDisplayChartValues() {\r
+    return mDisplayChartValues;\r
+  }\r
+\r
+  /**\r
+   * Sets if the chart point values should be displayed as text.\r
+   * \r
+   * @param display if the chart point values should be displayed as text\r
+   */\r
+  public void setDisplayChartValues(boolean display) {\r
+    mDisplayChartValues = display;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart values text size.\r
+   * \r
+   * @return the chart values text size\r
+   */\r
+  public float getChartValuesTextSize() {\r
+    return mChartValuesTextSize;\r
+  }\r
+\r
+  /**\r
+   * Sets the chart values text size.\r
+   * \r
+   * @param textSize the chart values text size\r
+   */\r
+  public void setChartValuesTextSize(float textSize) {\r
+    mChartValuesTextSize = textSize;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart values text align.\r
+   * \r
+   * @return the chart values text align\r
+   */\r
+  public Align getChartValuesTextAlign() {\r
+    return mChartValuesTextAlign;\r
+  }\r
+\r
+  /**\r
+   * Sets the chart values text align.\r
+   * \r
+   * @param align the chart values text align\r
+   */\r
+  public void setChartValuesTextAlign(Align align) {\r
+    mChartValuesTextAlign = align;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart values spacing from the data point.\r
+   * \r
+   * @return the chart values spacing\r
+   */\r
+  public float getChartValuesSpacing() {\r
+    return mChartValuesSpacing;\r
+  }\r
+\r
+  /**\r
+   * Sets the chart values spacing from the data point.\r
+   * \r
+   * @param spacing the chart values spacing (in pixels) from the chart data\r
+   *          point\r
+   */\r
+  public void setChartValuesSpacing(float spacing) {\r
+    mChartValuesSpacing = spacing;\r
+  }\r
+\r
+  /**\r
+   * Returns the stroke style.\r
+   * \r
+   * @return the stroke style\r
+   */\r
+  public BasicStroke getStroke() {\r
+    return mStroke;\r
+  }\r
+\r
+  /**\r
+   * Sets the stroke style.\r
+   * \r
+   * @param stroke the stroke style\r
+   */\r
+  public void setStroke(BasicStroke stroke) {\r
+    mStroke = stroke;\r
+  }\r
+\r
+  /**\r
+   * Returns the gradient is enabled value.\r
+   * \r
+   * @return the gradient enabled\r
+   */\r
+  public boolean isGradientEnabled() {\r
+    return mGradientEnabled;\r
+  }\r
+\r
+  /**\r
+   * Sets the gradient enabled value.\r
+   * \r
+   * @param enabled the gradient enabled\r
+   */\r
+  public void setGradientEnabled(boolean enabled) {\r
+    mGradientEnabled = enabled;\r
+  }\r
+\r
+  /**\r
+   * Returns the gradient start value.\r
+   * \r
+   * @return the gradient start value\r
+   */\r
+  public double getGradientStartValue() {\r
+    return mGradientStartValue;\r
+  }\r
+\r
+  /**\r
+   * Returns the gradient start color.\r
+   * \r
+   * @return the gradient start color\r
+   */\r
+  public int getGradientStartColor() {\r
+    return mGradientStartColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the gradient start value and color.\r
+   * \r
+   * @param start the gradient start value\r
+   * @param color the gradient start color\r
+   */\r
+  public void setGradientStart(double start, int color) {\r
+    mGradientStartValue = start;\r
+    mGradientStartColor = color;\r
+  }\r
+\r
+  /**\r
+   * Returns the gradient stop value.\r
+   * \r
+   * @return the gradient stop value\r
+   */\r
+  public double getGradientStopValue() {\r
+    return mGradientStopValue;\r
+  }\r
+\r
+  /**\r
+   * Returns the gradient stop color.\r
+   * \r
+   * @return the gradient stop color\r
+   */\r
+  public int getGradientStopColor() {\r
+    return mGradientStopColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the gradient stop value and color.\r
+   * \r
+   * @param start the gradient stop value\r
+   * @param color the gradient stop color\r
+   */\r
+  public void setGradientStop(double start, int color) {\r
+    mGradientStopValue = start;\r
+    mGradientStopColor = color;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/renderer/XYMultipleSeriesRenderer.java b/android-libraries/achartengine/src/org/achartengine/renderer/XYMultipleSeriesRenderer.java
new file mode 100644 (file)
index 0000000..64b3421
--- /dev/null
@@ -0,0 +1,1101 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import java.util.HashMap;\r
+import java.util.LinkedHashMap;\r
+import java.util.Map;\r
+\r
+import org.achartengine.util.MathHelper;\r
+\r
+import android.graphics.Color;\r
+import android.graphics.Paint.Align;\r
+\r
+/**\r
+ * Multiple XY series renderer.\r
+ */\r
+public class XYMultipleSeriesRenderer extends DefaultRenderer {\r
+  /** The X axis title. */\r
+  private String mXTitle = "";\r
+  /** The Y axis title. */\r
+  private String[] mYTitle;\r
+  /** The axis title text size. */\r
+  private float mAxisTitleTextSize = 12;\r
+  /** The start value in the X axis range. */\r
+  private double[] mMinX;\r
+  /** The end value in the X axis range. */\r
+  private double[] mMaxX;\r
+  /** The start value in the Y axis range. */\r
+  private double[] mMinY;\r
+  /** The end value in the Y axis range. */\r
+  private double[] mMaxY;\r
+  /** The approximative number of labels on the x axis. */\r
+  private int mXLabels = 5;\r
+  /** The approximative number of labels on the y axis. */\r
+  private int mYLabels = 5;\r
+  /** The current orientation of the chart. */\r
+  private Orientation mOrientation = Orientation.HORIZONTAL;\r
+  /** The X axis text labels. */\r
+  private Map<Double, String> mXTextLabels = new HashMap<Double, String>();\r
+  /** The Y axis text labels. */\r
+  private Map<Integer, Map<Double, String>> mYTextLabels = new LinkedHashMap<Integer, Map<Double, String>>();\r
+  /** A flag for enabling or not the pan on the X axis. */\r
+  private boolean mPanXEnabled = true;\r
+  /** A flag for enabling or not the pan on the Y axis. */\r
+  private boolean mPanYEnabled = true;\r
+  /** A flag for enabling or not the zoom on the X axis. */\r
+  private boolean mZoomXEnabled = true;\r
+  /** A flag for enabling or not the zoom on the Y axis . */\r
+  private boolean mZoomYEnabled = true;\r
+  /** The spacing between bars, in bar charts. */\r
+  private double mBarSpacing = 0;\r
+  /** The margins colors. */\r
+  private int mMarginsColor = NO_COLOR;\r
+  /** The pan limits. */\r
+  private double[] mPanLimits;\r
+  /** The zoom limits. */\r
+  private double[] mZoomLimits;\r
+  /** The X axis labels rotation angle. */\r
+  private float mXLabelsAngle;\r
+  /** The Y axis labels rotation angle. */\r
+  private float mYLabelsAngle;\r
+  /** The initial axis range. */\r
+  private Map<Integer, double[]> initialRange = new LinkedHashMap<Integer, double[]>();\r
+  /** The point size for charts displaying points. */\r
+  private float mPointSize = 3;\r
+  /** The grid color. */\r
+  private int mGridColor = Color.argb(75, 200, 200, 200);\r
+  /** The number of scales. */\r
+  private int scalesCount;\r
+  /** The X axis labels alignment. */\r
+  private Align xLabelsAlign = Align.CENTER;\r
+  /** The Y axis labels alignment. */\r
+  private Align[] yLabelsAlign;\r
+  /** The Y axis alignment. */\r
+  private Align[] yAxisAlign;\r
+  /** The X axis labels color. */\r
+  private int mXLabelsColor = TEXT_COLOR;\r
+  /** The Y axis labels color. */\r
+  private int[] mYLabelsColor = new int[] { TEXT_COLOR };\r
+  /**\r
+   * If X axis value selection algorithm to be used. Only used by the time\r
+   * charts.\r
+   */\r
+  private boolean mXRoundedLabels = true;\r
+\r
+  /**\r
+   * An enum for the XY chart orientation of the X axis.\r
+   */\r
+  public enum Orientation {\r
+    HORIZONTAL(0), VERTICAL(90);\r
+    /** The rotate angle. */\r
+    private int mAngle = 0;\r
+\r
+    private Orientation(int angle) {\r
+      mAngle = angle;\r
+    }\r
+\r
+    /**\r
+     * Return the orientation rotate angle.\r
+     * \r
+     * @return the orientaion rotate angle\r
+     */\r
+    public int getAngle() {\r
+      return mAngle;\r
+    }\r
+  }\r
+\r
+  public XYMultipleSeriesRenderer() {\r
+    this(1);\r
+  }\r
+\r
+  public XYMultipleSeriesRenderer(int scaleNumber) {\r
+    scalesCount = scaleNumber;\r
+    initAxesRange(scaleNumber);\r
+  }\r
+\r
+  public void initAxesRange(int scales) {\r
+    mYTitle = new String[scales];\r
+    yLabelsAlign = new Align[scales];\r
+    yAxisAlign = new Align[scales];\r
+    mYLabelsColor = new int[scales];\r
+    mMinX = new double[scales];\r
+    mMaxX = new double[scales];\r
+    mMinY = new double[scales];\r
+    mMaxY = new double[scales];\r
+    for (int i = 0; i < scales; i++) {\r
+      mYLabelsColor[i] = TEXT_COLOR;\r
+      initAxesRangeForScale(i);\r
+    }\r
+  }\r
+\r
+  public void initAxesRangeForScale(int i) {\r
+    mMinX[i] = MathHelper.NULL_VALUE;\r
+    mMaxX[i] = -MathHelper.NULL_VALUE;\r
+    mMinY[i] = MathHelper.NULL_VALUE;\r
+    mMaxY[i] = -MathHelper.NULL_VALUE;\r
+    double[] range = new double[] { mMinX[i], mMaxX[i], mMinY[i], mMaxY[i] };\r
+    initialRange.put(i, range);\r
+    mYTitle[i] = "";\r
+    mYTextLabels.put(i, new HashMap<Double, String>());\r
+    yLabelsAlign[i] = Align.CENTER;\r
+    yAxisAlign[i] = Align.LEFT;\r
+  }\r
+\r
+  /**\r
+   * Returns the current orientation of the chart X axis.\r
+   * \r
+   * @return the chart orientation\r
+   */\r
+  public Orientation getOrientation() {\r
+    return mOrientation;\r
+  }\r
+\r
+  /**\r
+   * Sets the current orientation of the chart X axis.\r
+   * \r
+   * @param orientation the chart orientation\r
+   */\r
+  public void setOrientation(Orientation orientation) {\r
+    mOrientation = orientation;\r
+  }\r
+\r
+  /**\r
+   * Returns the title for the X axis.\r
+   * \r
+   * @return the X axis title\r
+   */\r
+  public String getXTitle() {\r
+    return mXTitle;\r
+  }\r
+\r
+  /**\r
+   * Sets the title for the X axis.\r
+   * \r
+   * @param title the X axis title\r
+   */\r
+  public void setXTitle(String title) {\r
+    mXTitle = title;\r
+  }\r
+\r
+  /**\r
+   * Returns the title for the Y axis.\r
+   * \r
+   * @return the Y axis title\r
+   */\r
+  public String getYTitle() {\r
+    return getYTitle(0);\r
+  }\r
+\r
+  /**\r
+   * Returns the title for the Y axis.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the Y axis title\r
+   */\r
+  public String getYTitle(int scale) {\r
+    return mYTitle[scale];\r
+  }\r
+\r
+  /**\r
+   * Sets the title for the Y axis.\r
+   * \r
+   * @param title the Y axis title\r
+   */\r
+  public void setYTitle(String title) {\r
+    setYTitle(title, 0);\r
+  }\r
+\r
+  /**\r
+   * Sets the title for the Y axis.\r
+   * \r
+   * @param title the Y axis title\r
+   * @param scale the renderer scale\r
+   */\r
+  public void setYTitle(String title, int scale) {\r
+    mYTitle[scale] = title;\r
+  }\r
+\r
+  /**\r
+   * Returns the axis title text size.\r
+   * \r
+   * @return the axis title text size\r
+   */\r
+  public float getAxisTitleTextSize() {\r
+    return mAxisTitleTextSize;\r
+  }\r
+\r
+  /**\r
+   * Sets the axis title text size.\r
+   * \r
+   * @param textSize the chart axis text size\r
+   */\r
+  public void setAxisTitleTextSize(float textSize) {\r
+    mAxisTitleTextSize = textSize;\r
+  }\r
+\r
+  /**\r
+   * Returns the start value of the X axis range.\r
+   * \r
+   * @return the X axis range start value\r
+   */\r
+  public double getXAxisMin() {\r
+    return getXAxisMin(0);\r
+  }\r
+\r
+  /**\r
+   * Sets the start value of the X axis range.\r
+   * \r
+   * @param min the X axis range start value\r
+   */\r
+  public void setXAxisMin(double min) {\r
+    setXAxisMin(min, 0);\r
+  }\r
+\r
+  /**\r
+   * Returns if the minimum X value was set.\r
+   * \r
+   * @return the minX was set or not\r
+   */\r
+  public boolean isMinXSet() {\r
+    return isMinXSet(0);\r
+  }\r
+\r
+  /**\r
+   * Returns the end value of the X axis range.\r
+   * \r
+   * @return the X axis range end value\r
+   */\r
+  public double getXAxisMax() {\r
+    return getXAxisMax(0);\r
+  }\r
+\r
+  /**\r
+   * Sets the end value of the X axis range.\r
+   * \r
+   * @param max the X axis range end value\r
+   */\r
+  public void setXAxisMax(double max) {\r
+    setXAxisMax(max, 0);\r
+  }\r
+\r
+  /**\r
+   * Returns if the maximum X value was set.\r
+   * \r
+   * @return the maxX was set or not\r
+   */\r
+  public boolean isMaxXSet() {\r
+    return isMaxXSet(0);\r
+  }\r
+\r
+  /**\r
+   * Returns the start value of the Y axis range.\r
+   * \r
+   * @return the Y axis range end value\r
+   */\r
+  public double getYAxisMin() {\r
+    return getYAxisMin(0);\r
+  }\r
+\r
+  /**\r
+   * Sets the start value of the Y axis range.\r
+   * \r
+   * @param min the Y axis range start value\r
+   */\r
+  public void setYAxisMin(double min) {\r
+    setYAxisMin(min, 0);\r
+  }\r
+\r
+  /**\r
+   * Returns if the minimum Y value was set.\r
+   * \r
+   * @return the minY was set or not\r
+   */\r
+  public boolean isMinYSet() {\r
+    return isMinYSet(0);\r
+  }\r
+\r
+  /**\r
+   * Returns the end value of the Y axis range.\r
+   * \r
+   * @return the Y axis range end value\r
+   */\r
+  public double getYAxisMax() {\r
+    return getYAxisMax(0);\r
+  }\r
+\r
+  /**\r
+   * Sets the end value of the Y axis range.\r
+   * \r
+   * @param max the Y axis range end value\r
+   */\r
+  public void setYAxisMax(double max) {\r
+    setYAxisMax(max, 0);\r
+  }\r
+\r
+  /**\r
+   * Returns if the maximum Y value was set.\r
+   * \r
+   * @return the maxY was set or not\r
+   */\r
+  public boolean isMaxYSet() {\r
+    return isMaxYSet(0);\r
+  }\r
+\r
+  /**\r
+   * Returns the start value of the X axis range.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the X axis range start value\r
+   */\r
+  public double getXAxisMin(int scale) {\r
+    return mMinX[scale];\r
+  }\r
+\r
+  /**\r
+   * Sets the start value of the X axis range.\r
+   * \r
+   * @param min the X axis range start value\r
+   * @param scale the renderer scale\r
+   */\r
+  public void setXAxisMin(double min, int scale) {\r
+    if (!isMinXSet(scale)) {\r
+      initialRange.get(scale)[0] = min;\r
+    }\r
+    mMinX[scale] = min;\r
+  }\r
+\r
+  /**\r
+   * Returns if the minimum X value was set.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the minX was set or not\r
+   */\r
+  public boolean isMinXSet(int scale) {\r
+    return mMinX[scale] != MathHelper.NULL_VALUE;\r
+  }\r
+\r
+  /**\r
+   * Returns the end value of the X axis range.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the X axis range end value\r
+   */\r
+  public double getXAxisMax(int scale) {\r
+    return mMaxX[scale];\r
+  }\r
+\r
+  /**\r
+   * Sets the end value of the X axis range.\r
+   * \r
+   * @param max the X axis range end value\r
+   * @param scale the renderer scale\r
+   */\r
+  public void setXAxisMax(double max, int scale) {\r
+    if (!isMaxXSet(scale)) {\r
+      initialRange.get(scale)[1] = max;\r
+    }\r
+    mMaxX[scale] = max;\r
+  }\r
+\r
+  /**\r
+   * Returns if the maximum X value was set.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the maxX was set or not\r
+   */\r
+  public boolean isMaxXSet(int scale) {\r
+    return mMaxX[scale] != -MathHelper.NULL_VALUE;\r
+  }\r
+\r
+  /**\r
+   * Returns the start value of the Y axis range.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the Y axis range end value\r
+   */\r
+  public double getYAxisMin(int scale) {\r
+    return mMinY[scale];\r
+  }\r
+\r
+  /**\r
+   * Sets the start value of the Y axis range.\r
+   * \r
+   * @param min the Y axis range start value\r
+   * @param scale the renderer scale\r
+   */\r
+  public void setYAxisMin(double min, int scale) {\r
+    if (!isMinYSet(scale)) {\r
+      initialRange.get(scale)[2] = min;\r
+    }\r
+    mMinY[scale] = min;\r
+  }\r
+\r
+  /**\r
+   * Returns if the minimum Y value was set.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the minY was set or not\r
+   */\r
+  public boolean isMinYSet(int scale) {\r
+    return mMinY[scale] != MathHelper.NULL_VALUE;\r
+  }\r
+\r
+  /**\r
+   * Returns the end value of the Y axis range.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the Y axis range end value\r
+   */\r
+  public double getYAxisMax(int scale) {\r
+    return mMaxY[scale];\r
+  }\r
+\r
+  /**\r
+   * Sets the end value of the Y axis range.\r
+   * \r
+   * @param max the Y axis range end value\r
+   * @param scale the renderer scale\r
+   */\r
+  public void setYAxisMax(double max, int scale) {\r
+    if (!isMaxYSet(scale)) {\r
+      initialRange.get(scale)[3] = max;\r
+    }\r
+    mMaxY[scale] = max;\r
+  }\r
+\r
+  /**\r
+   * Returns if the maximum Y value was set.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the maxY was set or not\r
+   */\r
+  public boolean isMaxYSet(int scale) {\r
+    return mMaxY[scale] != -MathHelper.NULL_VALUE;\r
+  }\r
+\r
+  /**\r
+   * Returns the approximate number of labels for the X axis.\r
+   * \r
+   * @return the approximate number of labels for the X axis\r
+   */\r
+  public int getXLabels() {\r
+    return mXLabels;\r
+  }\r
+\r
+  /**\r
+   * Sets the approximate number of labels for the X axis.\r
+   * \r
+   * @param xLabels the approximate number of labels for the X axis\r
+   */\r
+  public void setXLabels(int xLabels) {\r
+    mXLabels = xLabels;\r
+  }\r
+\r
+  /**\r
+   * Adds a new text label for the specified X axis value.\r
+   * \r
+   * @param x the X axis value\r
+   * @param text the text label\r
+   * @deprecated use addXTextLabel instead\r
+   */\r
+  public void addTextLabel(double x, String text) {\r
+    addXTextLabel(x, text);\r
+  }\r
+\r
+  /**\r
+   * Adds a new text label for the specified X axis value.\r
+   * \r
+   * @param x the X axis value\r
+   * @param text the text label\r
+   */\r
+  public void addXTextLabel(double x, String text) {\r
+    mXTextLabels.put(x, text);\r
+  }\r
+\r
+  /**\r
+   * Returns the X axis text label at the specified X axis value.\r
+   * \r
+   * @param x the X axis value\r
+   * @return the X axis text label\r
+   */\r
+  public String getXTextLabel(Double x) {\r
+    return mXTextLabels.get(x);\r
+  }\r
+\r
+  /**\r
+   * Returns the X text label locations.\r
+   * \r
+   * @return the X text label locations\r
+   */\r
+  public Double[] getXTextLabelLocations() {\r
+    return mXTextLabels.keySet().toArray(new Double[0]);\r
+  }\r
+\r
+  /**\r
+   * Clears the existing text labels.\r
+   * \r
+   * @deprecated use clearXTextLabels instead\r
+   */\r
+  public void clearTextLabels() {\r
+    clearXTextLabels();\r
+  }\r
+\r
+  /**\r
+   * Clears the existing text labels on the X axis.\r
+   */\r
+  public void clearXTextLabels() {\r
+    mXTextLabels.clear();\r
+  }\r
+\r
+  /**\r
+   * If X axis labels should be rounded.\r
+   * \r
+   * @return if rounded time values to be used\r
+   */\r
+  public boolean isXRoundedLabels() {\r
+    return mXRoundedLabels;\r
+  }\r
+\r
+  /**\r
+   * Sets if X axis rounded time values to be used.\r
+   * \r
+   * @param rounded rounded values to be used\r
+   */\r
+  public void setXRoundedLabels(boolean rounded) {\r
+    mXRoundedLabels = rounded;\r
+  }\r
+\r
+  /**\r
+   * Adds a new text label for the specified Y axis value.\r
+   * \r
+   * @param y the Y axis value\r
+   * @param text the text label\r
+   */\r
+  public void addYTextLabel(double y, String text) {\r
+    addYTextLabel(y, text, 0);\r
+  }\r
+\r
+  /**\r
+   * Adds a new text label for the specified Y axis value.\r
+   * \r
+   * @param y the Y axis value\r
+   * @param text the text label\r
+   * @param scale the renderer scale\r
+   */\r
+  public void addYTextLabel(double y, String text, int scale) {\r
+    mYTextLabels.get(scale).put(y, text);\r
+  }\r
+\r
+  /**\r
+   * Returns the Y axis text label at the specified Y axis value.\r
+   * \r
+   * @param y the Y axis value\r
+   * @return the Y axis text label\r
+   */\r
+  public String getYTextLabel(Double y) {\r
+    return getYTextLabel(y, 0);\r
+  }\r
+\r
+  /**\r
+   * Returns the Y axis text label at the specified Y axis value.\r
+   * \r
+   * @param y the Y axis value\r
+   * @param scale the renderer scale\r
+   * @return the Y axis text label\r
+   */\r
+  public String getYTextLabel(Double y, int scale) {\r
+    return mYTextLabels.get(scale).get(y);\r
+  }\r
+\r
+  /**\r
+   * Returns the Y text label locations.\r
+   * \r
+   * @return the Y text label locations\r
+   */\r
+  public Double[] getYTextLabelLocations() {\r
+    return getYTextLabelLocations(0);\r
+  }\r
+\r
+  /**\r
+   * Returns the Y text label locations.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the Y text label locations\r
+   */\r
+  public Double[] getYTextLabelLocations(int scale) {\r
+    return mYTextLabels.get(scale).keySet().toArray(new Double[0]);\r
+  }\r
+\r
+  /**\r
+   * Clears the existing text labels on the Y axis.\r
+   */\r
+  public void clearYTextLabels() {\r
+    clearYTextLabels(0);\r
+  }\r
+\r
+  /**\r
+   * Clears the existing text labels on the Y axis.\r
+   * \r
+   * @param scale the renderer scale\r
+   */\r
+  public void clearYTextLabels(int scale) {\r
+    mYTextLabels.get(scale).clear();\r
+  }\r
+\r
+  /**\r
+   * Returns the approximate number of labels for the Y axis.\r
+   * \r
+   * @return the approximate number of labels for the Y axis\r
+   */\r
+  public int getYLabels() {\r
+    return mYLabels;\r
+  }\r
+\r
+  /**\r
+   * Sets the approximate number of labels for the Y axis.\r
+   * \r
+   * @param yLabels the approximate number of labels for the Y axis\r
+   */\r
+  public void setYLabels(int yLabels) {\r
+    mYLabels = yLabels;\r
+  }\r
+\r
+  /**\r
+   * Sets if the chart point values should be displayed as text.\r
+   * \r
+   * @param display if the chart point values should be displayed as text\r
+   * @deprecated use SimpleSeriesRenderer.setDisplayChartValues() instead\r
+   */\r
+  public void setDisplayChartValues(boolean display) {\r
+    SimpleSeriesRenderer[] renderers = getSeriesRenderers();\r
+    for (SimpleSeriesRenderer renderer : renderers) {\r
+      renderer.setDisplayChartValues(display);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Sets the chart values text size.\r
+   * \r
+   * @param textSize the chart values text size\r
+   * @deprecated use SimpleSeriesRenderer.setChartValuesTextSize() instead\r
+   */\r
+  public void setChartValuesTextSize(float textSize) {\r
+    SimpleSeriesRenderer[] renderers = getSeriesRenderers();\r
+    for (SimpleSeriesRenderer renderer : renderers) {\r
+      renderer.setChartValuesTextSize(textSize);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the pan on at least one axis.\r
+   * \r
+   * @return if pan is enabled\r
+   */\r
+  public boolean isPanEnabled() {\r
+    return isPanXEnabled() || isPanYEnabled();\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the pan on X axis.\r
+   * \r
+   * @return if pan is enabled on X axis\r
+   */\r
+  public boolean isPanXEnabled() {\r
+    return mPanXEnabled;\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the pan on Y axis.\r
+   * \r
+   * @return if pan is enabled on Y axis\r
+   */\r
+  public boolean isPanYEnabled() {\r
+    return mPanYEnabled;\r
+  }\r
+\r
+  /**\r
+   * Sets the enabled state of the pan.\r
+   * \r
+   * @param enabledX pan enabled on X axis\r
+   * @param enabledY pan enabled on Y axis\r
+   */\r
+  public void setPanEnabled(boolean enabledX, boolean enabledY) {\r
+    mPanXEnabled = enabledX;\r
+    mPanYEnabled = enabledY;\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the zoom on at least one axis.\r
+   * \r
+   * @return if zoom is enabled\r
+   */\r
+  public boolean isZoomEnabled() {\r
+    return isZoomXEnabled() || isZoomYEnabled();\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the zoom on X axis.\r
+   * \r
+   * @return if zoom is enabled on X axis\r
+   */\r
+  public boolean isZoomXEnabled() {\r
+    return mZoomXEnabled;\r
+  }\r
+\r
+  /**\r
+   * Returns the enabled state of the zoom on Y axis.\r
+   * \r
+   * @return if zoom is enabled on Y axis\r
+   */\r
+  public boolean isZoomYEnabled() {\r
+    return mZoomYEnabled;\r
+  }\r
+\r
+  /**\r
+   * Sets the enabled state of the zoom.\r
+   * \r
+   * @param enabledX zoom enabled on X axis\r
+   * @param enabledY zoom enabled on Y axis\r
+   */\r
+  public void setZoomEnabled(boolean enabledX, boolean enabledY) {\r
+    mZoomXEnabled = enabledX;\r
+    mZoomYEnabled = enabledY;\r
+  }\r
+\r
+  /**\r
+   * Returns the spacing between bars, in bar charts.\r
+   * \r
+   * @return the spacing between bars\r
+   * @deprecated use getBarSpacing instead\r
+   */\r
+  public double getBarsSpacing() {\r
+    return getBarSpacing();\r
+  }\r
+\r
+  /**\r
+   * Returns the spacing between bars, in bar charts.\r
+   * \r
+   * @return the spacing between bars\r
+   */\r
+  public double getBarSpacing() {\r
+    return mBarSpacing;\r
+  }\r
+\r
+  /**\r
+   * Sets the spacing between bars, in bar charts. Only available for bar\r
+   * charts. This is a coefficient of the bar width. For instance, if you want\r
+   * the spacing to be a half of the bar width, set this value to 0.5.\r
+   * \r
+   * @param spacing the spacing between bars coefficient\r
+   */\r
+  public void setBarSpacing(double spacing) {\r
+    mBarSpacing = spacing;\r
+  }\r
+\r
+  /**\r
+   * Returns the margins color.\r
+   * \r
+   * @return the margins color\r
+   */\r
+  public int getMarginsColor() {\r
+    return mMarginsColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the color of the margins.\r
+   * \r
+   * @param color the margins color\r
+   */\r
+  public void setMarginsColor(int color) {\r
+    mMarginsColor = color;\r
+  }\r
+\r
+  /**\r
+   * Returns the grid color.\r
+   * \r
+   * @return the grid color\r
+   */\r
+  public int getGridColor() {\r
+    return mGridColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the color of the grid.\r
+   * \r
+   * @param color the grid color\r
+   */\r
+  public void setGridColor(int color) {\r
+    mGridColor = color;\r
+  }\r
+\r
+  /**\r
+   * Returns the pan limits.\r
+   * \r
+   * @return the pan limits\r
+   */\r
+  public double[] getPanLimits() {\r
+    return mPanLimits;\r
+  }\r
+\r
+  /**\r
+   * Sets the pan limits as an array of 4 values. Setting it to null or a\r
+   * different size array will disable the panning limitation. Values:\r
+   * [panMinimumX, panMaximumX, panMinimumY, panMaximumY]\r
+   * \r
+   * @param panLimits the pan limits\r
+   */\r
+  public void setPanLimits(double[] panLimits) {\r
+    mPanLimits = panLimits;\r
+  }\r
+\r
+  /**\r
+   * Returns the zoom limits.\r
+   * \r
+   * @return the zoom limits\r
+   */\r
+  public double[] getZoomLimits() {\r
+    return mZoomLimits;\r
+  }\r
+\r
+  /**\r
+   * Sets the zoom limits as an array of 4 values. Setting it to null or a\r
+   * different size array will disable the zooming limitation. Values:\r
+   * [zoomMinimumX, zoomMaximumX, zoomMinimumY, zoomMaximumY]\r
+   * \r
+   * @param zoomLimits the zoom limits\r
+   */\r
+  public void setZoomLimits(double[] zoomLimits) {\r
+    mZoomLimits = zoomLimits;\r
+  }\r
+\r
+  /**\r
+   * Returns the rotation angle of labels for the X axis.\r
+   * \r
+   * @return the rotation angle of labels for the X axis\r
+   */\r
+  public float getXLabelsAngle() {\r
+    return mXLabelsAngle;\r
+  }\r
+\r
+  /**\r
+   * Sets the rotation angle (in degrees) of labels for the X axis.\r
+   * \r
+   * @param angle the rotation angle of labels for the X axis\r
+   */\r
+  public void setXLabelsAngle(float angle) {\r
+    mXLabelsAngle = angle;\r
+  }\r
+\r
+  /**\r
+   * Returns the rotation angle of labels for the Y axis.\r
+   * \r
+   * @return the approximate number of labels for the Y axis\r
+   */\r
+  public float getYLabelsAngle() {\r
+    return mYLabelsAngle;\r
+  }\r
+\r
+  /**\r
+   * Sets the rotation angle (in degrees) of labels for the Y axis.\r
+   * \r
+   * @param angle the rotation angle of labels for the Y axis\r
+   */\r
+  public void setYLabelsAngle(float angle) {\r
+    mYLabelsAngle = angle;\r
+  }\r
+\r
+  /**\r
+   * Returns the size of the points, for charts displaying points.\r
+   * \r
+   * @return the point size\r
+   */\r
+  public float getPointSize() {\r
+    return mPointSize;\r
+  }\r
+\r
+  /**\r
+   * Sets the size of the points, for charts displaying points.\r
+   * \r
+   * @param size the point size\r
+   */\r
+  public void setPointSize(float size) {\r
+    mPointSize = size;\r
+  }\r
+\r
+  public void setRange(double[] range) {\r
+    setRange(range, 0);\r
+  }\r
+\r
+  /**\r
+   * Sets the axes range values.\r
+   * \r
+   * @param range an array having the values in this order: minX, maxX, minY,\r
+   *          maxY\r
+   * @param scale the renderer scale\r
+   */\r
+  public void setRange(double[] range, int scale) {\r
+    setXAxisMin(range[0], scale);\r
+    setXAxisMax(range[1], scale);\r
+    setYAxisMin(range[2], scale);\r
+    setYAxisMax(range[3], scale);\r
+  }\r
+\r
+  public boolean isInitialRangeSet() {\r
+    return isInitialRangeSet(0);\r
+  }\r
+\r
+  /**\r
+   * Returns if the initial range is set.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the initial range was set or not\r
+   */\r
+  public boolean isInitialRangeSet(int scale) {\r
+    return initialRange.get(scale) != null;\r
+  }\r
+\r
+  /**\r
+   * Returns the initial range.\r
+   * \r
+   * @return the initial range\r
+   */\r
+  public double[] getInitialRange() {\r
+    return getInitialRange(0);\r
+  }\r
+\r
+  /**\r
+   * Returns the initial range.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return the initial range\r
+   */\r
+  public double[] getInitialRange(int scale) {\r
+    return initialRange.get(scale);\r
+  }\r
+\r
+  /**\r
+   * Sets the axes initial range values. This will be used in the zoom fit tool.\r
+   * \r
+   * @param range an array having the values in this order: minX, maxX, minY,\r
+   *          maxY\r
+   */\r
+  public void setInitialRange(double[] range) {\r
+    setInitialRange(range, 0);\r
+  }\r
+\r
+  /**\r
+   * Sets the axes initial range values. This will be used in the zoom fit tool.\r
+   * \r
+   * @param range an array having the values in this order: minX, maxX, minY,\r
+   *          maxY\r
+   * @param scale the renderer scale\r
+   */\r
+  public void setInitialRange(double[] range, int scale) {\r
+    initialRange.put(scale, range);\r
+  }\r
+\r
+  /**\r
+   * Returns the X axis labels color.\r
+   * \r
+   * @return the X axis labels color\r
+   */\r
+  public int getXLabelsColor() {\r
+    return mXLabelsColor;\r
+  }\r
+\r
+  /**\r
+   * Returns the Y axis labels color.\r
+   * \r
+   * @return the Y axis labels color\r
+   */\r
+  public int getYLabelsColor(int scale) {\r
+    return mYLabelsColor[scale];\r
+  }\r
+\r
+  /**\r
+   * Sets the X axis labels color.\r
+   * \r
+   * @param color the X axis labels color\r
+   */\r
+  public void setXLabelsColor(int color) {\r
+    mXLabelsColor = color;\r
+  }\r
+\r
+  /**\r
+   * Sets the Y axis labels color.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @param color the Y axis labels color\r
+   */\r
+  public void setYLabelsColor(int scale, int color) {\r
+    mYLabelsColor[scale] = color;\r
+  }\r
+\r
+  /**\r
+   * Returns the X axis labels alignment.\r
+   * \r
+   * @return X labels alignment\r
+   */\r
+  public Align getXLabelsAlign() {\r
+    return xLabelsAlign;\r
+  }\r
+\r
+  /**\r
+   * Sets the X axis labels alignment.\r
+   * \r
+   * @param align the X labels alignment\r
+   */\r
+  public void setXLabelsAlign(Align align) {\r
+    xLabelsAlign = align;\r
+  }\r
+\r
+  /**\r
+   * Returns the Y axis labels alignment.\r
+   * \r
+   * @param scale the renderer scale\r
+   * @return Y labels alignment\r
+   */\r
+  public Align getYLabelsAlign(int scale) {\r
+    return yLabelsAlign[scale];\r
+  }\r
+\r
+  public void setYLabelsAlign(Align align) {\r
+    setYLabelsAlign(align, 0);\r
+  }\r
+\r
+  public Align getYAxisAlign(int scale) {\r
+    return yAxisAlign[scale];\r
+  }\r
+\r
+  public void setYAxisAlign(Align align, int scale) {\r
+    yAxisAlign[scale] = align;\r
+  }\r
+\r
+  /**\r
+   * Sets the Y axis labels alignment.\r
+   * \r
+   * @param align the Y labels alignment\r
+   */\r
+  public void setYLabelsAlign(Align align, int scale) {\r
+    yLabelsAlign[scale] = align;\r
+  }\r
+\r
+  public int getScalesCount() {\r
+    return scalesCount;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/renderer/XYSeriesRenderer.java b/android-libraries/achartengine/src/org/achartengine/renderer/XYSeriesRenderer.java
new file mode 100644 (file)
index 0000000..42e4808
--- /dev/null
@@ -0,0 +1,128 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.renderer;\r
+\r
+import org.achartengine.chart.PointStyle;\r
+\r
+import android.graphics.Color;\r
+\r
+/**\r
+ * A renderer for the XY type series.\r
+ */\r
+public class XYSeriesRenderer extends SimpleSeriesRenderer {\r
+  /** If the chart points should be filled. */\r
+  private boolean mFillPoints = false;\r
+  /** If the chart should be filled below its line. */\r
+  private boolean mFillBelowLine = false;\r
+  /** The fill below the chart line color. */\r
+  private int mFillColor = Color.argb(125, 0, 0, 200);\r
+  /** The point style. */\r
+  private PointStyle mPointStyle = PointStyle.POINT;\r
+  /** The chart line width. */\r
+  private float mLineWidth = 1;\r
+\r
+  /**\r
+   * Returns if the chart should be filled below the line.\r
+   * \r
+   * @return the fill below line status\r
+   */\r
+  public boolean isFillBelowLine() {\r
+    return mFillBelowLine;\r
+  }\r
+\r
+  /**\r
+   * Sets if the line chart should be filled below its line. Filling below the\r
+   * line transforms a line chart into an area chart.\r
+   * \r
+   * @param fill the fill below line flag value\r
+   */\r
+  public void setFillBelowLine(boolean fill) {\r
+    mFillBelowLine = fill;\r
+  }\r
+\r
+  /**\r
+   * Returns if the chart points should be filled.\r
+   * \r
+   * @return the points fill status\r
+   */\r
+  public boolean isFillPoints() {\r
+    return mFillPoints;\r
+  }\r
+\r
+  /**\r
+   * Sets if the chart points should be filled.\r
+   * \r
+   * @param fill the points fill flag value\r
+   */\r
+  public void setFillPoints(boolean fill) {\r
+    mFillPoints = fill;\r
+  }\r
+\r
+  /**\r
+   * Returns the fill below line color.\r
+   * \r
+   * @return the fill below line color\r
+   */\r
+  public int getFillBelowLineColor() {\r
+    return mFillColor;\r
+  }\r
+\r
+  /**\r
+   * Sets the fill below the line color.\r
+   * \r
+   * @param color the fill below line color\r
+   */\r
+  public void setFillBelowLineColor(int color) {\r
+    mFillColor = color;\r
+  }\r
+\r
+  /**\r
+   * Returns the point style.\r
+   * \r
+   * @return the point style\r
+   */\r
+  public PointStyle getPointStyle() {\r
+    return mPointStyle;\r
+  }\r
+\r
+  /**\r
+   * Sets the point style.\r
+   * \r
+   * @param style the point style\r
+   */\r
+  public void setPointStyle(PointStyle style) {\r
+    mPointStyle = style;\r
+  }\r
+\r
+  /**\r
+   * Returns the chart line width.\r
+   * \r
+   * @return the line width\r
+   */\r
+  public float getLineWidth() {\r
+    return mLineWidth;\r
+  }\r
+\r
+  /**\r
+   * Sets the chart line width.\r
+   * \r
+   * @param lineWidth the line width\r
+   */\r
+  public void setLineWidth(float lineWidth) {\r
+    mLineWidth = lineWidth;\r
+  }\r
+  \r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/renderer/package.html b/android-libraries/achartengine/src/org/achartengine/renderer/package.html
new file mode 100644 (file)
index 0000000..c9db0a4
--- /dev/null
@@ -0,0 +1,6 @@
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+Provides renderer classes that keep the chart rendering / drawing styles.\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/tools/AbstractTool.java b/android-libraries/achartengine/src/org/achartengine/tools/AbstractTool.java
new file mode 100644 (file)
index 0000000..99841ed
--- /dev/null
@@ -0,0 +1,111 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.renderer.XYMultipleSeriesRenderer;\r
+\r
+/**\r
+ * Abstract class for being extended by graphical view tools.\r
+ */\r
+public abstract class AbstractTool {\r
+  /** The chart. */\r
+  protected AbstractChart mChart;\r
+  /** The renderer. */\r
+  protected XYMultipleSeriesRenderer mRenderer;\r
+\r
+  /**\r
+   * Abstract tool constructor.\r
+   * \r
+   * @param chart the chart\r
+   */\r
+  public AbstractTool(AbstractChart chart) {\r
+    mChart = chart;\r
+    if (chart instanceof XYChart) {\r
+      mRenderer = ((XYChart) chart).getRenderer();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Returns the current chart range.\r
+   * \r
+   * @param scale the scale\r
+   * @return the chart range\r
+   */\r
+  public double[] getRange(int scale) {\r
+    double minX = mRenderer.getXAxisMin(scale);\r
+    double maxX = mRenderer.getXAxisMax(scale);\r
+    double minY = mRenderer.getYAxisMin(scale);\r
+    double maxY = mRenderer.getYAxisMax(scale);\r
+    return new double[] { minX, maxX, minY, maxY };\r
+  }\r
+\r
+  /**\r
+   * Sets the range to the calculated one, if not already set.\r
+   * \r
+   * @param range the range\r
+   * @param scale the scale\r
+   */\r
+  public void checkRange(double[] range, int scale) {\r
+    if (mChart instanceof XYChart) {\r
+      double[] calcRange = ((XYChart) mChart).getCalcRange(scale);\r
+      if (calcRange != null) {\r
+        if (!mRenderer.isMinXSet(scale)) {\r
+          range[0] = calcRange[0];\r
+          mRenderer.setXAxisMin(range[0], scale);\r
+        }\r
+        if (!mRenderer.isMaxXSet(scale)) {\r
+          range[1] = calcRange[1];\r
+          mRenderer.setXAxisMax(range[1], scale);\r
+        }\r
+        if (!mRenderer.isMinYSet(scale)) {\r
+          range[2] = calcRange[2];\r
+          mRenderer.setYAxisMin(range[2], scale);\r
+        }\r
+        if (!mRenderer.isMaxYSet(scale)) {\r
+          range[3] = calcRange[3];\r
+          mRenderer.setYAxisMax(range[3], scale);\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Sets a new range on the X axis.\r
+   * \r
+   * @param min the minimum value\r
+   * @param max the maximum value\r
+   * @param scale the scale\r
+   */\r
+  protected void setXRange(double min, double max, int scale) {\r
+    mRenderer.setXAxisMin(min, scale);\r
+    mRenderer.setXAxisMax(max, scale);\r
+  }\r
+\r
+  /**\r
+   * Sets a new range on the Y axis.\r
+   * \r
+   * @param min the minimum value\r
+   * @param max the maximum value\r
+   * @param scale the scale\r
+   */\r
+  protected void setYRange(double min, double max, int scale) {\r
+    mRenderer.setYAxisMin(min, scale);\r
+    mRenderer.setYAxisMax(max, scale);\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/tools/FitZoom.java b/android-libraries/achartengine/src/org/achartengine/tools/FitZoom.java
new file mode 100644 (file)
index 0000000..92f67b8
--- /dev/null
@@ -0,0 +1,78 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.model.XYSeries;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+import org.achartengine.util.MathHelper;\r
+\r
+public class FitZoom extends AbstractTool {\r
+  /**\r
+   * Builds an instance of the fit zoom tool.\r
+   * \r
+   * @param chart the XY chart\r
+   */\r
+  public FitZoom(AbstractChart chart) {\r
+    super(chart);\r
+  }\r
+\r
+  /**\r
+   * Apply the tool.\r
+   */\r
+  public void apply() {\r
+    if (mChart instanceof XYChart) {\r
+      if (((XYChart) mChart).getDataset() == null) {\r
+        return;\r
+      }\r
+      int scales = mRenderer.getScalesCount();\r
+      if (mRenderer.isInitialRangeSet()) {\r
+        for (int i = 0; i < scales; i++) {\r
+          if (mRenderer.isInitialRangeSet(i)) {\r
+            mRenderer.setRange(mRenderer.getInitialRange(i), i);\r
+          }\r
+        }\r
+      } else {\r
+        XYSeries[] series = ((XYChart) mChart).getDataset().getSeries();\r
+        double[] range = null;\r
+        int length = series.length;\r
+        if (length > 0) {\r
+          for (int i = 0; i < scales; i++) {\r
+            range = new double[] { MathHelper.NULL_VALUE, -MathHelper.NULL_VALUE,\r
+                MathHelper.NULL_VALUE, -MathHelper.NULL_VALUE };\r
+            for (int j = 0; j < length; j++) {\r
+              if (i == series[j].getScaleNumber()) {\r
+                range[0] = Math.min(range[0], series[j].getMinX());\r
+                range[1] = Math.max(range[1], series[j].getMaxX());\r
+                range[2] = Math.min(range[2], series[j].getMinY());\r
+                range[3] = Math.max(range[3], series[j].getMaxY());\r
+              }\r
+            }\r
+            double marginX = Math.abs(range[1] - range[0]) / 40;\r
+            double marginY = Math.abs(range[3] - range[2]) / 40;\r
+            mRenderer.setRange(new double[] { range[0] - marginX, range[1] + marginX,\r
+                range[2] - marginY, range[3] + marginY }, i);\r
+          }\r
+        }\r
+      }\r
+    } else {\r
+      DefaultRenderer renderer = ((RoundChart) mChart).getRenderer();\r
+      renderer.setScale(renderer.getOriginalScale());\r
+    }\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/tools/Pan.java b/android-libraries/achartengine/src/org/achartengine/tools/Pan.java
new file mode 100644 (file)
index 0000000..2d4ea28
--- /dev/null
@@ -0,0 +1,163 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+\r
+/**\r
+ * The pan tool.\r
+ */\r
+public class Pan extends AbstractTool {\r
+  /** The pan listeners. */\r
+  private List<PanListener> mPanListeners = new ArrayList<PanListener>();\r
+  /** Pan limits reached on the X axis. */\r
+  private boolean limitsReachedX = false;\r
+  /** Pan limits reached on the X axis. */\r
+  private boolean limitsReachedY = false;\r
+\r
+  /**\r
+   * Builds and instance of the pan tool.\r
+   * \r
+   * @param chart the XY chart\r
+   */\r
+  public Pan(AbstractChart chart) {\r
+    super(chart);\r
+  }\r
+\r
+  /**\r
+   * Apply the tool.\r
+   * \r
+   * @param oldX the previous location on X axis\r
+   * @param oldY the previous location on Y axis\r
+   * @param newX the current location on X axis\r
+   * @param newY the current location on the Y axis\r
+   */\r
+  public void apply(float oldX, float oldY, float newX, float newY) {\r
+    boolean notLimitedUp = true;\r
+    boolean notLimitedBottom = true;\r
+    boolean notLimitedLeft = true;\r
+    boolean notLimitedRight = true;\r
+    if (mChart instanceof XYChart) {\r
+      int scales = mRenderer.getScalesCount();\r
+      double[] limits = mRenderer.getPanLimits();\r
+      boolean limited = limits != null && limits.length == 4;\r
+      XYChart chart = (XYChart) mChart;\r
+      for (int i = 0; i < scales; i++) {\r
+        double[] range = getRange(i);\r
+        double[] calcRange = chart.getCalcRange(i);\r
+        if (limitsReachedX\r
+            && limitsReachedY\r
+            && (range[0] == range[1] && calcRange[0] == calcRange[1] || range[2] == range[3]\r
+                && calcRange[2] == calcRange[3])) {\r
+          return;\r
+        }\r
+        checkRange(range, i);\r
+\r
+        double[] realPoint = chart.toRealPoint(oldX, oldY, i);\r
+        double[] realPoint2 = chart.toRealPoint(newX, newY, i);\r
+        double deltaX = realPoint[0] - realPoint2[0];\r
+        double deltaY = realPoint[1] - realPoint2[1];\r
+        double ratio = getAxisRatio(range);\r
+        if (chart.isVertical(mRenderer)) {\r
+          double newDeltaX = -deltaY * ratio;\r
+          double newDeltaY = deltaX / ratio;\r
+          deltaX = newDeltaX;\r
+          deltaY = newDeltaY;\r
+        }\r
+        if (mRenderer.isPanXEnabled()) {\r
+          if (limits != null) {\r
+            if (notLimitedLeft) {\r
+              notLimitedLeft = limits[0] <= range[0] + deltaX;\r
+            }\r
+            if (notLimitedRight) {\r
+              notLimitedRight = limits[1] >= range[1] + deltaX;\r
+            }\r
+          }\r
+          if (!limited || (notLimitedLeft && notLimitedRight)) {\r
+            setXRange(range[0] + deltaX, range[1] + deltaX, i);\r
+            limitsReachedX = false;\r
+          } else {\r
+            limitsReachedX = true;\r
+          }\r
+        }\r
+        if (mRenderer.isPanYEnabled()) {\r
+          if (limits != null) {\r
+            if (notLimitedBottom) {\r
+              notLimitedBottom = limits[2] <= range[2] + deltaY;\r
+            }\r
+            if (notLimitedUp) {\r
+              notLimitedUp = limits[3] >= range[3] + deltaY;\r
+            }\r
+          }\r
+          if (!limited || (notLimitedBottom && notLimitedUp)) {\r
+            setYRange(range[2] + deltaY, range[3] + deltaY, i);\r
+            limitsReachedY = false;\r
+          } else {\r
+            limitsReachedY = true;\r
+          }\r
+        }\r
+      }\r
+    } else {\r
+      RoundChart chart = (RoundChart) mChart;\r
+      chart.setCenterX(chart.getCenterX() + (int) (newX - oldX));\r
+      chart.setCenterY(chart.getCenterY() + (int) (newY - oldY));\r
+    }\r
+    notifyPanListeners();\r
+  }\r
+\r
+  /**\r
+   * Return the X / Y axis range ratio.\r
+   * \r
+   * @param range the axis range\r
+   * @return the ratio\r
+   */\r
+  private double getAxisRatio(double[] range) {\r
+    return Math.abs(range[1] - range[0]) / Math.abs(range[3] - range[2]);\r
+  }\r
+\r
+  /**\r
+   * Notify the pan listeners about a pan.\r
+   */\r
+  private synchronized void notifyPanListeners() {\r
+    for (PanListener listener : mPanListeners) {\r
+      listener.panApplied();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Adds a new pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  public synchronized void addPanListener(PanListener listener) {\r
+    mPanListeners.add(listener);\r
+  }\r
+\r
+  /**\r
+   * Removes a pan listener.\r
+   * \r
+   * @param listener pan listener\r
+   */\r
+  public synchronized void removePanListener(PanListener listener) {\r
+    mPanListeners.add(listener);\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/tools/PanListener.java b/android-libraries/achartengine/src/org/achartengine/tools/PanListener.java
new file mode 100644 (file)
index 0000000..d3d136c
--- /dev/null
@@ -0,0 +1,28 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+/**\r
+ * A pan listener.\r
+ */\r
+public interface PanListener {\r
+\r
+  /**\r
+   * Called when a pan change is triggered.\r
+   */\r
+  void panApplied();\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/tools/Zoom.java b/android-libraries/achartengine/src/org/achartengine/tools/Zoom.java
new file mode 100644 (file)
index 0000000..0abee92
--- /dev/null
@@ -0,0 +1,189 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.achartengine.chart.AbstractChart;\r
+import org.achartengine.chart.RoundChart;\r
+import org.achartengine.chart.XYChart;\r
+import org.achartengine.renderer.DefaultRenderer;\r
+\r
+/**\r
+ * The zoom tool.\r
+ */\r
+public class Zoom extends AbstractTool {\r
+  /** A flag to be used to know if this is a zoom in or out. */\r
+  private boolean mZoomIn;\r
+  /** The zoom rate. */\r
+  private float mZoomRate;\r
+  /** The zoom listeners. */\r
+  private List<ZoomListener> mZoomListeners = new ArrayList<ZoomListener>();\r
+  /** Zoom limits reached on the X axis. */\r
+  private boolean limitsReachedX = false;\r
+  /** Zoom limits reached on the Y axis. */\r
+  private boolean limitsReachedY = false;\r
+\r
+  /** Zoom on X axis and Y axis */\r
+  public static final int ZOOM_AXIS_XY = 0;\r
+  /** Zoom on X axis independently */\r
+  public static final int ZOOM_AXIS_X = 1;\r
+  /** Zoom on Y axis independently */\r
+  public static final int ZOOM_AXIS_Y = 2;\r
+\r
+\r
+  /**\r
+   * Builds the zoom tool.\r
+   * \r
+   * @param chart the chart\r
+   * @param in zoom in or out\r
+   * @param rate the zoom rate\r
+   */\r
+  public Zoom(AbstractChart chart, boolean in, float rate) {\r
+    super(chart);\r
+    mZoomIn = in;\r
+    setZoomRate(rate);\r
+  }\r
+\r
+  /**\r
+   * Sets the zoom rate.\r
+   * \r
+   * @param rate\r
+   */\r
+  public void setZoomRate(float rate) {\r
+    mZoomRate = rate;\r
+  }\r
+\r
+  /**\r
+   * Apply the zoom.\r
+   */\r
+  public void apply(int zoom_axis) {\r
+    if (mChart instanceof XYChart) {\r
+      int scales = mRenderer.getScalesCount();\r
+      for (int i = 0; i < scales; i++) {\r
+        double[] range = getRange(i);\r
+        checkRange(range, i);\r
+        double[] limits = mRenderer.getZoomLimits();\r
+\r
+        double centerX = (range[0] + range[1]) / 2;\r
+        double centerY = (range[2] + range[3]) / 2;\r
+        double newWidth = range[1] - range[0];\r
+        double newHeight = range[3] - range[2];\r
+        double newXMin = centerX - newWidth / 2;\r
+        double newXMax = centerX + newWidth / 2;\r
+        double newYMin = centerY - newHeight / 2;\r
+        double newYMax = centerY + newHeight / 2;\r
+\r
+        // if already reached last zoom, then it will always set to reached\r
+        if (i == 0) {\r
+          limitsReachedX = limits != null && (newXMin <= limits[0] || newXMax >= limits[1]);\r
+          limitsReachedY = limits != null && (newYMin <= limits[2] || newYMax >= limits[3]);\r
+        }\r
+\r
+        if (mZoomIn) {\r
+          if (mRenderer.isZoomXEnabled() &&     // zoom in on X axis\r
+              (zoom_axis == ZOOM_AXIS_X || zoom_axis == ZOOM_AXIS_XY)) {\r
+            if (limitsReachedX && mZoomRate < 1) {     \r
+              // ignore pinch zoom out once reached X limit\r
+            } else {\r
+              newWidth /= mZoomRate;\r
+            }\r
+          }\r
+\r
+          if (mRenderer.isZoomYEnabled() && // zoom in on Y axis\r
+              (zoom_axis == ZOOM_AXIS_Y || zoom_axis == ZOOM_AXIS_XY)) {\r
+            if (limitsReachedY && mZoomRate < 1) {\r
+            } else {\r
+              newHeight /= mZoomRate;\r
+            }\r
+          }\r
+        } else {\r
+          if (mRenderer.isZoomXEnabled() &&     !limitsReachedX &&         // zoom out on X axis\r
+              (zoom_axis == ZOOM_AXIS_X || zoom_axis == ZOOM_AXIS_XY)) {\r
+            newWidth *= mZoomRate;\r
+          }\r
+\r
+          if (mRenderer.isZoomYEnabled() &&     !limitsReachedY &&     // zoom out on Y axis\r
+              (zoom_axis == ZOOM_AXIS_Y || zoom_axis == ZOOM_AXIS_XY)) {\r
+            newHeight *= mZoomRate;\r
+          }\r
+        }\r
+\r
+        if (mRenderer.isZoomXEnabled() && \r
+            (zoom_axis == ZOOM_AXIS_X || zoom_axis == ZOOM_AXIS_XY)) {\r
+          newXMin = centerX - newWidth / 2;\r
+          newXMax = centerX + newWidth / 2;\r
+          setXRange(newXMin, newXMax, i);\r
+        }\r
+        if (mRenderer.isZoomYEnabled() &&\r
+            (zoom_axis == ZOOM_AXIS_Y || zoom_axis == ZOOM_AXIS_XY)) {\r
+          newYMin = centerY - newHeight / 2;\r
+          newYMax = centerY + newHeight / 2;\r
+          setYRange(newYMin, newYMax, i);\r
+        }\r
+      }\r
+    } else {\r
+      DefaultRenderer renderer = ((RoundChart) mChart).getRenderer();\r
+      if (mZoomIn) {\r
+        renderer.setScale(renderer.getScale() * mZoomRate);\r
+      } else {\r
+        renderer.setScale(renderer.getScale() / mZoomRate);\r
+      }\r
+    }\r
+    notifyZoomListeners(new ZoomEvent(mZoomIn, mZoomRate));\r
+  }\r
+\r
+\r
+  /**\r
+   * Notify the zoom listeners about a zoom change.\r
+   * \r
+   * @param e the zoom event\r
+   */\r
+  private synchronized void notifyZoomListeners(ZoomEvent e) {\r
+    for (ZoomListener listener : mZoomListeners) {\r
+      listener.zoomApplied(e);\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Notify the zoom listeners about a zoom reset.\r
+   */\r
+  public synchronized void notifyZoomResetListeners() {\r
+    for (ZoomListener listener : mZoomListeners) {\r
+      listener.zoomReset();\r
+    }\r
+  }\r
+\r
+  /**\r
+   * Adds a new zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  public synchronized void addZoomListener(ZoomListener listener) {\r
+    mZoomListeners.add(listener);\r
+  }\r
+\r
+  /**\r
+   * Removes a zoom listener.\r
+   * \r
+   * @param listener zoom listener\r
+   */\r
+  public synchronized void removeZoomListener(ZoomListener listener) {\r
+    mZoomListeners.add(listener);\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/tools/ZoomEvent.java b/android-libraries/achartengine/src/org/achartengine/tools/ZoomEvent.java
new file mode 100644 (file)
index 0000000..bd8fb68
--- /dev/null
@@ -0,0 +1,56 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+\r
+/**\r
+ * A zoom event.\r
+ */\r
+public class ZoomEvent {\r
+  /** A flag to be used to know if this is a zoom in or out. */\r
+  private boolean mZoomIn;\r
+  /** The zoom rate. */\r
+  private float mZoomRate;\r
+\r
+  /**\r
+   * Builds the zoom tool.\r
+   * \r
+   * @param in zoom in or out\r
+   * @param rate the zoom rate\r
+   */\r
+  public ZoomEvent(boolean in, float rate) {\r
+    mZoomIn = in;\r
+    mZoomRate = rate;\r
+  }\r
+\r
+  /**\r
+   * Returns the zoom type.\r
+   * \r
+   * @return true if zoom in, false otherwise\r
+   */\r
+  public boolean isZoomIn() {\r
+    return mZoomIn;\r
+  }\r
+  \r
+  /**\r
+   * Returns the zoom rate.\r
+   * \r
+   * @return the zoom rate\r
+   */\r
+  public float getZoomRate() {\r
+    return mZoomRate;\r
+  }\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/tools/ZoomListener.java b/android-libraries/achartengine/src/org/achartengine/tools/ZoomListener.java
new file mode 100644 (file)
index 0000000..4827483
--- /dev/null
@@ -0,0 +1,33 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.tools;\r
+\r
+/**\r
+ * A zoom listener.\r
+ */\r
+public interface ZoomListener {\r
+  \r
+  /**\r
+   * Called when a zoom change is triggered.\r
+   * @param e the zoom event\r
+   */\r
+  void zoomApplied(ZoomEvent e);\r
+  \r
+  /**\r
+   * Called when a zoom reset is done.\r
+   */\r
+  void zoomReset();\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/util/IndexXYMap.java b/android-libraries/achartengine/src/org/achartengine/util/IndexXYMap.java
new file mode 100644 (file)
index 0000000..f957262
--- /dev/null
@@ -0,0 +1,108 @@
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.TreeMap;
+
+/**
+ * This class requires sorted x values
+ */
+public class IndexXYMap<K, V> extends TreeMap<K, V> {
+  private final List<K> indexList = new ArrayList<K>();
+
+  private double maxXDifference = 0;
+
+  public IndexXYMap() {
+    super();
+  }
+
+  public V put(K key, V value) {
+    indexList.add(key);
+    updateMaxXDifference();
+    return super.put(key, value);
+  }
+
+  private void updateMaxXDifference() {
+    if (indexList.size() < 2) {
+      maxXDifference = 0;
+      return;
+    }
+
+    if (Math.abs((Double) indexList.get(indexList.size() - 1)
+        - (Double) indexList.get(indexList.size() - 2)) > maxXDifference)
+      maxXDifference = Math.abs((Double) indexList.get(indexList.size() - 1)
+          - (Double) indexList.get(indexList.size() - 2));
+  }
+
+  public double getMaxXDifference() {
+    return maxXDifference;
+  }
+
+  public void clear() {
+    updateMaxXDifference();
+    super.clear();
+    indexList.clear();
+  }
+
+  /**
+   * Returns X-value according to the given index
+   * 
+   * @param index
+   * @return the X value
+   */
+  public K getXByIndex(int index) {
+    return indexList.get(index);
+  }
+
+  /**
+   * Returns Y-value according to the given index
+   * 
+   * @param index
+   * @return the Y value
+   */
+  public V getYByIndex(int index) {
+    K key = indexList.get(index);
+    return this.get(key);
+  }
+
+  /**
+   * Returns XY-entry according to the given index
+   * 
+   * @param index
+   * @return the X and Y values
+   */
+  public XYEntry<K, V> getByIndex(int index) {
+    K key = indexList.get(index);
+    return new XYEntry<K, V>(key, this.get(key));
+  }
+
+  /**
+   * Removes entry from map by index
+   * 
+   * @param index
+   */
+  public XYEntry<K, V> removeByIndex(int index) {
+    K key = indexList.remove(index);
+    return new XYEntry<K, V>(key, this.remove(key));
+  }
+
+  public int getIndexForKey(K key) {
+    return Collections.binarySearch(indexList, key, null);
+  }
+}
diff --git a/android-libraries/achartengine/src/org/achartengine/util/MathHelper.java b/android-libraries/achartengine/src/org/achartengine/util/MathHelper.java
new file mode 100644 (file)
index 0000000..f5b893b
--- /dev/null
@@ -0,0 +1,174 @@
+/**\r
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
+ *  \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *  \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *  \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.achartengine.util;\r
+\r
+import java.text.NumberFormat;\r
+import java.text.ParseException;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+/**\r
+ * Utility class for math operations.\r
+ */\r
+public class MathHelper {\r
+  /** A value that is used a null value. */\r
+  public static final double NULL_VALUE = Double.MAX_VALUE;\r
+  /**\r
+   * A number formatter to be used to make sure we have a maximum number of\r
+   * fraction digits in the labels.\r
+   */\r
+  private static final NumberFormat FORMAT = NumberFormat.getNumberInstance();\r
+\r
+  private MathHelper() {\r
+    // empty constructor\r
+  }\r
+\r
+  /**\r
+   * Calculate the minimum and maximum values out of a list of doubles.\r
+   * \r
+   * @param values the input values\r
+   * @return an array with the minimum and maximum values\r
+   */\r
+  public static double[] minmax(List<Double> values) {\r
+    if (values.size() == 0) {\r
+      return new double[2];\r
+    }\r
+    double min = values.get(0);\r
+    double max = min;\r
+    int length = values.size();\r
+    for (int i = 1; i < length; i++) {\r
+      double value = values.get(i);\r
+      min = Math.min(min, value);\r
+      max = Math.max(max, value);\r
+    }\r
+    return new double[] { min, max };\r
+  }\r
+\r
+  /**\r
+   * Computes a reasonable set of labels for a data interval and number of\r
+   * labels.\r
+   * \r
+   * @param start start value\r
+   * @param end final value\r
+   * @param approxNumLabels desired number of labels\r
+   * @return collection containing {start value, end value, increment}\r
+   */\r
+  public static List<Double> getLabels(final double start, final double end,\r
+      final int approxNumLabels) {\r
+    FORMAT.setMaximumFractionDigits(5);\r
+    List<Double> labels = new ArrayList<Double>();\r
+    double[] labelParams = computeLabels(start, end, approxNumLabels);\r
+    // when the start > end the inc will be negative so it will still work\r
+    int numLabels = 1 + (int) ((labelParams[1] - labelParams[0]) / labelParams[2]);\r
+    // we want the range to be inclusive but we don't want to blow up when\r
+    // looping for the case where the min and max are the same. So we loop\r
+    // on\r
+    // numLabels not on the values.\r
+    for (int i = 0; i < numLabels; i++) {\r
+      double z = labelParams[0] + i * labelParams[2];\r
+      try {\r
+        // this way, we avoid a label value like 0.4000000000000000001 instead\r
+        // of 0.4\r
+        z = FORMAT.parse(FORMAT.format(z)).doubleValue();\r
+      } catch (ParseException e) {\r
+        // do nothing here\r
+      }\r
+      labels.add(z);\r
+    }\r
+    return labels;\r
+  }\r
+\r
+  /**\r
+   * Computes a reasonable number of labels for a data range.\r
+   * \r
+   * @param start start value\r
+   * @param end final value\r
+   * @param approxNumLabels desired number of labels\r
+   * @return double[] array containing {start value, end value, increment}\r
+   */\r
+  private static double[] computeLabels(final double start, final double end,\r
+      final int approxNumLabels) {\r
+    if (Math.abs(start - end) < 0.0000001f) {\r
+      return new double[] { start, start, 0 };\r
+    }\r
+    double s = start;\r
+    double e = end;\r
+    boolean switched = false;\r
+    if (s > e) {\r
+      switched = true;\r
+      double tmp = s;\r
+      s = e;\r
+      e = tmp;\r
+    }\r
+    double xStep = roundUp(Math.abs(s - e) / approxNumLabels);\r
+    // Compute x starting point so it is a multiple of xStep.\r
+    double xStart = xStep * Math.ceil(s / xStep);\r
+    double xEnd = xStep * Math.floor(e / xStep);\r
+    if (switched) {\r
+      return new double[] { xEnd, xStart, -1.0 * xStep };\r
+    }\r
+    return new double[] { xStart, xEnd, xStep };\r
+  }\r
+\r
+  /**\r
+   * Given a number, round up to the nearest power of ten times 1, 2, or 5. The\r
+   * argument must be strictly positive.\r
+   */\r
+  private static double roundUp(final double val) {\r
+    int exponent = (int) Math.floor(Math.log10(val));\r
+    double rval = val * Math.pow(10, -exponent);\r
+    if (rval > 5.0) {\r
+      rval = 10.0;\r
+    } else if (rval > 2.0) {\r
+      rval = 5.0;\r
+    } else if (rval > 1.0) {\r
+      rval = 2.0;\r
+    }\r
+    rval *= Math.pow(10, exponent);\r
+    return rval;\r
+  }\r
+\r
+  /**\r
+   * Transforms a list of Float values into an array of float.\r
+   * \r
+   * @param values the list of Float\r
+   * @return the array of floats\r
+   */\r
+  public static float[] getFloats(List<Float> values) {\r
+    int length = values.size();\r
+    float[] result = new float[length];\r
+    for (int i = 0; i < length; i++) {\r
+      result[i] = values.get(i).floatValue();\r
+    }\r
+    return result;\r
+  }\r
+\r
+  /**\r
+   * Transforms a list of Double values into an array of double.\r
+   * \r
+   * @param values the list of Double\r
+   * @return the array of doubles\r
+   */\r
+  public static double[] getDoubles(List<Double> values) {\r
+    int length = values.size();\r
+    double[] result = new double[length];\r
+    for (int i = 0; i < length; i++) {\r
+      result[i] = values.get(i).doubleValue();\r
+    }\r
+    return result;\r
+  }\r
+\r
+}\r
diff --git a/android-libraries/achartengine/src/org/achartengine/util/XYEntry.java b/android-libraries/achartengine/src/org/achartengine/util/XYEntry.java
new file mode 100644 (file)
index 0000000..53761a4
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL
+ *  
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.achartengine.util;
+
+import java.util.Map.Entry;
+
+/**
+ * A map entry value encapsulating an XY point.
+ */
+public class XYEntry<K, V> implements Entry<K, V> {
+  private final K key;
+  
+  private V value;
+
+  public XYEntry(K key, V value) {
+    this.key = key;
+    this.value = value;
+  }
+
+  public K getKey() {
+    return key;
+  }
+
+  public V getValue() {
+    return value;
+  }
+
+  public V setValue(V object) {
+    this.value = object;
+    return this.value;
+  }
+}
\ No newline at end of file
diff --git a/android-libraries/achartengine/src/org/achartengine/util/package.html b/android-libraries/achartengine/src/org/achartengine/util/package.html
new file mode 100644 (file)
index 0000000..da92e91
--- /dev/null
@@ -0,0 +1,6 @@
+<html>\r
+<title>AChartEngine</title>\r
+<body>\r
+Utility classes that provide helper methods used by most of the other packages.\r
+</body>\r
+</html>
\ No newline at end of file
index b1868ee863f77ba02db3ba402e35ab1a121a5915..07677d89fafe2264c948a7eb2b8a0167f98636d5 100644 (file)
@@ -2,11 +2,10 @@
 <classpath>\r
        <classpathentry kind="src" path="gen"/>\r
        <classpathentry excluding="**/.svn/**/*" including="l10n/**/*" kind="src" path="core-resources"/>\r
-       <classpathentry excluding="**/.svn/**/*|net/sf/openrocket/file/CSVExport.java|net/sf/openrocket/file/motor/MotorLoaderHelper.java|net/sf/openrocket/file/rocksim/export/|net/sf/openrocket/gui/|net/sf/openrocket/startup/Startup.java|net/sf/openrocket/startup/Startup2.java|net/sf/openrocket/startup/VersionHelper.java|net/sf/openrocket/utils/" kind="src" path="core"/>\r
+       <classpathentry excluding="**/.svn/**/*|net/sf/openrocket/file/CSVExport.java|net/sf/openrocket/file/motor/MotorLoaderHelper.java|net/sf/openrocket/file/rocksim/export/|net/sf/openrocket/gui/|net/sf/openrocket/plugin/|net/sf/openrocket/preset/loader/|net/sf/openrocket/preset/xml/|net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java|net/sf/openrocket/startup/ConcurrentLoadingThrustCurveMotorSetDatabase.java|net/sf/openrocket/startup/OSXStartup.java|net/sf/openrocket/startup/Startup.java|net/sf/openrocket/startup/Startup2.java|net/sf/openrocket/startup/VersionHelper.java|net/sf/openrocket/util/ExpressionParser.java|net/sf/openrocket/utils/" kind="src" path="core"/>\r
        <classpathentry kind="src" path="src"/>\r
        <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>\r
        <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>\r
        <classpathentry kind="lib" path="libs/android-support-v4.jar"/>\r
-       <classpathentry kind="lib" path="libs/achartengine-0.7.0.jar" sourcepath="/AChartEngine/src"/>\r
        <classpathentry kind="output" path="bin/classes"/>\r
 </classpath>\r
index 07a6582f8d1da28d3a819a6fd2ea9e08084a5a05..473dfeb2115077123f3dd144ea7505a9848dbff3 100644 (file)
@@ -5,7 +5,7 @@
     android:versionName="1.0" >\r
 \r
     <uses-sdk\r
-        android:minSdkVersion="9"\r
+        android:minSdkVersion="8"\r
         android:targetSdkVersion="15" />\r
 \r
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />\r
 \r
     <application\r
         android:name=".android.Application"\r
-        android:debuggable="false"\r
         android:icon="@drawable/or_launcher"\r
         android:killAfterRestore="true"\r
         android:label="@string/app_name"\r
         android:theme="@style/AppTheme" >\r
         <activity\r
             android:name=".android.Main"\r
-            android:theme="@style/AppTheme.Clean" >\r
+            android:theme="@style/AppTheme.NoActionBar" >\r
             <intent-filter>\r
                 <action android:name="android.intent.action.MAIN" />\r
 \r
                 <category android:name="android.intent.category.LAUNCHER" />\r
             </intent-filter>\r
-        </activity>\r
-        <activity\r
-            android:name=".android.rocket.OpenRocketLoaderActivity"\r
-            android:theme="@style/AppTheme.Clean" >\r
-\r
             <!--\r
                  I don't understand why I need to have two different intent filters. \r
                                Combining the <data> elements into a single field did not result in a working \r
                                application. The first intent-filter (with mimeType wildcard) convinces the \r
                                file browser to associate the correct launcher icon. the second intent-filter \r
-                               is actually invoked when a file is selected.\r\r\r
+                               is actually invoked when a file is selected.\r\r\r\r
             -->\r
             <!-- this intent filter convinces the file browser to display icons -->\r
             <intent-filter>\r
@@ -62,7 +56,9 @@
                     android:scheme="file" />\r
             </intent-filter>\r
         </activity>\r
-        <activity android:name=".android.rocket.OpenRocketViewer" />\r
+        <activity\r
+            android:name=".android.rocket.OpenRocketViewer"\r
+            android:windowSoftInputMode="adjustPan" />\r
         <activity android:name=".android.PreferencesActivity" >\r
             <intent-filter>\r
                 <action android:name="net.sf.openrocket.android.PreferencesActivity" />\r
         <activity android:name=".android.motor.MotorBrowserActivity" />\r
         <activity\r
             android:name=".android.motor.BurnPlotActivity"\r
-            android:theme="@style/AppTheme.NoTitleBar" />\r
-        <activity android:name=".android.thrustcurve.TCQueryActivity" />\r
+            android:theme="@style/AppTheme.NoActionBar" />\r
+        <activity\r
+            android:name=".android.thrustcurve.TCQueryActivity"\r
+            android:theme="@style/Theme.Sherlock.Dialog" />\r
         <activity\r
             android:name=".android.simulation.SimulationViewActivity"\r
-            android:theme="@style/AppTheme.NoTitleBar" />\r
-        <activity android:name=".android.filebrowser.SimpleFileBrowser" />\r
+            android:theme="@style/AppTheme.NoActionBar" />\r
+        <activity\r
+            android:name=".android.filebrowser.SimpleFileBrowser"\r
+            android:theme="@style/Theme.Sherlock.Dialog" />\r
+\r
+        <service android:name=".android.simservice.SimulationService" />\r
     </application>\r
 \r
 </manifest>
\ No newline at end of file
index 8da376af8d49472521c33bad1d544b8755a62c16..8202ea55fd7440524a64b2bef9ded1432344b6e0 100644 (file)
@@ -9,3 +9,6 @@
 
 # Project target.
 target=android-15
+android.library.reference.1=../ActionBarSherlock
+android.library.reference.2=../TreeViewList
+android.library.reference.3=../achartengine
diff --git a/android/res/drawable-hdpi/actionbar_shadow.9.png b/android/res/drawable-hdpi/actionbar_shadow.9.png
deleted file mode 100644 (file)
index 3c80a3f..0000000
Binary files a/android/res/drawable-hdpi/actionbar_shadow.9.png and /dev/null differ
diff --git a/android/res/drawable-hdpi/collapsed.png b/android/res/drawable-hdpi/collapsed.png
deleted file mode 100644 (file)
index c1e1f3d..0000000
Binary files a/android/res/drawable-hdpi/collapsed.png and /dev/null differ
diff --git a/android/res/drawable-hdpi/expanded.png b/android/res/drawable-hdpi/expanded.png
deleted file mode 100644 (file)
index cec254a..0000000
Binary files a/android/res/drawable-hdpi/expanded.png and /dev/null differ
diff --git a/android/res/drawable-hdpi/ic_menu_add.png b/android/res/drawable-hdpi/ic_menu_add.png
new file mode 100644 (file)
index 0000000..444e8a5
Binary files /dev/null and b/android/res/drawable-hdpi/ic_menu_add.png differ
diff --git a/android/res/drawable-hdpi/ic_menu_archive.png b/android/res/drawable-hdpi/ic_menu_archive.png
new file mode 100644 (file)
index 0000000..e2d9bc1
Binary files /dev/null and b/android/res/drawable-hdpi/ic_menu_archive.png differ
diff --git a/android/res/drawable-hdpi/ic_menu_info_details.png b/android/res/drawable-hdpi/ic_menu_info_details.png
new file mode 100644 (file)
index 0000000..6a7a1e9
Binary files /dev/null and b/android/res/drawable-hdpi/ic_menu_info_details.png differ
diff --git a/android/res/drawable-hdpi/ic_menu_preferences.png b/android/res/drawable-hdpi/ic_menu_preferences.png
new file mode 100644 (file)
index 0000000..5321f82
Binary files /dev/null and b/android/res/drawable-hdpi/ic_menu_preferences.png differ
diff --git a/android/res/drawable-hdpi/ic_menu_save.png b/android/res/drawable-hdpi/ic_menu_save.png
new file mode 100644 (file)
index 0000000..36fc7f4
Binary files /dev/null and b/android/res/drawable-hdpi/ic_menu_save.png differ
diff --git a/android/res/drawable-hdpi/ic_menu_search.png b/android/res/drawable-hdpi/ic_menu_search.png
new file mode 100644 (file)
index 0000000..a7f9bbe
Binary files /dev/null and b/android/res/drawable-hdpi/ic_menu_search.png differ
diff --git a/android/res/drawable-hdpi/or_launcher.png b/android/res/drawable-hdpi/or_launcher.png
new file mode 100644 (file)
index 0000000..22c526f
Binary files /dev/null and b/android/res/drawable-hdpi/or_launcher.png differ
diff --git a/android/res/drawable-ldpi/collapsed.png b/android/res/drawable-ldpi/collapsed.png
deleted file mode 100644 (file)
index a52e846..0000000
Binary files a/android/res/drawable-ldpi/collapsed.png and /dev/null differ
diff --git a/android/res/drawable-ldpi/expanded.png b/android/res/drawable-ldpi/expanded.png
deleted file mode 100644 (file)
index d8b7ab8..0000000
Binary files a/android/res/drawable-ldpi/expanded.png and /dev/null differ
diff --git a/android/res/drawable-ldpi/ic_menu_add.png b/android/res/drawable-ldpi/ic_menu_add.png
new file mode 100644 (file)
index 0000000..89620af
Binary files /dev/null and b/android/res/drawable-ldpi/ic_menu_add.png differ
diff --git a/android/res/drawable-ldpi/ic_menu_archive.png b/android/res/drawable-ldpi/ic_menu_archive.png
new file mode 100644 (file)
index 0000000..719ecd8
Binary files /dev/null and b/android/res/drawable-ldpi/ic_menu_archive.png differ
diff --git a/android/res/drawable-ldpi/ic_menu_info_details.png b/android/res/drawable-ldpi/ic_menu_info_details.png
new file mode 100644 (file)
index 0000000..55c57d5
Binary files /dev/null and b/android/res/drawable-ldpi/ic_menu_info_details.png differ
diff --git a/android/res/drawable-ldpi/ic_menu_preferences.png b/android/res/drawable-ldpi/ic_menu_preferences.png
new file mode 100644 (file)
index 0000000..efc2f3e
Binary files /dev/null and b/android/res/drawable-ldpi/ic_menu_preferences.png differ
diff --git a/android/res/drawable-ldpi/ic_menu_save.png b/android/res/drawable-ldpi/ic_menu_save.png
new file mode 100644 (file)
index 0000000..ac053b4
Binary files /dev/null and b/android/res/drawable-ldpi/ic_menu_save.png differ
diff --git a/android/res/drawable-ldpi/ic_menu_search.png b/android/res/drawable-ldpi/ic_menu_search.png
new file mode 100644 (file)
index 0000000..1d95408
Binary files /dev/null and b/android/res/drawable-ldpi/ic_menu_search.png differ
diff --git a/android/res/drawable-ldpi/or_launcher.png b/android/res/drawable-ldpi/or_launcher.png
new file mode 100644 (file)
index 0000000..5f7a0b2
Binary files /dev/null and b/android/res/drawable-ldpi/or_launcher.png differ
diff --git a/android/res/drawable-mdpi/actionbar_shadow.9.png b/android/res/drawable-mdpi/actionbar_shadow.9.png
deleted file mode 100644 (file)
index cae1778..0000000
Binary files a/android/res/drawable-mdpi/actionbar_shadow.9.png and /dev/null differ
diff --git a/android/res/drawable-mdpi/collapsed.png b/android/res/drawable-mdpi/collapsed.png
deleted file mode 100644 (file)
index b235551..0000000
Binary files a/android/res/drawable-mdpi/collapsed.png and /dev/null differ
diff --git a/android/res/drawable-mdpi/expanded.png b/android/res/drawable-mdpi/expanded.png
deleted file mode 100644 (file)
index f7377cb..0000000
Binary files a/android/res/drawable-mdpi/expanded.png and /dev/null differ
diff --git a/android/res/drawable-mdpi/ic_home_carat.png b/android/res/drawable-mdpi/ic_home_carat.png
deleted file mode 100644 (file)
index 22dad56..0000000
Binary files a/android/res/drawable-mdpi/ic_home_carat.png and /dev/null differ
diff --git a/android/res/drawable-mdpi/ic_menu_add.png b/android/res/drawable-mdpi/ic_menu_add.png
new file mode 100644 (file)
index 0000000..361c7c4
Binary files /dev/null and b/android/res/drawable-mdpi/ic_menu_add.png differ
diff --git a/android/res/drawable-mdpi/ic_menu_archive.png b/android/res/drawable-mdpi/ic_menu_archive.png
new file mode 100644 (file)
index 0000000..49ac569
Binary files /dev/null and b/android/res/drawable-mdpi/ic_menu_archive.png differ
diff --git a/android/res/drawable-mdpi/ic_menu_info_details.png b/android/res/drawable-mdpi/ic_menu_info_details.png
new file mode 100644 (file)
index 0000000..18b15b5
Binary files /dev/null and b/android/res/drawable-mdpi/ic_menu_info_details.png differ
diff --git a/android/res/drawable-mdpi/ic_menu_preferences.png b/android/res/drawable-mdpi/ic_menu_preferences.png
new file mode 100644 (file)
index 0000000..ccc50e6
Binary files /dev/null and b/android/res/drawable-mdpi/ic_menu_preferences.png differ
diff --git a/android/res/drawable-mdpi/ic_menu_save.png b/android/res/drawable-mdpi/ic_menu_save.png
new file mode 100644 (file)
index 0000000..5f66864
Binary files /dev/null and b/android/res/drawable-mdpi/ic_menu_save.png differ
diff --git a/android/res/drawable-mdpi/ic_menu_search.png b/android/res/drawable-mdpi/ic_menu_search.png
new file mode 100644 (file)
index 0000000..5d3155e
Binary files /dev/null and b/android/res/drawable-mdpi/ic_menu_search.png differ
index 849b6f1f6b5ed5b7fa2fa2404f32c88c206d6ebf..36a91549da9ef8ab264a645f5319272b46b749e2 100644 (file)
Binary files a/android/res/drawable-mdpi/or_launcher.png and b/android/res/drawable-mdpi/or_launcher.png differ
diff --git a/android/res/drawable-xhdpi/actionbar_shadow.9.png b/android/res/drawable-xhdpi/actionbar_shadow.9.png
deleted file mode 100644 (file)
index 30778e3..0000000
Binary files a/android/res/drawable-xhdpi/actionbar_shadow.9.png and /dev/null differ
diff --git a/android/res/drawable-xhdpi/ic_menu_add.png b/android/res/drawable-xhdpi/ic_menu_add.png
new file mode 100644 (file)
index 0000000..7d498a9
Binary files /dev/null and b/android/res/drawable-xhdpi/ic_menu_add.png differ
diff --git a/android/res/drawable-xhdpi/ic_menu_archive.png b/android/res/drawable-xhdpi/ic_menu_archive.png
new file mode 100644 (file)
index 0000000..b1be9d5
Binary files /dev/null and b/android/res/drawable-xhdpi/ic_menu_archive.png differ
diff --git a/android/res/drawable-xhdpi/ic_menu_info_details.png b/android/res/drawable-xhdpi/ic_menu_info_details.png
new file mode 100644 (file)
index 0000000..24ea543
Binary files /dev/null and b/android/res/drawable-xhdpi/ic_menu_info_details.png differ
diff --git a/android/res/drawable-xhdpi/ic_menu_preferences.png b/android/res/drawable-xhdpi/ic_menu_preferences.png
new file mode 100644 (file)
index 0000000..02cfbad
Binary files /dev/null and b/android/res/drawable-xhdpi/ic_menu_preferences.png differ
diff --git a/android/res/drawable-xhdpi/ic_menu_save.png b/android/res/drawable-xhdpi/ic_menu_save.png
new file mode 100644 (file)
index 0000000..62a66d8
Binary files /dev/null and b/android/res/drawable-xhdpi/ic_menu_save.png differ
diff --git a/android/res/drawable-xhdpi/ic_menu_search.png b/android/res/drawable-xhdpi/ic_menu_search.png
new file mode 100644 (file)
index 0000000..5c18f9e
Binary files /dev/null and b/android/res/drawable-xhdpi/ic_menu_search.png differ
index 77464db04175ee6d05494e6f20b67d6d588d3b9d..f13148d214873f711c408b17983f36997060ad51 100644 (file)
Binary files a/android/res/drawable-xhdpi/or_launcher.png and b/android/res/drawable-xhdpi/or_launcher.png differ
diff --git a/android/res/drawable/actionbar_compat_item.xml b/android/res/drawable/actionbar_compat_item.xml
deleted file mode 100644 (file)
index 4b3960c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/actionbar_compat_item_pressed"
-        android:state_pressed="true" />
-    <item android:drawable="@drawable/actionbar_compat_item_focused"
-        android:state_focused="true" />
-    <item android:drawable="@android:color/transparent" />
-</selector>
diff --git a/android/res/drawable/actionbar_compat_item_focused.xml b/android/res/drawable/actionbar_compat_item_focused.xml
deleted file mode 100644 (file)
index 04811d3..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="#ef7000" />
-</shape>
diff --git a/android/res/drawable/actionbar_compat_item_pressed.xml b/android/res/drawable/actionbar_compat_item_pressed.xml
deleted file mode 100644 (file)
index 72ff4b4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="#eda700" />
-</shape>
diff --git a/android/res/drawable/divider.xml b/android/res/drawable/divider.xml
deleted file mode 100644 (file)
index 5f37949..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
-  android:src="@android:drawable/divider_horizontal_dark"
-  android:layout_width="fill_parent" android:layout_height="wrap_content"
-  android:scaleType="fitXY" android:paddingLeft="5sp"
-  android:paddingRight="5sp" android:paddingBottom="2sp" />
diff --git a/android/res/drawable/home_item.xml b/android/res/drawable/home_item.xml
deleted file mode 100644 (file)
index 9afcd5a..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<bitmap  xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/or_launcher"/>
diff --git a/android/res/drawable/ic_menu_preferences.png b/android/res/drawable/ic_menu_preferences.png
deleted file mode 100644 (file)
index b8e7141..0000000
Binary files a/android/res/drawable/ic_menu_preferences.png and /dev/null differ
diff --git a/android/res/drawable/list_selector_background.xml b/android/res/drawable/list_selector_background.xml
deleted file mode 100644 (file)
index 2b21b0c..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project Licensed under the 
-       Apache License, Version 2.0 (the "License"); you may not use this file except 
-       in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
-       Unless required by applicable law or agreed to in writing, software distributed 
-       under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES 
-       OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
-       the specific language governing permissions and limitations under the License. -->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-       <item android:state_window_focused="false" android:drawable="@android:color/transparent" />
-
-       <!-- Even though these two point to the same resource, have two states so 
-               the drawable will invalidate itself when coming out of pressed state. -->
-       <item android:state_focused="true" android:state_enabled="false"
-               android:state_pressed="true" android:drawable="@drawable/list_selector_background_disabled" />
-       <item android:state_focused="true" android:state_enabled="false"
-               android:drawable="@drawable/list_selector_background_disabled" />
-
-       <item android:state_focused="true" android:state_pressed="true"
-               android:drawable="@drawable/list_selector_background_transition" />
-       <item android:state_focused="false" android:state_pressed="true"
-               android:drawable="@drawable/list_selector_background_transition" />
-
-       <item android:state_focused="true"
-               android:drawable="@drawable/list_selector_background_focus" />
-
-       <!-- !!hack!! to fill StateListDrawable.mStateListState with exactly 10 
-               items otherwise it will throw NPE on Android 1.6 -->
-
-       <item android:animationCache="true"
-               android:drawable="@android:color/transparent" />
-
-       <item android:animationCache="false"
-               android:drawable="@android:color/transparent" />
-
-       <item android:alwaysDrawnWithCache="false"
-               android:drawable="@android:color/transparent" />
-
-       <item android:alwaysDrawnWithCache="true"
-               android:drawable="@android:color/transparent" />
-       
-       
-</selector>
\ No newline at end of file
diff --git a/android/res/drawable/list_selector_background_disabled.9.png b/android/res/drawable/list_selector_background_disabled.9.png
deleted file mode 100644 (file)
index bf970b0..0000000
Binary files a/android/res/drawable/list_selector_background_disabled.9.png and /dev/null differ
diff --git a/android/res/drawable/list_selector_background_focus.9.png b/android/res/drawable/list_selector_background_focus.9.png
deleted file mode 100644 (file)
index c3e2415..0000000
Binary files a/android/res/drawable/list_selector_background_focus.9.png and /dev/null differ
diff --git a/android/res/drawable/list_selector_background_longpress.9.png b/android/res/drawable/list_selector_background_longpress.9.png
deleted file mode 100644 (file)
index 5cbb251..0000000
Binary files a/android/res/drawable/list_selector_background_longpress.9.png and /dev/null differ
diff --git a/android/res/drawable/list_selector_background_pressed.9.png b/android/res/drawable/list_selector_background_pressed.9.png
deleted file mode 100644 (file)
index 02b4e9a..0000000
Binary files a/android/res/drawable/list_selector_background_pressed.9.png and /dev/null differ
diff --git a/android/res/drawable/list_selector_background_transition.xml b/android/res/drawable/list_selector_background_transition.xml
deleted file mode 100644 (file)
index 0dec133..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-  
-          http://www.apache.org/licenses/LICENSE-2.0
-  
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<transition xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:drawable="@drawable/list_selector_background_pressed"  />
-    <item android:drawable="@drawable/list_selector_background_longpress"  />
-</transition>
diff --git a/android/res/drawable/simulation_state.xml b/android/res/drawable/simulation_state.xml
new file mode 100644 (file)
index 0000000..28e5923
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<selector xmlns:android="http://schemas.android.com/apk/res/android" \r
+    xmlns:openrocket="http://schemas.android.com/apk/res/net.sf.openrocket"\r
+    android:constantSize="true" android:dither="true" android:variablePadding="false">\r
+    <item android:drawable="@drawable/simulation_state_red" openrocket:simulation_invalid="true"/>\r
+    <item android:drawable="@drawable/simulation_state_yellow" openrocket:simulation_stale="true"/>\r
+    <item android:drawable="@drawable/simulation_state_green"/>\r
+</selector>
\ No newline at end of file
diff --git a/android/res/drawable/simulation_state_green.xml b/android/res/drawable/simulation_state_green.xml
new file mode 100644 (file)
index 0000000..4ccef18
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<shape xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:shape="oval" >\r
+\r
+    <corners android:radius="12dp"/>\r
+    <solid android:color="#CC00FF00"/>\r
+    <size android:width="24dp" android:height="24dp"/>\r
+    \r
+</shape>
\ No newline at end of file
diff --git a/android/res/drawable/simulation_state_red.xml b/android/res/drawable/simulation_state_red.xml
new file mode 100644 (file)
index 0000000..37c5b52
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<shape xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:shape="oval" >\r
+\r
+    <corners android:radius="12dp"/>\r
+    <solid android:color="#CCFF0000"/>\r
+    <size android:width="24dp" android:height="24dp"/>\r
+    \r
+</shape>
\ No newline at end of file
diff --git a/android/res/drawable/simulation_state_yellow.xml b/android/res/drawable/simulation_state_yellow.xml
new file mode 100644 (file)
index 0000000..1d25847
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<shape xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:shape="oval" >\r
+\r
+    <corners android:radius="12dp"/>\r
+    <solid android:color="#CCFFFF00"/>\r
+    <size android:width="24dp" android:height="24dp"/>\r
+    \r
+</shape>
\ No newline at end of file
diff --git a/android/res/layout-land/simulation_event_item.xml b/android/res/layout-land/simulation_event_item.xml
new file mode 100644 (file)
index 0000000..726be69
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<TableRow xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="wrap_content"\r
+    android:layout_height="match_parent" >\r
+\r
+    <TextView\r
+        android:id="@+id/eventName"\r
+        style="@style/labelTextStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="eventName" />\r
+\r
+    <TextView\r
+        android:id="@+id/eventTime"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:padding="5dp"\r
+        android:text="eventTime"\r
+        android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+    <TextView\r
+        android:id="@+id/eventVelocity"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:padding="5dp"\r
+        android:text="eventVelocity"\r
+        android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+    <TextView\r
+        android:id="@+id/eventAltitude"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:padding="5dp"\r
+        android:text="eventAltitude"\r
+        android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+</TableRow>
\ No newline at end of file
diff --git a/android/res/layout-large-land/motorbrowser.xml b/android/res/layout-large-land/motorbrowser.xml
new file mode 100644 (file)
index 0000000..25a2a83
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:baselineAligned="false"\r
+    android:orientation="horizontal" >\r
+\r
+    <FrameLayout\r
+        android:id="@+id/motorBrowserList"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="match_parent"\r
+        android:layout_weight="4" />\r
+\r
+    <FrameLayout\r
+        android:id="@+id/sidepane"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_weight="1" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/android/res/layout-large-land/openrocketviewer.xml b/android/res/layout-large-land/openrocketviewer.xml
new file mode 100644 (file)
index 0000000..6481624
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:orientation="horizontal" >\r
+\r
+    <android.support.v4.view.ViewPager\r
+        android:id="@+id/pager"\r
+        android:layout_weight="4"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="match_parent" >\r
+\r
+        <android.support.v4.view.PagerTitleStrip\r
+            android:layout_width="match_parent"\r
+            android:layout_height="match_parent"\r
+            android:layout_gravity="top" />\r
+    </android.support.v4.view.ViewPager>\r
+\r
+    <LinearLayout\r
+        android:id="@+id/sidepane"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_weight="1"\r
+        android:orientation="vertical" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/android/res/layout-v11/actionbar_indeterminate_progress.xml b/android/res/layout-v11/actionbar_indeterminate_progress.xml
deleted file mode 100644 (file)
index c05750e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:gravity="center">
-    <ProgressBar android:layout_width="32dp"
-        android:layout_height="32dp"
-        android:layout_marginLeft="12dp"
-        android:layout_marginRight="12dp"
-        android:layout_gravity="center"
-        style="?android:attr/indeterminateProgressStyle" />
-</FrameLayout>
diff --git a/android/res/layout-xlarge-land/motorbrowser.xml b/android/res/layout-xlarge-land/motorbrowser.xml
deleted file mode 100644 (file)
index 33c1237..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
-    android:layout_width="match_parent"\r
-    android:layout_height="match_parent"\r
-    android:orientation="horizontal" >\r
-\r
-    <FrameLayout\r
-        android:id="@+id/motorBrowserList"\r
-        android:layout_width="wrap_content"\r
-        android:layout_height="match_parent"\r
-        android:layout_weight="4"/>\r
-\r
-    <FrameLayout\r
-        android:id="@+id/sidepane"\r
-        android:layout_width="wrap_content"\r
-        android:layout_height="wrap_content"\r
-        android:layout_weight="1"/>\r
-\r
-</LinearLayout>
\ No newline at end of file
diff --git a/android/res/layout-xlarge-land/openrocketviewer.xml b/android/res/layout-xlarge-land/openrocketviewer.xml
deleted file mode 100644 (file)
index 6481624..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
-    android:layout_width="match_parent"\r
-    android:layout_height="match_parent"\r
-    android:orientation="horizontal" >\r
-\r
-    <android.support.v4.view.ViewPager\r
-        android:id="@+id/pager"\r
-        android:layout_weight="4"\r
-        android:layout_width="match_parent"\r
-        android:layout_height="match_parent" >\r
-\r
-        <android.support.v4.view.PagerTitleStrip\r
-            android:layout_width="match_parent"\r
-            android:layout_height="match_parent"\r
-            android:layout_gravity="top" />\r
-    </android.support.v4.view.ViewPager>\r
-\r
-    <LinearLayout\r
-        android:id="@+id/sidepane"\r
-        android:layout_width="wrap_content"\r
-        android:layout_height="wrap_content"\r
-        android:layout_weight="1"\r
-        android:orientation="vertical" />\r
-\r
-</LinearLayout>
\ No newline at end of file
diff --git a/android/res/layout/actionbar_compat.xml b/android/res/layout/actionbar_compat.xml
deleted file mode 100644 (file)
index 7e504d9..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@id/actionbar_compat"
-    android:background="#ff000000"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"
-    android:orientation="horizontal" />
index 6956b2d01f07cddf1721278bcce6c3bde5531282..7b12fc2d38181c7519714b2f57e8bcb24e6de420 100644 (file)
@@ -3,11 +3,11 @@
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     android:gravity="center_vertical"
-    padding="2dip" >
+    android:padding="2dip" >
 
     <TextView
         android:id="@android:id/text1"
-        android:layout_width="fill_parent"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:padding="4dip"
index 9e8de5e713f9bb57368f429f62936e321fab9cab..0cee268fc919fb587cf2e0192adf96970fd66c19 100644 (file)
@@ -11,7 +11,7 @@
 
     <TextView
         android:id="@+id/filebrowser_list_item_name"
-        android:layout_width="wrap_content"
+        android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_weight="1"
         android:gravity="center_vertical"
index aa7ef8740a67d38ff90d5d062b89cb67edcc2ce5..0ef5c289f8237ab6c1485a5e64e622a2e15b92bf 100644 (file)
@@ -11,6 +11,7 @@
         android:layout_height="wrap_content"\r
         android:layout_weight="1"\r
         android:gravity="center_horizontal"\r
+        android:paddingTop="22dp"\r
         android:src="@drawable/openrocket" />\r
 \r
     <TextView\r
         <Button\r
             android:id="@+id/main_open"\r
             android:layout_width="wrap_content"\r
-            android:layout_height="wrap_content"\r
+            android:layout_height="50dp"\r
+            android:layout_gravity="center"\r
             android:text="@string/openfilelabel" />\r
 \r
         <Button\r
             android:id="@+id/main_browse"\r
             android:layout_width="wrap_content"\r
-            android:layout_height="wrap_content"\r
+            android:layout_height="50dp"\r
+            android:layout_gravity="center"\r
             android:text="@string/viewmotorslabel" />\r
-    </LinearLayout>\r
 \r
-    <Button\r
-        android:id="@+id/main_donate"\r
-        android:layout_width="wrap_content"\r
-        android:layout_height="wrap_content"\r
-        android:layout_gravity="center"\r
-        android:background="@drawable/sf_donate" />\r
+        <Button\r
+            android:id="@+id/main_donate"\r
+            android:layout_width="wrap_content"\r
+            android:layout_height="wrap_content"\r
+            android:layout_gravity="center"\r
+            android:background="@drawable/sf_donate" />\r
+    </LinearLayout>\r
 \r
 </LinearLayout>
\ No newline at end of file
diff --git a/android/res/layout/motor_config_delay_dialog.xml b/android/res/layout/motor_config_delay_dialog.xml
new file mode 100644 (file)
index 0000000..8df8882
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:orientation="vertical" >
+\r
+    <EditText\r
+        android:id="@+id/motor_config_delay_diag_edit"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:singleLine="true"\r
+        android:ems="10"\r
+        android:imeOptions="actionDone"\r
+        android:inputType="phone"\r
+        android:digits="1234567890" >\r
+\r
+        <requestFocus />\r
+    </EditText>
+\r
+    <ListView\r
+        android:id="@+id/motor_config_delay_diag_list"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content" >\r
+    </ListView>\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/android/res/layout/motor_config_item.xml b/android/res/layout/motor_config_item.xml
new file mode 100644 (file)
index 0000000..46b07a2
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:focusable="false" >\r
+\r
+    <TextView\r
+        android:id="@+id/motor_config_motor_mount_name"\r
+        style="@style/labelTextStyle"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:focusable="false"\r
+        android:text="Stage" />\r
+\r\r
+    <Button\r
+        android:id="@+id/motor_config_motor_desc"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_below="@id/motor_config_motor_mount_name"\r
+        android:layout_margin="0dp"\r
+        android:layout_toLeftOf="@+id/motor_config_motor_dash"\r
+        android:text="@string/select_motor"\r
+        android:textAppearance="@style/valueTextStyle" />\r
+\r
+    <TextView\r
+        android:id="@+id/motor_config_motor_dash"\r
+        style="@style/valueTextStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_alignBaseline="@id/motor_config_motor_desc"\r
+        android:layout_below="@id/motor_config_motor_mount_name"\r
+        android:layout_toLeftOf="@+id/motor_config_motor_delay"\r
+        android:gravity="right"\r
+        android:text="-" />\r
+\r\r
+    <Button\r
+        android:id="@+id/motor_config_motor_delay"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:layout_alignBaseline="@id/motor_config_motor_desc"\r
+        android:layout_alignParentRight="true"\r
+        android:layout_below="@id/motor_config_motor_mount_name"\r
+        android:text="@string/select_delay"\r
+        android:textAppearance="@style/valueTextStyle" />\r
+\r
+</RelativeLayout>
\ No newline at end of file
diff --git a/android/res/layout/motor_list_dialog.xml b/android/res/layout/motor_list_dialog.xml
new file mode 100644 (file)
index 0000000..ff18b98
--- /dev/null
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:orientation="vertical" >\r
+\r
+    <fragment\r
+        android:id="@+id/motor_list"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="match_parent"\r
+        class="net.sf.openrocket.motor.MotorListFragment" />\r
+\r
+</LinearLayout>
\ No newline at end of file
diff --git a/android/res/layout/rocket_configurations.xml b/android/res/layout/rocket_configurations.xml
new file mode 100644 (file)
index 0000000..001c520
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:orientation="vertical" >\r
+\r
+    <!--\r
+        Note because my implementation of ExpandableListFragment is stupid, the id\r
+        of the ExpandableListView must be @android:id/list\r
+    -->\r
+\r
+    <ExpandableListView\r
+        android:id="@android:id/list"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content" />\r
+\r
+</LinearLayout>
\ No newline at end of file
index 4ebc0b08db5be254c9dfe9bdb76f2c9b3f8c2c69..6a881a49d511cbfe2244218e0331155993f2fd4b 100644 (file)
@@ -61,7 +61,7 @@
             android:layout_height="wrap_content"\r
             android:text="" />\r
 \r
-        <Spinner\r
+        <net.sf.openrocket.android.rocket.MotorConfigSpinner\r
             android:id="@+id/openrocketviewerConfigurationSpinner"\r
             android:layout_width="match_parent"\r
             android:layout_height="wrap_content"\r
diff --git a/android/res/layout/simple_spinner_item.xml b/android/res/layout/simple_spinner_item.xml
deleted file mode 100644 (file)
index 12ff153..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-    style="@style/spinnerStyle"
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android" 
-    style="@style/spinnerStyle"
-    android:id="@android:id/text1"
-    android:singleLine="true"
-    android:layout_width="match_parent"
-    android:ellipsize="marquee" />
diff --git a/android/res/layout/simulation_condition_dialog.xml b/android/res/layout/simulation_condition_dialog.xml
new file mode 100644 (file)
index 0000000..2edd052
--- /dev/null
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="match_parent"\r
+    android:layout_height="match_parent"\r
+    android:descendantFocusability="beforeDescendants"\r
+    android:focusableInTouchMode="true"\r
+    android:minWidth="250dp"\r
+    android:orientation="vertical" >\r
+\r
+    <TextView\r
+        style="@style/labelTextStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="@string/simulationConditionWind" />\r
+\r
+    <EditText\r
+        android:id="@+id/simulation_condition_windspeed"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:ems="10"\r
+        android:gravity="right"\r
+        android:inputType="number"\r
+        android:text="0" >\r
+\r
+        <requestFocus />\r
+    </EditText>\r
+\r
+    <TextView\r
+        style="@style/labelTextStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="@string/simulationConditionsRodLength" />\r
+\r
+    <EditText\r
+        android:id="@+id/simulation_condition_rodlength"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:ems="10"\r
+        android:gravity="right"\r
+        android:inputType="number"\r
+        android:text="0" />\r
+\r
+    <TextView\r
+        style="@style/labelTextStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="@string/simulationConditionsLaunchRodAngle" />\r
+\r
+    <EditText\r
+        android:id="@+id/simulation_condition_rodangle"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:ems="10"\r
+        android:gravity="right"\r
+        android:inputType="number"\r
+        android:text="0" />\r
+\r
+    <TextView\r
+        style="@style/labelTextStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="@string/simulationConditionsLaunchRodDirection" />\r
+\r
+    <EditText\r
+        android:id="@+id/simulation_condition_roddirection"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:ems="10"\r
+        android:gravity="right"\r
+        android:inputType="number"\r
+        android:text="0" />\r
+\r
+    <net.sf.openrocket.android.rocket.MotorConfigSpinner\r
+        android:id="@+id/simulationConditionConfigurationSpinner"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:prompt="@string/simulationConditionSelectMotors" />\r
+\r
+    <Button\r
+        android:id="@+id/simulationConditionDelete"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:text="@string/Delete" />\r
+\r
+    <Button\r
+        android:id="@+id/simulationConditionRun"\r
+        android:layout_width="match_parent"\r
+        android:layout_height="wrap_content"\r
+        android:text="@string/Run" />\r
+\r
+</LinearLayout>
\ No newline at end of file
index 1fc4426f52cc92ffacc5d0eb7d056ed6151a8a75..d92b42f76ccfe5ca15c9b7481ec1c847078fedaf 100644 (file)
@@ -1,12 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical" >
-
-    <ListView
+    android:layout_height="match_parent">
+    
+    <TableLayout
         android:id="@+id/simulationEventsList"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent" />
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" >
+    </TableLayout>
+
 
-</LinearLayout>
\ No newline at end of file
+</ScrollView>
diff --git a/android/res/layout/simulation_event_item.xml b/android/res/layout/simulation_event_item.xml
new file mode 100644 (file)
index 0000000..e50a2c2
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<TableRow xmlns:android="http://schemas.android.com/apk/res/android"\r
+    android:layout_width="wrap_content"\r
+    android:layout_height="match_parent" >\r
+\r
+    <TextView\r
+        android:id="@+id/eventName"\r
+        style="@style/labelTextStyle"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="eventName" />\r
+\r
+    <LinearLayout\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:orientation="vertical">\r
+        \r
+    <TextView\r
+        android:id="@+id/eventTime"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="eventTime"\r
+        android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+    <TextView\r
+        android:id="@+id/eventVelocity"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="eventVelocity"\r
+        android:textAppearance="?android:attr/textAppearanceSmall" />\r
+\r
+    <TextView\r
+        android:id="@+id/eventAltitude"\r
+        android:layout_width="wrap_content"\r
+        android:layout_height="wrap_content"\r
+        android:text="eventAltitude"\r
+        android:textAppearance="?android:attr/textAppearanceSmall" />\r
+    </LinearLayout>\r
+    \r
+</TableRow>
\ No newline at end of file
diff --git a/android/res/layout/simulation_list_item.xml b/android/res/layout/simulation_list_item.xml
new file mode 100644 (file)
index 0000000..4d34918
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android" >
+
+    <ImageView
+        android:id="@+id/simulation_status"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:src="@drawable/simulation_state"
+        android:duplicateParentState="true"
+        android:paddingRight="5dp" />
+
+    <TwoLineListItem
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="10px" >
+
+        <TextView
+            android:id="@android:id/text1"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="TextView"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <TextView
+            android:id="@android:id/text2"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingTop="30px"
+            android:text="TextView"
+            android:textAppearance="?android:attr/textAppearanceSmall" />
+    </TwoLineListItem>
+
+</merge>
\ No newline at end of file
diff --git a/android/res/layout/simulation_plot_config_dialog.xml b/android/res/layout/simulation_plot_config_dialog.xml
new file mode 100644 (file)
index 0000000..d3af901
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/simulationSeries1Label" />
+
+    <Spinner
+        android:id="@+id/simulationSeries1"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:drawSelectorOnTop="true" />
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/simulationSeries2Label" />
+
+    <Spinner
+        android:id="@+id/simulationSeries2"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:drawSelectorOnTop="true" />
+
+    <ListView
+        android:id="@+id/simulationEventsList"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <Button
+        android:id="@+id/simulationOkButton"
+        android:layout_width="70dp"
+        android:layout_height="45dp"
+        android:layout_gravity="center_horizontal"
+        android:text="@string/plot" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/android/res/layout/simulation_plot_config_event_list_item.xml b/android/res/layout/simulation_plot_config_event_list_item.xml
new file mode 100644 (file)
index 0000000..19eb9f2
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:textAppearance="?android:attr/textAppearanceListItem"
+    android:gravity="center_vertical"
+    android:checkMark="?android:attr/listChoiceIndicatorMultiple"
+    android:paddingLeft="8dip"
+    android:paddingRight="8dip"
+/>
diff --git a/android/res/layout/simulation_series_dialog.xml b/android/res/layout/simulation_series_dialog.xml
deleted file mode 100644 (file)
index 0b28cfd..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical" >
-
-    <!--  shim to get dialog correct size ?? -->
-    <View
-        android:layout_width="200dp"
-        android:layout_height="0px"
-        android:layout_margin="0px"
-        android:orientation="horizontal" />
-
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="@string/simulationSeries1Label" />
-
-    <Spinner
-        android:id="@+id/simulationSeries1"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:drawSelectorOnTop="true" />
-
-    <TextView
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:text="@string/simulationSeries2Label" />
-
-    <Spinner
-        android:id="@+id/simulationSeries2"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:drawSelectorOnTop="true" />
-
-    <Button
-        android:id="@+id/simulationOkButton"
-        android:layout_width="70dp"
-        android:layout_height="70dp"
-        android:layout_gravity="center_horizontal"
-        android:text="ok" />
-
-</LinearLayout>
\ No newline at end of file
index 4295e879babf1e6af52e490ca5ed19971927e4db..d739334aebaeef3de3a20c6ba63bb0ef0885d8e0 100644 (file)
@@ -2,73 +2,64 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:descendantFocusability="beforeDescendants"
+    android:focusableInTouchMode="true"
+    android:minWidth="250dp"
     android:orientation="vertical" >
 
-    <!-- this is just here so the edittext doesn't get focus -->
-
-    <LinearLayout
-        android:layout_width="0px"
-        android:layout_height="0px"
-        android:focusable="true"
-        android:focusableInTouchMode="true" />
-
-    <TableLayout
-        android:id="@+id/tableLayout1"
-        android:layout_width="fill_parent"
+    <TextView
+        android:id="@+id/textView1"
+        style="@style/labelTextStyle"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:stretchColumns="1" >
-
-        <TableRow>
-
-            <TextView
-                android:id="@+id/textView1"
-                android:text="@string/motor_manufacturer" />
+        android:text="@string/motor_manufacturer" />
 
-            <Spinner
-                android:id="@+id/TCMotorSearchFormManufacturerField"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:entries="@array/TCMotorSearchManufacturerList" />
-        </TableRow>
-
-        <TableRow>
-
-            <TextView
-                android:text="@string/motor_impulseclass" />
-
-            <Spinner
-                android:id="@+id/TCMotorSearchFormImpulseField"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:entries="@array/TCMotorSearchImpulseList" />
-        </TableRow>
+    <Spinner
+        android:id="@+id/TCMotorSearchFormManufacturerField"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:entries="@array/TCMotorSearchManufacturerList" />
 
-        <TableRow>
+    <TextView
+        style="@style/labelTextStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/motor_impulseclass" />
 
-            <TextView
-                android:text="@string/motor_commonname" />
+    <Spinner
+        android:id="@+id/TCMotorSearchFormImpulseField"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:entries="@array/TCMotorSearchImpulseList" />
 
-            <EditText
-                android:id="@+id/TCMotorSearchFormCommonNameField"
-                android:text="" />
-        </TableRow>
+    <TextView
+        style="@style/labelTextStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/motor_commonname" />
 
-        <TableRow>
+    <EditText
+        android:id="@+id/TCMotorSearchFormCommonNameField"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:inputType="text"
+        android:text="" />
 
-            <TextView
-                android:text="@string/motor_diameter" />
+    <TextView
+        style="@style/labelTextStyle"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/motor_diameter" />
 
-            <Spinner
-                android:id="@+id/TCMotorSearchFormDiameterField"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:entries="@array/TCMotorSearchDiameterList" />
-        </TableRow>
-    </TableLayout>
+    <Spinner
+        android:id="@+id/TCMotorSearchFormDiameterField"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:entries="@array/TCMotorSearchDiameterList" />
 
     <Button
         android:id="@+id/TCMotorSearchFromSubmitButton"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_gravity="center_horizontal"
         android:text="@string/TCMotorSearchFormSubmit" />
diff --git a/android/res/layout/tree_list_item_wrapper.xml b/android/res/layout/tree_list_item_wrapper.xml
deleted file mode 100644 (file)
index ba93f47..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent" >
-
-    <LinearLayout
-        android:id="@+id/treeview_list_item_image_layout"
-        android:layout_width="80dip"
-        android:layout_height="fill_parent"
-        android:gravity="right|center_vertical" >
-
-        <ImageView
-            android:id="@+id/treeview_list_item_image"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:src="@drawable/collapsed" >
-        </ImageView>
-    </LinearLayout>
-
-    <FrameLayout
-        android:id="@+id/treeview_list_item_frame"
-        android:layout_width="fill_parent"
-        android:layout_height="fill_parent"
-        android:layout_weight="1" >
-    </FrameLayout>
-
-</LinearLayout>
\ No newline at end of file
index 07b8f1ad20c2da247e8c9684ae7e7cd07371f99a..51fc89f9e9c606cfb270b8463074f3e5df21c560 100644 (file)
@@ -10,6 +10,7 @@
     <item\r
         android:id="@+id/menu_about"\r
         android:title="@string/About"\r
+        android:icon="@drawable/ic_menu_info_details"\r
         android:showAsAction="never"/>\r
 \r
 </menu>
\ No newline at end of file
index 23ad3760ce8615acaf9fa6923348764e1cfafb8b..caded38b6baddefdbde5024252e95588a4fc2bf6 100644 (file)
@@ -3,13 +3,16 @@
 
     <item
         android:id="@+id/download_from_thrustcurve_menu_option"
-        android:title="@string/Download"/>
+        android:title="@string/Download"
+        android:icon="@drawable/ic_menu_search"
+        android:showAsAction="always"/>
     <item
         android:id="@+id/preference_menu_option"
         android:icon="@drawable/ic_menu_preferences"
         android:title="@string/Preferences"/>
     <item
         android:id="@+id/menu_about"
+        android:icon="@drawable/ic_menu_info_details"
         android:showAsAction="never"
         android:title="@string/About"/>
 
diff --git a/android/res/menu/rocket_viewer_configurations_option_menu.xml b/android/res/menu/rocket_viewer_configurations_option_menu.xml
new file mode 100644 (file)
index 0000000..0464e59
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >\r
+\r
+    <item\r
+        android:id="@+id/menu_add"\r
+        android:icon="@drawable/ic_menu_add"\r
+        android:orderInCategory="2"\r
+        android:showAsAction="always"\r
+        android:title="@string/Add"/>\r
+\r
+</menu>
\ No newline at end of file
index cc80d992a199d6cba252ae2d2c1d3fbfb4f780f9..eaf7bc22a260a7d4d1aba19ae9feff27a8ee1262 100644 (file)
@@ -1,17 +1,33 @@
 <?xml version="1.0" encoding="utf-8"?>\r
 <menu xmlns:android="http://schemas.android.com/apk/res/android" >\r
 \r
+    <item\r
+        android:id="@+id/menu_load"\r
+        android:icon="@drawable/ic_menu_archive"\r
+        android:orderInCategory="1"\r
+        android:showAsAction="ifRoom"\r
+        android:title="@string/load"/>\r
+    <item\r
+        android:id="@+id/menu_save"\r
+        android:icon="@drawable/ic_menu_save"\r
+        android:orderInCategory="0"\r
+        android:showAsAction="ifRoom"\r
+        android:title="@string/save"/>\r
     <item\r
         android:id="@+id/motor_list_menu_option"\r
         android:icon="@drawable/ic_motorbrowser"\r
-        android:showAsAction="always"\r
+        android:orderInCategory="10"\r
+        android:showAsAction="ifRoom"\r
         android:title="@string/viewmotorslabel"/>\r
     <item\r
         android:id="@+id/preference_menu_option"\r
         android:icon="@drawable/ic_menu_preferences"\r
+        android:orderInCategory="10"\r
         android:title="@string/Preferences"/>\r
     <item\r
         android:id="@+id/menu_about"\r
+        android:icon="@drawable/ic_menu_info_details"\r
+        android:orderInCategory="10"\r
         android:showAsAction="never"\r
         android:title="@string/About"/>\r
 \r
diff --git a/android/res/menu/rocket_viewer_simulation_option_menu.xml b/android/res/menu/rocket_viewer_simulation_option_menu.xml
new file mode 100644 (file)
index 0000000..0464e59
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<menu xmlns:android="http://schemas.android.com/apk/res/android" >\r
+\r
+    <item\r
+        android:id="@+id/menu_add"\r
+        android:icon="@drawable/ic_menu_add"\r
+        android:orderInCategory="2"\r
+        android:showAsAction="always"\r
+        android:title="@string/Add"/>\r
+\r
+</menu>
\ No newline at end of file
index 122de68cd5fe3e6540980d48676aa729c29d4111..0f8aa934faab87396e69e873c5e612b034c4be8d 100644 (file)
@@ -2,9 +2,9 @@
 <menu xmlns:android="http://schemas.android.com/apk/res/android" >
 
     <item
-        android:id="@+id/simulation_select_series_menu_option"
-        android:title="@string/select_series"/>
+        android:id="@+id/simulation_config_plot_menu_option"
+        android:title="@string/configurePlot"/>
     <item
-        android:id="@+id/simulation_select_events_menu_option"
+        android:id="@+id/simulation_view_events_menu_option"
         android:title="@string/view_events"/>
 </menu>
\ No newline at end of file
diff --git a/android/res/values-fr/strings.xml b/android/res/values-fr/strings.xml
new file mode 100644 (file)
index 0000000..a6dcffd
--- /dev/null
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+    <string name="app_name">OpenRocket</string>
+    <string name="version">version 12.07-b7</string>
+    <string name="load">Charger</string>
+    <string name="save">Sauvegarder</string>
+    <string name="Add">Ajouter</string>
+    <string name="MotorListTitle">Liste de moteur</string>
+    <string name="Download">Télécharger</string>
+    <string name="About">A propos</string>
+    <string name="Preferences">Préférences</string>
+    <string name="configurePlot">Changer le tracé</string>
+    <string name="view_events">Voir les événements</string>
+    <string name="simulationPlotDialogTitle">Sélectionner les Séries et Evénements</string>
+    <string name="plot">Tracer</string>
+    <string name="saving">Sauvegarder le fichierâ…</string>
+    <string name="loading">Charger le fichierâ…</string>
+    <string name="loadWarnUnsaved">Voulez vous sauvegarder les changements dans le modèle courant?</string>
+    <string name="no">Non</string>
+    <string name="yes">Oui</string>
+    <string name="autoSaveMessage">Sauvegarde automatique de la fusée</string>
+    <string name="loadingErrorMessage">Erreur en chargeant le fichier</string>
+
+    <string-array name="PreferenceMotorBrowserGroupingEntries">
+        <item>Boitier</item>
+        <item>Diamètre</item>
+        <item>Impulsion</item>
+        <item>Fabriquant</item>
+    </string-array>
+
+    <string name="TCMotorSearchFormSubmit">Soumettre</string>
+    <string name="overviewConfigurationSpinnerPrompt">Choisir la Configuration</string>
+    <string name="simulationSeries1Label">Séries 1</string>
+    <string name="simulationSeries2Label">Séries 2</string>
+
+    <string name="autosavetitle">Sauvegarde auto de la fusée</string>
+    <string name="autosavesummary">Sauvegarde automatique du document fusée après avoir fait les simulations</string>
+    
+    <string name="motorbrowsergrouptitle">Motor Browser Grouping</string>
+    <string name="motorbrowsergroupsummary">Set the grouping in Motor Browser</string>
+    
+    <string name="motorbrowsertitle">Motor Browser</string>
+    
+    <string name="useinternalfilebrowsertitle">Utiliser le gestionnaire de fichiers interne</string>
+    <string name="useinternalfilebrowsersummary">Vérification pour Utiliser le gestionnaire de fichiers interne à la place d\'un gestionnaire de fichiers externe</string>
+    
+    <string name="showonlyorkfiles">Montrer seulement les fichiers ORK avec le gestionnaire de fichiers interne</string>
+    <string name="showonlyorkfilessummary">Check to show only .ork files in internal file browser</string>
+    
+    <string-array name="PreferenceUnitLengthEntries">
+        <item>Millimètres</item>
+        <item>Centimètres</item>
+        <item>Mètres</item>
+        <item>Pouces</item>
+        <item>Pieds</item>
+    </string-array>
+    <string-array name="PreferenceUnitMassEntries">
+        <item>Grammes</item>
+        <item>Kilogrammes</item>
+        <item>Onces</item>
+        <item>Livres</item>
+    </string-array>
+    <string-array name="PreferenceUnitVelocityEntries">
+        <item>Mètres/Seconde</item>
+        <item>Kilomètres/Heure</item>
+        <item>Pied/Seconde</item>
+        <item>Miles/Heure</item>
+    </string-array>
+    <string-array name="PreferenceUnitDistanceEntries">
+        <item>Mètres</item>
+        <item>Kilomètres</item>
+        <item>Pieds</item>
+        <item>Yards</item>
+        <item>Miles</item>
+        <item>Miles Nautiques</item>
+    </string-array>
+        <string name="rocket_cg">CG</string>
+        <string name="rocket_designer">Concepteur</string>
+        <string name="rocket_length">Longueur</string>
+        <string name="rocket_emptymass">Masse à vide</string>
+        <string name="rocket_stagecount">Nombre d\'étages</string>
+        <string name="rocket_liftoffweight">Poids au décollage</string>
+        <string name="rocket_cp">CP</string>
+        <string name="rocket_stabilitymargin">Marge de stabilité</string>
+        <string name="openfilelabel">Ouvrir le fichier ork</string>
+        <string name="viewmotorslabel">Voir les moteurs</string>
+        <string name="motor_manufacturer">Fabriquant</string>
+        <string name="motor_commonname">Nom commun</string>
+        <string name="motor_delays">Retards</string>
+        <string name="motor_caseinfo">Info boitier</string>
+        <string name="motor_impulseclass">Class de l\'impulsion</string>
+        <string name="motor_diameter">Diamètre</string>
+        <string name="motor_length">Longueur</string>
+        <string name="simulationConditionSelectMotors">Choisir les Moteurs</string>
+        <string name="simulationConditionWind">Vitesse du vent</string>
+        <string name="simulationConditionsRodLength">Longueur de la rampe</string>
+        <string name="simulationConditionsLaunchRodAngle">Angle de la rampe</string>
+        <string name="simulationConditionsLaunchRodDirection">Direction de la rampe</string>
+        <string name="select_motor">Choisir le moteur</string>
+        <string name="select_delay">Retard</string>
+        <string name="Delete">Effacer</string>
+        <string name="Run">Lancer</string>
+
+</resources>
index 1da23b82fd8e706e256c7dc1968af8bfd29fd28c..535b5345acd25849485db08fbed1d1f6798a1499 100644 (file)
@@ -1,39 +1,22 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-
 <resources>
 
-    <style name="AppTheme" parent="android:style/Theme.Holo">
-        <item name="android:actionBarStyle">@style/ActionBar</item>
-        <item name="android:windowContentOverlay">@drawable/actionbar_shadow</item>
-    </style>
-
-    <style name="ActionBar" parent="android:style/Widget.Holo.ActionBar">
-        <item name="android:background">@color/actionbar_background_color</item>
-        <item name="android:titleTextStyle">@style/ActionBarTitle</item>
-        <item name="android:logo">@drawable/home_item</item>
+    <style name="spinnerStyle" parent="Widget.Sherlock.TextView.SpinnerItem">
+        <item name="android:textSize">22dp</item>
     </style>
 
-    <style name="ActionBarTitle">
-        <item name="android:textColor">@color/actionbar_title_color</item>
+    <style name="AppTheme.NoActionBar" parent="AppTheme">
+        <item name="android:actionBarStyle">@style/ActionBar.noBlueBar</item>
+        <item name="android:background">@android:color/transparent</item>
+        <item name="background">@android:color/transparent</item>
+        <item name="android:windowActionBarOverlay">true</item>
+        <item name="windowActionBarOverlay">true</item>
     </style>
 
-    <style name="spinnerStyle" parent="@android:style/Widget.Holo.TextView.SpinnerItem">
-        <item name="android:textSize">22dp</item>
-        <item name="android:layout_height">wrap_content</item>
+    <style name="ActionBar.noBlueBar" parent="Widget.Sherlock.ActionBar">
+        <item name="android:background">@android:color/transparent</item>
+        <item name="background">@android:color/transparent</item>
+        <item name="android:displayOptions"></item>
+        <item name="displayOptions"></item>
     </style>
 
 </resources>
\ No newline at end of file
diff --git a/android/res/values-v13/styles.xml b/android/res/values-v13/styles.xml
deleted file mode 100644 (file)
index 69466f3..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
--->
-
-<resources>
-
-    <style name="ActionBarTitle" parent="android:style/TextAppearance.Holo.Widget.ActionBar.Title">
-        <item name="android:textColor">@color/actionbar_title_color</item>
-        <item name="android:background">@color/actionbar_background_color</item>
-    </style>
-
-</resources>
\ No newline at end of file
diff --git a/android/res/values/actionbar_attrs.xml b/android/res/values/actionbar_attrs.xml
deleted file mode 100644 (file)
index d731929..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<resources>
-
-    <declare-styleable name="AppTheme">
-        <attr name="actionbarCompatHomeAsUpStyle" format="reference" />
-        <attr name="actionbarCompatTitleStyle" format="reference" />
-        <attr name="actionbarCompatItemStyle" format="reference" />
-        <attr name="actionbarCompatItemHomeStyle" format="reference" />
-        <attr name="actionbarCompatProgressIndicatorStyle" format="reference" />
-    </declare-styleable>
-
-</resources>
diff --git a/android/res/values/actionbar_colors.xml b/android/res/values/actionbar_colors.xml
deleted file mode 100644 (file)
index 8939b91..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<resources>
-
-    <color name="actionbar_title_color">#FFFFFF</color>
-    <color name="actionbar_background_color">#00000000</color>
-    
-</resources>
diff --git a/android/res/values/actionbar_dimens.xml b/android/res/values/actionbar_dimens.xml
deleted file mode 100644 (file)
index d0960f0..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<resources>
-    <dimen name="actionbar_compat_height">48dp</dimen>
-    <dimen name="actionbar_compat_button_width">48dp</dimen>
-    <dimen name="actionbar_compat_button_home_width">40dp</dimen>
-</resources>
diff --git a/android/res/values/actionbar_ids.xml b/android/res/values/actionbar_ids.xml
deleted file mode 100644 (file)
index d0c0897..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-  Copyright 2011 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<resources>
-    <item type="id" name="actionbar_compat" />
-    <item type="id" name="actionbar_home_as_up" />
-    <item type="id" name="actionbar_compat_title" />
-    <item type="id" name="actionbar_compat_item_refresh_progress" />
-    <item type="id" name="actionbar_compat_item_refresh" />
-    <item type="id" name="menu_refresh" />
-</resources>
diff --git a/android/res/values/actionbar_styles.xml b/android/res/values/actionbar_styles.xml
deleted file mode 100644 (file)
index b09b716..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-<!--\r
-  Copyright 2011 The Android Open Source Project\r
-\r
-  Licensed under the Apache License, Version 2.0 (the "License");\r
-  you may not use this file except in compliance with the License.\r
-  You may obtain a copy of the License at\r
-\r
-      http://www.apache.org/licenses/LICENSE-2.0\r
-\r
-  Unless required by applicable law or agreed to in writing, software\r
-  distributed under the License is distributed on an "AS IS" BASIS,\r
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-  See the License for the specific language governing permissions and\r
-  limitations under the License.\r\r
--->\r
-\r
-<resources>\r
-\r
-    <style name="AppTheme.Clean" parent="AppTheme">\r
-        <item name="android:windowActionBarOverlay">true</item>\r
-    </style>\r
-\r
-    <style name="AppTheme" parent="android:style/Theme">\r
-        <item name="android:windowTitleSize">@dimen/actionbar_compat_height</item>\r
-        <item name="android:windowTitleBackgroundStyle">@style/ActionBarCompat</item>\r
-        <item name="android:windowContentOverlay">@drawable/actionbar_shadow</item>\r
-\r
-        <!-- for programmatic instantiation -->\r
-        <item name="actionbarCompatTitleStyle">@style/ActionBarCompatTitle</item>\r
-        <item name="actionbarCompatItemStyle">@style/ActionBarCompatItem</item>\r
-        <item name="actionbarCompatItemHomeStyle">@style/ActionBarCompatHomeItem</item>\r
-        <item name="actionbarCompatProgressIndicatorStyle">@style/ActionBarCompatProgressIndicator</item>\r
-        <item name="actionbarCompatHomeAsUpStyle">@style/ActionBarCompatHomeAsUp</item>\r
-    </style>\r
-\r
-    <style name="ActionBarCompat">\r
-        <item name="android:background">@color/actionbar_background_color</item>\r
-    </style>\r
-\r
-    <style name="ActionBarCompatHomeAsUp">\r
-        <item name="android:background">@drawable/ic_home_carat</item>\r
-    </style>\r
-\r
-    <style name="ActionBarCompatItemBase">\r
-\r
-        <!-- layout_width/height must be set in code -->\r
-        <item name="android:scaleType">center</item>\r
-        <item name="android:background">@drawable/actionbar_compat_item</item>\r
-    </style>\r
-\r
-    <style name="ActionBarCompatProgressIndicator" parent="android:style/Widget.ProgressBar.Large">\r
-        <item name="android:indeterminate">true</item>\r
-    </style>\r
-\r
-    <style name="ActionBarCompatTitleBase">\r
-        <item name="android:id">@id/actionbar_compat_title</item>\r
-        <!-- layout_width/height/weight must be set in code -->\r
-        <item name="android:gravity">center_vertical</item>\r
-        <item name="android:textSize">16sp</item>\r
-        <item name="android:paddingLeft">6dp</item>\r
-        <item name="android:paddingRight">6dp</item>\r
-        <item name="android:singleLine">true</item>\r
-        <item name="android:ellipsize">marquee</item>\r
-    </style>\r
-\r
-    <style name="ActionBarCompatTitle" parent="style/ActionBarCompatTitleBase">\r
-        <item name="android:textColor">@color/actionbar_title_color</item>\r
-    </style>\r
-\r
-    <style name="ActionBarCompatItem" parent="style/ActionBarCompatItemBase"></style>\r
-\r
-    <style name="ActionBarCompatHomeItem" parent="style/ActionBarCompatItemBase"></style>\r
-\r
-</resources>
\ No newline at end of file
diff --git a/android/res/values/attrs.xml b/android/res/values/attrs.xml
deleted file mode 100644 (file)
index 30060a4..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-       <declare-styleable name="TreeViewList">
-           <attr name="collapsible" format="boolean" />
-               <attr name="src_expanded" format="reference|color" />
-               <attr name="src_collapsed" format="reference|color" />
-        <attr name="indent_width" format="dimension" />
-        <attr name="handle_trackball_press" format="boolean" />
-               <attr name="indicator_gravity">
-                       <!-- Push object to the top of its container, not changing its size. -->
-                       <flag name="top" value="0x30" />
-                       <!-- Push object to the bottom of its container, not changing its size. -->
-                       <flag name="bottom" value="0x50" />
-                       <!-- Push object to the left of its container, not changing its size. -->
-                       <flag name="left" value="0x03" />
-                       <!-- Push object to the right of its container, not changing its size. -->
-                       <flag name="right" value="0x05" />
-                       <!-- Place object in the vertical center of its container, not changing its size. -->
-                       <flag name="center_vertical" value="0x10" />
-                       <!-- Grow the vertical size of the object if needed so it completely fills its container. -->
-                       <flag name="fill_vertical" value="0x70" />
-                       <!-- Place object in the horizontal center of its container, not changing its size. -->
-                       <flag name="center_horizontal" value="0x01" />
-                       <!-- Grow the horizontal size of the object if needed so it completely fills its container. -->
-                       <flag name="fill_horizontal" value="0x07" />
-                       <!-- Place the object in the center of its container in both the vertical and horizontal axis, not changing its size. -->
-                       <flag name="center" value="0x11" />
-                       <!-- Grow the horizontal and vertical size of the object if needed so it completely fills its container. -->
-                       <flag name="fill" value="0x77" />
-                       <!-- Additional option that can be set to have the top and/or bottom edges of the child clipped to its container's bounds.
-                               The clip will be based on the vertical gravity: a top gravity will clip the bottom edge, a bottom gravity will clip the top
-                               edge, and neither will clip both edges. -->
-                       <flag name="clip_vertical" value="0x80" />
-                       <!-- Additional option that can be set to have the left and/or right edges of the child clipped to its container's bounds.
-                               The clip will be based on the horizontal gravity: a left gravity will clip the right edge, a right gravity will clip the
-                               left edge, and neither will clip both edges. -->
-                       <flag name="clip_horizontal" value="0x08" />
-               </attr>
-        <attr name="indicator_background" format="reference|color" />
-        <attr name="row_background" format="reference|color" />
-       </declare-styleable>
-</resources>
\ No newline at end of file
index dcdd42210ab833a4fefa0674dac8aa26800508ab..5f3284ac4c7348c3ffcf0ab84120eb0bcbe82a33 100644 (file)
@@ -1,10 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>\r
 <resources>\r
 \r
+    <string name="SimulationServiceNotificationID"></string>\r
     <string name="PreferenceMotorBrowserGroupingOption">PreferenceMotorBrowserGroupingOption</string>\r
     <string name="PreferenceUseInternalFileBrowserOption">PreferenceUseInternalFileBrowserOpion</string>\r
     <string name="PreferenceFileBrowserBaseDirectory">PreferenceFileBrowserBaseDirectory</string>\r
     <string name="PreferenceShowOnlyOrkFiles">PreferenceShowOnlyOrkFiles</string>\r
+    <string name="PreferenceAutoSaveOption">PreferenceAutoSaveOption</string>\r
 \r
     <string-array name="PreferenceMotorBrowserGroupingValues">\r
         <item>0</item>\r
diff --git a/android/res/values/simulation_states.xml b/android/res/values/simulation_states.xml
new file mode 100644 (file)
index 0000000..836f7b4
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>\r
+<resources>\r
+\r
+    <declare-styleable name="SimulationState">\r
+        <attr name="simulation_invalid" format="boolean"/>\r
+        <attr name="simulation_stale" format="boolean"/>\r
+    </declare-styleable>\r
+\r
+</resources>
\ No newline at end of file
index 8eb5b45976d550cc373c218a610a1b6331b43c5f..993436e3fd57d2e570f7f6500590ccf2cfc2eda6 100644 (file)
@@ -2,14 +2,33 @@
 <resources>\r
 \r
     <string name="app_name">OpenRocket</string>\r
-    <string name="version">version 12.03</string>\r
+    <string name="version">version 12.07-b8</string>\r
+    <string name="cancel">Cancel</string>\r
+    <string name="ok">OK</string>\r
+    <string name="dismiss">Dismiss</string>\r
+    <string name="load">Load</string>\r
     <string name="save">Save</string>\r
+    <string name="Add">Add</string>\r
     <string name="MotorListTitle">Motor List</string>\r
     <string name="Download">Download</string>\r
     <string name="About">About</string>\r
     <string name="Preferences">Preferences</string>\r
-    <string name="select_series">Select Series</string>\r
+    <string name="missingMotors">Missing Motors</string>\r
+    <string name="missingMotorsMessageStart">The following motors are missing:</string>\r
+    <string name="missingMotorsMessageEnd">Would you like to download them from Thrustcurve?</string>\r
+    <string name="configurePlot">Change Plot</string>\r
     <string name="view_events">View Events</string>\r
+    <string name="simulationPlotDialogTitle">Select Series And Events</string>\r
+    <string name="DeleteConfigTitle">Delete Motor Configuration</string>\r
+    \r
+    <string name="plot">Plot</string>\r
+    <string name="saving">Saving file…</string>\r
+    <string name="loading">Loading file…</string>\r
+    <string name="loadWarnUnsaved">Would you like to save the changes to the current model?</string>\r
+    <string name="no">No</string>\r
+    <string name="yes">Yes</string>\r
+    <string name="autoSaveMessage">Automatically saving rocket</string>\r
+    <string name="loadingErrorMessage">Error Loading File</string>\r
 \r
     <string-array name="PreferenceMotorBrowserGroupingEntries">\r
         <item>Case</item>\r
     </string-array>\r
 \r
     <string name="TCMotorSearchFormSubmit">Submit</string>\r
+    <string name="TCMotorSearchFormTitle">Search Thrustcurve.org</string>\r
     <string name="overviewConfigurationSpinnerPrompt">Select Configuration</string>\r
     <string name="simulationSeries1Label">Series 1</string>\r
     <string name="simulationSeries2Label">Series 2</string>\r
 \r
+    <string name="autosavetitle">Autosave Rocket</string>\r
+    <string name="autosavesummary">Automatically save the rocket document after simulations</string>\r
+    \r
     <string name="motorbrowsergrouptitle">Motor Browser Grouping</string>\r
+    <string name="motorbrowsergroupsummary">Set the grouping in Motor Browser</string>\r
+    \r
+    <string name="motorbrowsertitle">Motor Browser</string>\r
     \r
     <string name="useinternalfilebrowsertitle">Use Internal File Browser</string>\r
     <string name="useinternalfilebrowsersummary">Check to use built in file browser instead of external file browser</string>\r
         <string name="motor_impulseclass">Impulse Class</string>\r
         <string name="motor_diameter">Diameter</string>\r
         <string name="motor_length">Length</string>\r
+        <string name="simulationConditionSelectMotors">Select Motors</string>\r
+        <string name="simulationConditionWind">Wind speed</string>\r
+        <string name="simulationConditionsRodLength">Launch Rod Length</string>\r
+        <string name="simulationConditionsLaunchRodAngle">Launch Rod Angle</string>\r
+        <string name="simulationConditionsLaunchRodDirection">Launch Rod Direction</string>\r
+        <string name="select_motor">Select Motor</string>\r
+        <string name="select_delay">Delay</string>\r
+        <string name="Delete">Delete</string>\r
+        <string name="Run">Run</string>\r
 \r
 </resources>
\ No newline at end of file
index 316c9fe8e5daaeb512bd32f1b2cdf355a99996e0..303484eac1ab8b9af5a09cc41c907c323ccd08bb 100644 (file)
@@ -1,23 +1,23 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <style name="treeViewListStyle" parent="@android:attr/listViewStyle">
-        <item name="android:background">@android:color/white</item>
-        <item name="android:divider">@drawable/divider</item>
-    </style>
-
     <style name="labelTextStyle" parent="@android:style/TextAppearance.Medium" />
 
     <style name="valueTextStyle" parent="@android:style/TextAppearance.Large">
         <item name="android:gravity">right</item>
     </style>
 
-    <style name="AppTheme.NoTitleBar" parent="@style/AppTheme">
-        <item name="android:windowNoTitle">true</item>
+    <style name="AppTheme" parent="Theme.Sherlock">
+        <item name="android:spinnerItemStyle">@style/spinnerStyle</item>
     </style>
 
-    <style name="spinnerStyle" parent="@android:style/Widget.TextView.SpinnerItem">
-        <item name="android:textSize">22dp</item>
+    <style name="AppTheme.NoActionBar" parent="AppTheme">
+        <item name="android:windowNoTitle">true</item>
+        <item name="windowNoTitle">true</item>
+        </style>
+
+    <style name="spinnerStyle" parent="Widget.Sherlock.TextView.SpinnerItem">
+        <item name="android:textSize">26dp</item>
         <item name="android:textColor">#000000</item>
         <item name="android:layout_height">30dp</item>
     </style>
index 2c1a667f456e4b2e686b97f597cb91139d63247c..ff39a61f380c4cd0b2a45650deb82cfb6434011a 100644 (file)
@@ -8,11 +8,17 @@
         android:entries="@array/PreferenceMotorBrowserGroupingEntries"
         android:entryValues="@array/PreferenceMotorBrowserGroupingValues"
         android:key="@string/PreferenceMotorBrowserGroupingOption"
-        android:summary="Set the grouping in Motor Browser"
+        android:summary="@string/motorbrowsergroupsummary"
         android:title="@string/motorbrowsergrouptitle" />
 
     <CheckBoxPreference
         android:defaultValue="false"
+        android:title="@string/autosavetitle"
+        android:key="@string/PreferenceAutoSaveOption"
+        android:summary="@string/autosavesummary"/>
+    
+    <CheckBoxPreference
+        android:defaultValue="true"
         android:title="@string/useinternalfilebrowsertitle"
         android:key="@string/PreferenceUseInternalFileBrowserOption"
         android:summary="@string/useinternalfilebrowsersummary"
diff --git a/android/src/build.properties b/android/src/build.properties
new file mode 100644 (file)
index 0000000..b892c09
--- /dev/null
@@ -0,0 +1,2 @@
+build.version=12.03-droid-DEV\r
+build.source=source\r
index 760176415b3d62f8ef9a489e6d9cc4e78fd26549..02e920e4c24d9246179f578d62c6a28ff192e1de 100644 (file)
@@ -11,7 +11,7 @@ public abstract class ActivityHelpers {
 \r
        public static void goHome( Activity parent ) {\r
                Intent i = new Intent(parent, Main.class);\r
-               i.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP);\r
+               i.addFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP + Intent.FLAG_ACTIVITY_NEW_TASK );\r
                parent.startActivity(i);\r
        }\r
        \r
index 98df485b24a4467be6f067bed39071e557c67a71..9661f400dd3e84f0b534f5d608397d48252fd4ad 100644 (file)
@@ -2,22 +2,19 @@ package net.sf.openrocket.android;
 \r
 import java.util.Locale;\r
 \r
-import net.sf.openrocket.aerodynamics.WarningSet;\r
 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
-import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.database.ComponentPresetDatabase;\r
 import net.sf.openrocket.l10n.DebugTranslator;\r
 import net.sf.openrocket.l10n.ResourceBundleTranslator;\r
 import net.sf.openrocket.l10n.Translator;\r
+import android.content.pm.ApplicationInfo;\r
 import android.preference.PreferenceManager;\r
 \r
 public class Application extends android.app.Application {\r
 \r
-       private OpenRocketDocument rocketDocument;\r
-       private WarningSet warnings;\r
-       \r
        // Big B boolean so I can synchronize on it.\r
        private static Boolean initialized = false;\r
-       \r
+\r
        public void initialize() {\r
                synchronized (initialized) {\r
                        if ( initialized == true ) {\r
@@ -28,19 +25,26 @@ public class Application extends android.app.Application {
                        System.setProperty("org.xml.sax.driver","org.xmlpull.v1.sax2.Driver");\r
 \r
                        net.sf.openrocket.startup.Application.setLogger( new AndroidLogWrapper.LogHelper() );\r
-                       \r
+\r
                        net.sf.openrocket.startup.Application.setPreferences( new PreferencesAdapter() );\r
-                       \r
+\r
+                       net.sf.openrocket.startup.Application.setComponentPresetDao( new ComponentPresetDatabase(){\r
+                               @Override\r
+                               protected void load() {\r
+                                       // We don't need components\r
+                               } \r
+                       } );\r
+\r
                        MotorDatabaseAdapter db = new MotorDatabaseAdapter(this);\r
 \r
                        net.sf.openrocket.startup.Application.setMotorSetDatabase(db);\r
-                       \r
+\r
                        Translator t;\r
                        t = new ResourceBundleTranslator("l10n.messages");\r
                        if (Locale.getDefault().getLanguage().equals("xx")) {\r
                                t = new DebugTranslator(t);\r
                        }\r
-                       \r
+\r
                        net.sf.openrocket.startup.Application.setBaseTranslator(t);\r
 \r
                        initialized = true;\r
@@ -57,31 +61,9 @@ public class Application extends android.app.Application {
        public void onCreate() {\r
                super.onCreate();\r
                initialize();\r
+               boolean isDebuggable = (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE));\r
+               AndroidLogWrapper.setLogEnabled(isDebuggable);\r
                PreferencesActivity.initializePreferences(this, PreferenceManager.getDefaultSharedPreferences(this));\r
        }\r
 \r
-       /**\r
-        * @return the rocketDocument\r
-        */\r
-       public OpenRocketDocument getRocketDocument() {\r
-               return rocketDocument;\r
-       }\r
-\r
-       /**\r
-        * @param rocketDocument the rocketDocument to set\r
-        */\r
-       public void setRocketDocument(OpenRocketDocument rocketDocument) {\r
-               this.rocketDocument = rocketDocument;\r
-       }\r
-\r
-       public WarningSet getWarnings() {\r
-               return warnings;\r
-       }\r
-\r
-       public void setWarnings(WarningSet warnings) {\r
-               this.warnings = warnings;\r
-       }\r
-       \r
-       \r
-       \r
 }\r
diff --git a/android/src/net/sf/openrocket/android/CurrentRocket.java b/android/src/net/sf/openrocket/android/CurrentRocket.java
new file mode 100644 (file)
index 0000000..3644606
--- /dev/null
@@ -0,0 +1,154 @@
+package net.sf.openrocket.android;\r
+\r
+import static net.sf.openrocket.android.events.Events.*;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import net.sf.openrocket.aerodynamics.WarningSet;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.document.Simulation;\r
+import net.sf.openrocket.document.StorageOptions;\r
+import net.sf.openrocket.file.openrocket.OpenRocketSaver;\r
+import net.sf.openrocket.rocketcomponent.Rocket;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.net.Uri;\r
+import android.support.v4.content.LocalBroadcastManager;\r
+\r
+public class CurrentRocket {\r
+\r
+       private Uri fileUri;\r
+\r
+       private OpenRocketDocument rocketDocument;\r
+       private WarningSet warnings;\r
+\r
+       private boolean isModified = false;\r
+       private Set<Integer> runningSims = new HashSet<Integer>();\r
+\r
+       /**\r
+        * @return the rocketDocument\r
+        */\r
+       public OpenRocketDocument getRocketDocument() {\r
+               return rocketDocument;\r
+       }\r
+\r
+       private void notifySimsChanged( Context context ) {\r
+               Intent msg = new Intent(MESSAGE_ACTION);\r
+               msg.putExtra(TYPE, SIMS_CHANGED);\r
+\r
+               LocalBroadcastManager.getInstance(context).sendBroadcast(msg);\r
+       }\r
+\r
+       private void notifySimComplete( Context context ) {\r
+               Intent msg = new Intent(MESSAGE_ACTION);\r
+               msg.putExtra(TYPE, SIM_COMPLETE);\r
+\r
+               LocalBroadcastManager.getInstance(context).sendBroadcast(msg);\r
+       }\r
+\r
+       private void notifyMotorConfigChanged( Context context ) {\r
+               Intent msg = new Intent(MESSAGE_ACTION);\r
+               msg.putExtra(TYPE, CONFIGS_CHANGED);\r
+\r
+               LocalBroadcastManager.getInstance(context).sendBroadcast(msg);\r
+       }\r
+\r
+       public synchronized void lockSimulation( Context context, int simulationId ) {\r
+               runningSims.add(simulationId);\r
+               // TODO - someday we might want to know about this:\r
+               // notifySimsChanged( context );\r
+       }\r
+\r
+       public synchronized void unlockSimulation( Context context, int simulationId ) {\r
+               this.isModified = true;\r
+               runningSims.remove(simulationId);\r
+               notifySimComplete(context);\r
+       }\r
+\r
+       public synchronized Set<Integer> lockedSimulations() {\r
+               return new HashSet<Integer>(runningSims);\r
+       }\r
+\r
+       public synchronized void addNewSimulation( Context context ) {\r
+               isModified = true;\r
+               Rocket rocket = rocketDocument.getRocket();\r
+               Simulation newSim = new Simulation(rocket);\r
+               newSim.setName(rocketDocument.getNextSimulationName());\r
+               rocketDocument.addSimulation(newSim);\r
+               notifySimsChanged(context);\r
+       }\r
+\r
+       public synchronized void deleteSimulation( Context context, int simulationPos ) {\r
+               isModified = true;\r
+               rocketDocument.removeSimulation( simulationPos );\r
+               notifySimsChanged(context);\r
+       }\r
+\r
+       public synchronized String addNewMotorConfig( Context context ) {\r
+               isModified = true;\r
+               String configId = rocketDocument.getRocket().newMotorConfigurationID();\r
+               notifyMotorConfigChanged(context);\r
+               return configId;\r
+       }\r
+       \r
+       public synchronized void deleteMotorConfig( Context context, String config ) {\r
+               rocketDocument.getRocket().removeMotorConfigurationID(config);\r
+               notifyMotorConfigChanged(context);\r
+       }\r
+       \r
+       /**\r
+        * @param rocketDocument the rocketDocument to set\r
+        */\r
+       public void setRocketDocument(OpenRocketDocument rocketDocument) {\r
+               this.rocketDocument = rocketDocument;\r
+               synchronized ( this ) {\r
+                       isModified = false;\r
+               }\r
+       }\r
+\r
+       public WarningSet getWarnings() {\r
+               return warnings;\r
+       }\r
+\r
+       public void setWarnings(WarningSet warnings) {\r
+               this.warnings = warnings;\r
+       }\r
+\r
+       public Uri getFileUri() {\r
+               return fileUri;\r
+       }\r
+\r
+       public void setFileUri(Uri fileUri) {\r
+               this.fileUri = fileUri;\r
+       }\r
+\r
+       public boolean isModified() {\r
+               return this.isModified;\r
+       }\r
+\r
+       public boolean canSave() {\r
+               return this.isModified && this.runningSims.isEmpty();\r
+       }\r
+\r
+       public void saveOpenRocketDocument() throws IOException {\r
+\r
+               // Translate the fileUri if it happens to be a .rkt file.\r
+\r
+               String filename = fileUri.getPath();\r
+\r
+               if ( ! filename.endsWith(".ork") ) {\r
+                       filename = filename.concat(".ork");\r
+               }\r
+\r
+               OpenRocketSaver saver = new OpenRocketSaver();\r
+               StorageOptions options = new StorageOptions();\r
+               options.setCompressionEnabled(true);\r
+               options.setSimulationTimeSkip(StorageOptions.SIMULATION_DATA_ALL);\r
+               saver.save(new File(filename),rocketDocument,options);\r
+               isModified = false;\r
+       }\r
+\r
+}\r
diff --git a/android/src/net/sf/openrocket/android/CurrentRocketHolder.java b/android/src/net/sf/openrocket/android/CurrentRocketHolder.java
new file mode 100644 (file)
index 0000000..566a2db
--- /dev/null
@@ -0,0 +1,12 @@
+package net.sf.openrocket.android;\r
+\r
+\r
+public abstract class CurrentRocketHolder {\r
+\r
+       private static CurrentRocket currentRocket = new CurrentRocket();\r
+       \r
+       public static CurrentRocket getCurrentRocket() {\r
+               return currentRocket;\r
+       }\r
+       \r
+}\r
index 06e581386f48503ac0957c6bf9a6c25ec2dca1c0..7b6eb48e3e39a03e34205d3cfa1c9d04824ea2b9 100644 (file)
@@ -1,30 +1,21 @@
 package net.sf.openrocket.android;\r
 \r
 import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.actionbarcompat.ActionBarFragmentActivity;\r
-import net.sf.openrocket.android.filebrowser.SimpleFileBrowser;\r
-import android.content.ActivityNotFoundException;\r
-import android.content.Intent;\r
-import android.content.SharedPreferences;\r
-import android.content.res.Resources;\r
-import android.net.Uri;\r
+import net.sf.openrocket.android.rocket.OpenRocketLoaderActivity;\r
 import android.os.Bundle;\r
-import android.preference.PreferenceManager;\r
-import android.view.Menu;\r
-import android.view.MenuInflater;\r
-import android.view.MenuItem;\r
 import android.view.View;\r
 import android.widget.Button;\r
 \r
-public class Main extends ActionBarFragmentActivity {\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
 \r
-       private static final int PICK_ORK_FILE_RESULT = 1;\r
+public class Main extends OpenRocketLoaderActivity {\r
 \r
        /** Called when the activity is first created. */\r
        @Override\r
        public void onCreate(Bundle icicle) {\r
                super.onCreate(icicle);\r
-               setTitle("");\r
                setContentView(R.layout.main);\r
                ((Button) findViewById(R.id.main_open)).setOnClickListener(\r
                                new View.OnClickListener() {\r
@@ -49,9 +40,18 @@ public class Main extends ActionBarFragmentActivity {
                                });\r
        }\r
 \r
+       @Override\r
+       protected void onPostResume() {\r
+               super.onPostResume();\r
+               // Rocket already loaded.\r
+               if ( !isLoading() && CurrentRocketHolder.getCurrentRocket().getRocketDocument() != null ) {\r
+                       moveOnToViewer();\r
+               }\r
+       }\r
+\r
        @Override\r
        public boolean onCreateOptionsMenu(Menu menu) {\r
-               MenuInflater inflater = getMenuInflater();\r
+               MenuInflater inflater = getSupportMenuInflater();\r
                inflater.inflate(R.menu.main_menu, menu);\r
                return true;\r
        }\r
@@ -69,55 +69,4 @@ public class Main extends ActionBarFragmentActivity {
                return super.onOptionsItemSelected(item);\r
        }\r
 \r
-       /* (non-Javadoc)\r
-        * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)\r
-        */\r
-       @Override\r
-       protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
-               switch ( requestCode ) {\r
-               case PICK_ORK_FILE_RESULT:\r
-                       if(resultCode==RESULT_OK){\r
-                               Uri file = data.getData();\r
-                               Intent intent = new Intent(Intent.ACTION_VIEW);\r
-                               intent.setData(file);\r
-                               startActivity(intent);\r
-                       }\r
-                       break;\r
-               }\r
-               super.onActivityResult(requestCode, resultCode, data);\r
-       }\r
-\r
-       private void pickOrkFiles( ) {\r
-               Resources resources = this.getResources();\r
-               String key = resources.getString(R.string.PreferenceUseInternalFileBrowserOption);\r
-               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);\r
-\r
-               boolean useinternalbrowser = pref.getBoolean(key, false);\r
-\r
-               if ( useinternalbrowser ) {\r
-                       Intent intent = new Intent(Main.this, SimpleFileBrowser.class);\r
-                       startActivityForResult(intent,PICK_ORK_FILE_RESULT);\r
-               } else {\r
-                       try {\r
-                               Intent intent = new Intent(Intent.ACTION_GET_CONTENT);\r
-                               intent.setType("file/*");\r
-                               startActivityForResult(intent,PICK_ORK_FILE_RESULT);\r
-                       } catch ( ActivityNotFoundException ex ) { \r
-                               // No activity for ACTION_GET_CONTENT  use internal file browser\r
-                               // update the preference value.\r
-                               pref.edit().putBoolean(key, false).commit();\r
-                               // fire our browser\r
-                               Intent intent = new Intent(Main.this, SimpleFileBrowser.class);\r
-                               startActivityForResult(intent,PICK_ORK_FILE_RESULT);\r
-                       }\r
-               }               \r
-       }\r
-       public void pickOrkFiles( View v ) {\r
-               pickOrkFiles();\r
-       }\r
-\r
-       public void browseMotors( View v ) {\r
-               ActivityHelpers.browseMotors(this);\r
-       }\r
-\r
 }\r
index 7260918479a7114a17d72a9ce94ee819174bf910..cb027d2b8a1a77e242d8be57435000ee1071a19c 100644 (file)
@@ -33,7 +33,7 @@ public class MotorDatabaseAdapter implements MotorDatabase {
                try {\r
                        ExtendedThrustCurveMotor m = mDbHelper.getMotorDao().fetchMotor(manufacturer, designation);\r
                        if ( m != null ) {\r
-                               return Collections.singletonList(m.getThrustCurveMotor());\r
+                               return Collections.singletonList(m);\r
                        }\r
                } catch ( Exception ex ) {\r
 \r
index 5aa544ad71f0a9d2a800634c4ef15884e9b933c2..c6e6eee327b74f9831fbc4adb9a57d91cc5cadb6 100644 (file)
@@ -8,7 +8,9 @@ import android.os.Bundle;
 import android.preference.Preference;\r
 import android.preference.PreferenceManager;\r
 \r
-public class PreferencesActivity extends android.preference.PreferenceActivity \r
+import com.actionbarsherlock.app.SherlockPreferenceActivity;\r
+\r
+public class PreferencesActivity extends SherlockPreferenceActivity \r
 {\r
 \r
        \r
index 086c18c32b1b499110004240911b669805a1097b..e4d68a7a54b8aee287d1c1aaa5b1d032a5329bbb 100644 (file)
@@ -4,6 +4,8 @@ import java.util.Collections;
 import java.util.Set;\r
 \r
 import net.sf.openrocket.material.Material;\r
+import net.sf.openrocket.preset.ComponentPreset;\r
+import net.sf.openrocket.preset.ComponentPreset.Type;\r
 \r
 public class PreferencesAdapter extends net.sf.openrocket.startup.Preferences {\r
 \r
@@ -89,8 +91,15 @@ public class PreferencesAdapter extends net.sf.openrocket.startup.Preferences {
         */\r
        @Override\r
        public void removeUserMaterial(Material m) {\r
-               // TODO Auto-generated method stub\r
-               \r
+       }\r
+\r
+       @Override\r
+       public void setComponentFavorite(ComponentPreset preset, Type type,     boolean favorite) {\r
+       }\r
+\r
+       @Override\r
+       public Set<String> getComponentFavorites(Type type) {\r
+               return Collections.<String>emptySet();\r
        }\r
 \r
 }\r
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarActivity.java b/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarActivity.java
deleted file mode 100644 (file)
index a3bad47..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-
-/**
- * A base activity that defers common functionality across app activities to an {@link
- * ActionBarHelper}.
- *
- * NOTE: dynamically marking menu items as invisible/visible is not currently supported.
- *
- * NOTE: this may used with the Android Compatibility Package by extending
- * android.support.v4.app.FragmentActivity instead of {@link Activity}.
- */
-public abstract class ActionBarActivity extends Activity {
-    final ActionBarHelper mActionBarHelper = ActionBarHelper.createInstance(this);
-
-    /**
-     * Returns the {@link ActionBarHelper} for this activity.
-     */
-    protected ActionBarHelper getActionBarHelper() {
-        return mActionBarHelper;
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    public MenuInflater getMenuInflater() {
-        return mActionBarHelper.getMenuInflater(super.getMenuInflater());
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mActionBarHelper.onCreate(savedInstanceState);
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onPostCreate(Bundle savedInstanceState) {
-        super.onPostCreate(savedInstanceState);
-        mActionBarHelper.onPostCreate(savedInstanceState);
-    }
-
-    /**
-     * Base action bar-aware implementation for
-     * {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
-     *
-     * Note: marking menu items as invisible/visible is not currently supported.
-     */
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        boolean retValue = false;
-        retValue |= mActionBarHelper.onCreateOptionsMenu(menu);
-        retValue |= super.onCreateOptionsMenu(menu);
-        return retValue;
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onTitleChanged(CharSequence title, int color) {
-        mActionBarHelper.onTitleChanged(title, color);
-        super.onTitleChanged(title, color);
-    }
-}
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarFragmentActivity.java b/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarFragmentActivity.java
deleted file mode 100644 (file)
index 526c962..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.support.v4.app.FragmentActivity;
-import android.view.Menu;
-import android.view.MenuInflater;
-
-/**
- * A base activity that defers common functionality across app activities to an {@link
- * ActionBarHelper}.
- *
- * NOTE: dynamically marking menu items as invisible/visible is not currently supported.
- *
- * NOTE: this may used with the Android Compatibility Package by extending
- * android.support.v4.app.FragmentActivity instead of {@link Activity}.
- */
-public abstract class ActionBarFragmentActivity extends FragmentActivity {
-    final ActionBarHelper mActionBarHelper = ActionBarHelper.createInstance(this);
-
-    /**
-     * Returns the {@link ActionBarHelper} for this activity.
-     */
-    protected ActionBarHelper getActionBarHelper() {
-        return mActionBarHelper;
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    public MenuInflater getMenuInflater() {
-        return mActionBarHelper.getMenuInflater(super.getMenuInflater());
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mActionBarHelper.onCreate(savedInstanceState);
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onPostCreate(Bundle savedInstanceState) {
-        super.onPostCreate(savedInstanceState);
-        mActionBarHelper.onPostCreate(savedInstanceState);
-    }
-
-    /**
-     * Base action bar-aware implementation for
-     * {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
-     *
-     * Note: marking menu items as invisible/visible is not currently supported.
-     */
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        boolean retValue = false;
-        retValue |= mActionBarHelper.onCreateOptionsMenu(menu);
-        retValue |= super.onCreateOptionsMenu(menu);
-        return retValue;
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onTitleChanged(CharSequence title, int color) {
-        mActionBarHelper.onTitleChanged(title, color);
-        super.onTitleChanged(title, color);
-    }
-}
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelper.java b/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelper.java
deleted file mode 100644 (file)
index e0595d8..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import net.sf.openrocket.R;
-import android.app.Activity;
-import android.os.Build;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-
-/**
- * An abstract class that handles some common action bar-related functionality in the app. This
- * class provides functionality useful for both phones and tablets, and does not require any Android
- * 3.0-specific features, although it uses them if available.
- *
- * Two implementations of this class are {@link ActionBarHelperBase} for a pre-Honeycomb version of
- * the action bar, and {@link ActionBarHelperHoneycomb}, which uses the built-in ActionBar features
- * in Android 3.0 and later.
- */
-public abstract class ActionBarHelper {
-    protected Activity mActivity;
-
-    /**
-     * Factory method for creating {@link ActionBarHelper} objects for a
-     * given activity. Depending on which device the app is running, either a basic helper or
-     * Honeycomb-specific helper will be returned.
-     */
-    public static ActionBarHelper createInstance(Activity activity) {
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            return new ActionBarHelperICS(activity);
-        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
-            return new ActionBarHelperHoneycomb(activity);
-        } else {
-            return new ActionBarHelperBase(activity);
-        }
-    }
-
-    protected ActionBarHelper(Activity activity) {
-        mActivity = activity;
-    }
-
-    /**
-     * Action bar helper code to be run in {@link Activity#onCreate(android.os.Bundle)}.
-     */
-    public void onCreate(Bundle savedInstanceState) {
-    }
-
-    /**
-     * Action bar helper code to be run in {@link Activity#onPostCreate(android.os.Bundle)}.
-     */
-    public void onPostCreate(Bundle savedInstanceState) {
-    }
-
-    /**
-     * Action bar helper code to be run in {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
-     *
-     * NOTE: Setting the visibility of menu items in <em>menu</em> is not currently supported.
-     */
-    public boolean onCreateOptionsMenu(Menu menu) {
-        return true;
-    }
-
-    /**
-     * Action bar helper code to be run in {@link Activity#onTitleChanged(CharSequence, int)}.
-     */
-    protected void onTitleChanged(CharSequence title, int color) {
-    }
-
-    /**
-     * Sets the indeterminate loading state of the item with ID {@link R.id.menu_refresh}.
-     * (where the item ID was menu_refresh).
-     */
-    public abstract void setRefreshActionItemState(boolean refreshing);
-
-    /**
-     * Returns a {@link MenuInflater} for use when inflating menus. The implementation of this
-     * method in {@link ActionBarHelperBase} returns a wrapped menu inflater that can read
-     * action bar metadata from a menu resource pre-Honeycomb.
-     */
-    public MenuInflater getMenuInflater(MenuInflater superMenuInflater) {
-        return superMenuInflater;
-    }
-    
-    public abstract void setDisplayHomeAsUpEnabled( boolean enabled );
-    
-    public abstract void hide();
-}
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperBase.java b/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperBase.java
deleted file mode 100644 (file)
index 6c8054f..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import java.io.IOException;
-import java.util.HashSet;
-import java.util.Set;
-
-import net.sf.openrocket.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.res.XmlResourceParser;
-import android.os.Bundle;
-import android.view.Gravity;
-import android.view.InflateException;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-/**
- * A class that implements the action bar pattern for pre-Honeycomb devices.
- */
-public class ActionBarHelperBase extends ActionBarHelper {
-    private static final String MENU_RES_NAMESPACE = "http://schemas.android.com/apk/res/android";
-    private static final String MENU_ATTR_ID = "id";
-    private static final String MENU_ATTR_SHOW_AS_ACTION = "showAsAction";
-    
-    private boolean showHomeAsUpEnabled = false;
-
-    protected Set<Integer> mActionItemIds = new HashSet<Integer>();
-
-    protected ActionBarHelperBase(Activity activity) {
-        super(activity);
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        mActivity.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    public void onPostCreate(Bundle savedInstanceState) {
-        mActivity.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
-                R.layout.actionbar_compat);
-        setupActionBar();
-
-        SimpleMenu menu = new SimpleMenu(mActivity);
-        mActivity.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);
-        mActivity.onPrepareOptionsMenu(menu);
-        for (int i = 0; i < menu.size(); i++) {
-            MenuItem item = menu.getItem(i);
-            if (mActionItemIds.contains(item.getItemId())) {
-                addActionItemCompatFromMenuItem(item);
-            }
-        }
-    }
-
-    /**
-     * Sets up the compatibility action bar with the given title.
-     */
-    private void setupActionBar() {
-        final ViewGroup actionBarCompat = getActionBarCompat();
-        if (actionBarCompat == null) {
-            return;
-        }
-
-        LinearLayout.LayoutParams springLayoutParams = new LinearLayout.LayoutParams(
-                0, ViewGroup.LayoutParams.FILL_PARENT);
-        springLayoutParams.weight = 1;
-
-        // Add Home as Up Carat
-        ImageButton homeAsUp = new ImageButton(mActivity,null, R.attr.actionbarCompatHomeAsUpStyle);
-        homeAsUp.setId(R.id.actionbar_home_as_up);
-        LinearLayout.LayoutParams centerVerticalParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
-        centerVerticalParams.gravity = Gravity.CENTER_VERTICAL;
-        homeAsUp.setLayoutParams(centerVerticalParams);
-        homeAsUp.setVisibility( showHomeAsUpEnabled ? View.VISIBLE : View.INVISIBLE );
-        actionBarCompat.addView(homeAsUp);
-        
-        // Add Home button
-        SimpleMenu tempMenu = new SimpleMenu(mActivity);
-        SimpleMenuItem homeItem = new SimpleMenuItem(
-                tempMenu, android.R.id.home, 0, mActivity.getString(R.string.app_name));
-        homeItem.setIcon(R.drawable.home_item);
-        addActionItemCompatFromMenuItem(homeItem);
-
-        // Add title text
-        TextView titleText = new TextView(mActivity, null, R.attr.actionbarCompatTitleStyle);
-        titleText.setLayoutParams(springLayoutParams);
-        titleText.setText(mActivity.getTitle());
-        actionBarCompat.addView(titleText);
-        
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    public void setRefreshActionItemState(boolean refreshing) {
-        View refreshButton = mActivity.findViewById(R.id.actionbar_compat_item_refresh);
-        View refreshIndicator = mActivity.findViewById(
-                R.id.actionbar_compat_item_refresh_progress);
-
-        if (refreshButton != null) {
-            refreshButton.setVisibility(refreshing ? View.GONE : View.VISIBLE);
-        }
-        if (refreshIndicator != null) {
-            refreshIndicator.setVisibility(refreshing ? View.VISIBLE : View.GONE);
-        }
-    }
-
-    /**
-     * Action bar helper code to be run in {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
-     *
-     * NOTE: This code will mark on-screen menu items as invisible.
-     */
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        // Hides on-screen action items from the options menu.
-        for (Integer id : mActionItemIds) {
-            menu.findItem(id).setVisible(false);
-        }
-        return true;
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onTitleChanged(CharSequence title, int color) {
-        TextView titleView = (TextView) mActivity.findViewById(R.id.actionbar_compat_title);
-        if (titleView != null) {
-            titleView.setText(title);
-        }
-    }
-
-    /**
-     * Returns a {@link android.view.MenuInflater} that can read action bar metadata on
-     * pre-Honeycomb devices.
-     */
-    public MenuInflater getMenuInflater(MenuInflater superMenuInflater) {
-        return new WrappedMenuInflater(mActivity, superMenuInflater);
-    }
-
-    @Override
-       public void setDisplayHomeAsUpEnabled(boolean enabled) {
-       showHomeAsUpEnabled = enabled;
-       View v = mActivity.findViewById(R.id.actionbar_home_as_up);
-       if ( v != null ) {
-               v.setVisibility( showHomeAsUpEnabled ? View.VISIBLE : View.INVISIBLE );
-       }
-               
-       }
-
-    @Override
-    public void hide() {
-       ViewGroup actionbar = getActionBarCompat();
-       actionbar.setVisibility(View.GONE);
-    }
-       /**
-     * Returns the {@link android.view.ViewGroup} for the action bar on phones (compatibility action
-     * bar). Can return null, and will return null on Honeycomb.
-     */
-    private ViewGroup getActionBarCompat() {
-        return (ViewGroup) mActivity.findViewById(R.id.actionbar_compat);
-    }
-
-    /**
-     * Adds an action button to the compatibility action bar, using menu information from a {@link
-     * android.view.MenuItem}. If the menu item ID is <code>menu_refresh</code>, the menu item's
-     * state can be changed to show a loading spinner using
-     * {@link com.example.android.actionbarcompat.ActionBarHelperBase#setRefreshActionItemState(boolean)}.
-     */
-    private View addActionItemCompatFromMenuItem(final MenuItem item) {
-        final int itemId = item.getItemId();
-
-        final ViewGroup actionBar = getActionBarCompat();
-        if (actionBar == null) {
-            return null;
-        }
-
-        // Create the button
-        ImageButton actionButton = new ImageButton(mActivity, null,
-                itemId == android.R.id.home
-                        ? R.attr.actionbarCompatItemHomeStyle
-                        : R.attr.actionbarCompatItemStyle);
-        actionButton.setLayoutParams(new ViewGroup.LayoutParams(
-                (int) mActivity.getResources().getDimension(
-                        itemId == android.R.id.home
-                                ? R.dimen.actionbar_compat_button_home_width
-                                : R.dimen.actionbar_compat_button_width),
-                ViewGroup.LayoutParams.FILL_PARENT));
-        if (itemId == R.id.menu_refresh) {
-            actionButton.setId(R.id.actionbar_compat_item_refresh);
-        }
-        actionButton.setImageDrawable(item.getIcon());
-        actionButton.setScaleType(ImageView.ScaleType.CENTER);
-        actionButton.setContentDescription(item.getTitle());
-        actionButton.setOnClickListener(new View.OnClickListener() {
-            public void onClick(View view) {
-                mActivity.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
-            }
-        });
-
-        actionBar.addView(actionButton);
-
-        if (item.getItemId() == R.id.menu_refresh) {
-            // Refresh buttons should be stateful, and allow for indeterminate progress indicators,
-            // so add those.
-            ProgressBar indicator = new ProgressBar(mActivity, null,
-                    R.attr.actionbarCompatProgressIndicatorStyle);
-
-            final int buttonWidth = mActivity.getResources().getDimensionPixelSize(
-                    R.dimen.actionbar_compat_button_width);
-            final int buttonHeight = mActivity.getResources().getDimensionPixelSize(
-                    R.dimen.actionbar_compat_height);
-            final int progressIndicatorWidth = buttonWidth / 2;
-
-            LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
-                    progressIndicatorWidth, progressIndicatorWidth);
-            indicatorLayoutParams.setMargins(
-                    (buttonWidth - progressIndicatorWidth) / 2,
-                    (buttonHeight - progressIndicatorWidth) / 2,
-                    (buttonWidth - progressIndicatorWidth) / 2,
-                    0);
-            indicator.setLayoutParams(indicatorLayoutParams);
-            indicator.setVisibility(View.GONE);
-            indicator.setId(R.id.actionbar_compat_item_refresh_progress);
-            actionBar.addView(indicator);
-        }
-
-        return actionButton;
-    }
-
-    /**
-     * A {@link android.view.MenuInflater} that reads action bar metadata.
-     */
-    private class WrappedMenuInflater extends MenuInflater {
-        MenuInflater mInflater;
-
-        public WrappedMenuInflater(Context context, MenuInflater inflater) {
-            super(context);
-            mInflater = inflater;
-        }
-
-        @Override
-        public void inflate(int menuRes, Menu menu) {
-            loadActionBarMetadata(menuRes);
-            mInflater.inflate(menuRes, menu);
-        }
-
-        /**
-         * Loads action bar metadata from a menu resource, storing a list of menu item IDs that
-         * should be shown on-screen (i.e. those with showAsAction set to always or ifRoom).
-         * @param menuResId
-         */
-        private void loadActionBarMetadata(int menuResId) {
-            XmlResourceParser parser = null;
-            try {
-                parser = mActivity.getResources().getXml(menuResId);
-
-                int eventType = parser.getEventType();
-                int itemId;
-                int showAsAction;
-
-                boolean eof = false;
-                while (!eof) {
-                    switch (eventType) {
-                        case XmlPullParser.START_TAG:
-                            if (!parser.getName().equals("item")) {
-                                break;
-                            }
-
-                            itemId = parser.getAttributeResourceValue(MENU_RES_NAMESPACE,
-                                    MENU_ATTR_ID, 0);
-                            if (itemId == 0) {
-                                break;
-                            }
-
-                            showAsAction = parser.getAttributeIntValue(MENU_RES_NAMESPACE,
-                                    MENU_ATTR_SHOW_AS_ACTION, -1);
-                            if (showAsAction == MenuItem.SHOW_AS_ACTION_ALWAYS ||
-                                    showAsAction == MenuItem.SHOW_AS_ACTION_IF_ROOM) {
-                                mActionItemIds.add(itemId);
-                            }
-                            break;
-
-                        case XmlPullParser.END_DOCUMENT:
-                            eof = true;
-                            break;
-                    }
-
-                    eventType = parser.next();
-                }
-            } catch (XmlPullParserException e) {
-                throw new InflateException("Error inflating menu XML", e);
-            } catch (IOException e) {
-                throw new InflateException("Error inflating menu XML", e);
-            } finally {
-                if (parser != null) {
-                    parser.close();
-                }
-            }
-        }
-
-    }
-}
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperHoneycomb.java b/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperHoneycomb.java
deleted file mode 100644 (file)
index e31a4f9..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import net.sf.openrocket.R;
-import android.app.Activity;
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-
-/**
- * An extension of {@link ActionBarHelper} that provides Android 3.0-specific functionality for
- * Honeycomb tablets. It thus requires API level 11.
- */
-public class ActionBarHelperHoneycomb extends ActionBarHelper {
-    private Menu mOptionsMenu;
-    private View mRefreshIndeterminateProgressView = null;
-
-    protected ActionBarHelperHoneycomb(Activity activity) {
-        super(activity);
-    }
-
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        mOptionsMenu = menu;
-        return super.onCreateOptionsMenu(menu);
-    }
-
-    @Override
-    public void setRefreshActionItemState(boolean refreshing) {
-        // On Honeycomb, we can set the state of the refresh button by giving it a custom
-        // action view.
-        if (mOptionsMenu == null) {
-            return;
-        }
-
-        final MenuItem refreshItem = mOptionsMenu.findItem(R.id.menu_refresh);
-        if (refreshItem != null) {
-            if (refreshing) {
-                if (mRefreshIndeterminateProgressView == null) {
-                    LayoutInflater inflater = (LayoutInflater)
-                            getActionBarThemedContext().getSystemService(
-                                    Context.LAYOUT_INFLATER_SERVICE);
-                    mRefreshIndeterminateProgressView = inflater.inflate(
-                            R.layout.actionbar_indeterminate_progress, null);
-                }
-
-                refreshItem.setActionView(mRefreshIndeterminateProgressView);
-            } else {
-                refreshItem.setActionView(null);
-            }
-        }
-    }
-
-    /**
-     * Returns a {@link Context} suitable for inflating layouts for the action bar. The
-     * implementation for this method in {@link ActionBarHelperICS} asks the action bar for a
-     * themed context.
-     */
-    protected Context getActionBarThemedContext() {
-        return mActivity;
-    }
-
-       @Override
-       public void setDisplayHomeAsUpEnabled(boolean enabled) {
-               mActivity.getActionBar().setDisplayHomeAsUpEnabled(enabled);
-       }
-    
-       @Override
-       public void hide() {
-               mActivity.getActionBar().hide();
-       }
-    
-}
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperICS.java b/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarHelperICS.java
deleted file mode 100644 (file)
index 7d00612..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import android.app.Activity;
-import android.content.Context;
-
-/**
- * An extension of {@link com.example.android.actionbarcompat.ActionBarHelper} that provides Android
- * 4.0-specific functionality for IceCreamSandwich devices. It thus requires API level 14.
- */
-public class ActionBarHelperICS extends ActionBarHelperHoneycomb {
-    protected ActionBarHelperICS(Activity activity) {
-        super(activity);
-    }
-
-    @Override
-    protected Context getActionBarThemedContext() {
-        return mActivity.getActionBar().getThemedContext();
-    }
-}
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarListActivity.java b/android/src/net/sf/openrocket/android/actionbarcompat/ActionBarListActivity.java
deleted file mode 100644 (file)
index b813208..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import android.app.Activity;
-import android.app.ListActivity;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-
-public abstract class ActionBarListActivity extends ListActivity {
-    final ActionBarHelper mActionBarHelper = ActionBarHelper.createInstance(this);
-
-    /**
-     * Returns the {@link ActionBarHelper} for this activity.
-     */
-    protected ActionBarHelper getActionBarHelper() {
-        return mActionBarHelper;
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    public MenuInflater getMenuInflater() {
-        return mActionBarHelper.getMenuInflater(super.getMenuInflater());
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        mActionBarHelper.onCreate(savedInstanceState);
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onPostCreate(Bundle savedInstanceState) {
-        super.onPostCreate(savedInstanceState);
-        mActionBarHelper.onPostCreate(savedInstanceState);
-    }
-
-    /**
-     * Base action bar-aware implementation for
-     * {@link Activity#onCreateOptionsMenu(android.view.Menu)}.
-     *
-     * Note: marking menu items as invisible/visible is not currently supported.
-     */
-    @Override
-    public boolean onCreateOptionsMenu(Menu menu) {
-        boolean retValue = false;
-        retValue |= mActionBarHelper.onCreateOptionsMenu(menu);
-        retValue |= super.onCreateOptionsMenu(menu);
-        return retValue;
-    }
-
-    /**{@inheritDoc}*/
-    @Override
-    protected void onTitleChanged(CharSequence title, int color) {
-        mActionBarHelper.onTitleChanged(title, color);
-        super.onTitleChanged(title, color);
-    }
-}
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/SimpleMenu.java b/android/src/net/sf/openrocket/android/actionbarcompat/SimpleMenu.java
deleted file mode 100644 (file)
index fb9a48f..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import java.util.ArrayList;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Resources;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-
-/**
- * A <em>really</em> dumb implementation of the {@link android.view.Menu} interface, that's only
- * useful for our actionbar-compat purposes. See
- * <code>com.android.internal.view.menu.MenuBuilder</code> in AOSP for a more complete
- * implementation.
- */
-public class SimpleMenu implements Menu {
-
-    private Context mContext;
-    private Resources mResources;
-
-    private ArrayList<SimpleMenuItem> mItems;
-
-    public SimpleMenu(Context context) {
-        mContext = context;
-        mResources = context.getResources();
-        mItems = new ArrayList<SimpleMenuItem>();
-    }
-
-    public Context getContext() {
-        return mContext;
-    }
-
-    public Resources getResources() {
-        return mResources;
-    }
-
-    public MenuItem add(CharSequence title) {
-        return addInternal(0, 0, title);
-    }
-
-    public MenuItem add(int titleRes) {
-        return addInternal(0, 0, mResources.getString(titleRes));
-    }
-
-    public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
-        return addInternal(itemId, order, title);
-    }
-
-    public MenuItem add(int groupId, int itemId, int order, int titleRes) {
-        return addInternal(itemId, order, mResources.getString(titleRes));
-    }
-
-    /**
-     * Adds an item to the menu.  The other add methods funnel to this.
-     */
-    private MenuItem addInternal(int itemId, int order, CharSequence title) {
-        final SimpleMenuItem item = new SimpleMenuItem(this, itemId, order, title);
-        mItems.add(findInsertIndex(mItems, order), item);
-        return item;
-    }
-
-    private static int findInsertIndex(ArrayList<? extends MenuItem> items, int order) {
-        for (int i = items.size() - 1; i >= 0; i--) {
-            MenuItem item = items.get(i);
-            if (item.getOrder() <= order) {
-                return i + 1;
-            }
-        }
-
-        return 0;
-    }
-
-    public int findItemIndex(int id) {
-        final int size = size();
-
-        for (int i = 0; i < size; i++) {
-            SimpleMenuItem item = mItems.get(i);
-            if (item.getItemId() == id) {
-                return i;
-            }
-        }
-
-        return -1;
-    }
-
-    public void removeItem(int itemId) {
-        removeItemAtInt(findItemIndex(itemId));
-    }
-
-    private void removeItemAtInt(int index) {
-        if ((index < 0) || (index >= mItems.size())) {
-            return;
-        }
-        mItems.remove(index);
-    }
-
-    public void clear() {
-        mItems.clear();
-    }
-
-    public MenuItem findItem(int id) {
-        final int size = size();
-        for (int i = 0; i < size; i++) {
-            SimpleMenuItem item = mItems.get(i);
-            if (item.getItemId() == id) {
-                return item;
-            }
-        }
-
-        return null;
-    }
-
-    public int size() {
-        return mItems.size();
-    }
-
-    public MenuItem getItem(int index) {
-        return mItems.get(index);
-    }
-
-    // Unsupported operations.
-
-    public SubMenu addSubMenu(CharSequence charSequence) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public SubMenu addSubMenu(int titleRes) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public int addIntentOptions(int i, int i1, int i2, ComponentName componentName,
-            Intent[] intents, Intent intent, int i3, MenuItem[] menuItems) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public void removeGroup(int i) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public void setGroupCheckable(int i, boolean b, boolean b1) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public void setGroupVisible(int i, boolean b) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public void setGroupEnabled(int i, boolean b) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public boolean hasVisibleItems() {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public void close() {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public boolean performShortcut(int i, KeyEvent keyEvent, int i1) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public boolean isShortcutKey(int i, KeyEvent keyEvent) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public boolean performIdentifierAction(int i, int i1) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-
-    public void setQwertyMode(boolean b) {
-        throw new UnsupportedOperationException("This operation is not supported for SimpleMenu");
-    }
-}
diff --git a/android/src/net/sf/openrocket/android/actionbarcompat/SimpleMenuItem.java b/android/src/net/sf/openrocket/android/actionbarcompat/SimpleMenuItem.java
deleted file mode 100644 (file)
index 8af4c5d..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package net.sf.openrocket.android.actionbarcompat;
-
-import android.content.Intent;
-import android.graphics.drawable.Drawable;
-import android.view.ActionProvider;
-import android.view.ContextMenu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-
-/**
- * A <em>really</em> dumb implementation of the {@link android.view.MenuItem} interface, that's only
- * useful for our actionbar-compat purposes. See
- * <code>com.android.internal.view.menu.MenuItemImpl</code> in AOSP for a more complete
- * implementation.
- */
-public class SimpleMenuItem implements MenuItem {
-
-    private SimpleMenu mMenu;
-
-    private final int mId;
-    private final int mOrder;
-    private CharSequence mTitle;
-    private CharSequence mTitleCondensed;
-    private Drawable mIconDrawable;
-    private int mIconResId = 0;
-    private boolean mEnabled = true;
-
-    public SimpleMenuItem(SimpleMenu menu, int id, int order, CharSequence title) {
-        mMenu = menu;
-        mId = id;
-        mOrder = order;
-        mTitle = title;
-    }
-
-    public int getItemId() {
-        return mId;
-    }
-
-    public int getOrder() {
-        return mOrder;
-    }
-
-    public MenuItem setTitle(CharSequence title) {
-        mTitle = title;
-        return this;
-    }
-
-    public MenuItem setTitle(int titleRes) {
-        return setTitle(mMenu.getContext().getString(titleRes));
-    }
-
-    public CharSequence getTitle() {
-        return mTitle;
-    }
-
-    public MenuItem setTitleCondensed(CharSequence title) {
-        mTitleCondensed = title;
-        return this;
-    }
-
-    public CharSequence getTitleCondensed() {
-        return mTitleCondensed != null ? mTitleCondensed : mTitle;
-    }
-
-    public MenuItem setIcon(Drawable icon) {
-        mIconResId = 0;
-        mIconDrawable = icon;
-        return this;
-    }
-
-    public MenuItem setIcon(int iconResId) {
-        mIconDrawable = null;
-        mIconResId = iconResId;
-        return this;
-    }
-
-    public Drawable getIcon() {
-        if (mIconDrawable != null) {
-            return mIconDrawable;
-        }
-
-        if (mIconResId != 0) {
-            return mMenu.getResources().getDrawable(mIconResId);
-        }
-
-        return null;
-    }
-
-    public MenuItem setEnabled(boolean enabled) {
-        mEnabled = enabled;
-        return this;
-    }
-
-    public boolean isEnabled() {
-        return mEnabled;
-    }
-
-    // No-op operations. We use no-ops to allow inflation from menu XML.
-
-    public int getGroupId() {
-        // Noop
-        return 0;
-    }
-
-    public View getActionView() {
-        // Noop
-        return null;
-    }
-
-    public MenuItem setActionProvider(ActionProvider actionProvider) {
-        // Noop
-        return this;
-    }
-
-    public ActionProvider getActionProvider() {
-        // Noop
-        return null;
-    }
-
-    public boolean expandActionView() {
-        // Noop
-        return false;
-    }
-
-    public boolean collapseActionView() {
-        // Noop
-        return false;
-    }
-
-    public boolean isActionViewExpanded() {
-        // Noop
-        return false;
-    }
-
-    public MenuItem setOnActionExpandListener(OnActionExpandListener onActionExpandListener) {
-        // Noop
-        return this;
-    }
-
-    public MenuItem setIntent(Intent intent) {
-        // Noop
-        return this;
-    }
-
-       public Intent getIntent() {
-        // Noop
-        return null;
-    }
-
-    public MenuItem setShortcut(char c, char c1) {
-        // Noop
-        return this;
-    }
-
-    public MenuItem setNumericShortcut(char c) {
-        // Noop
-        return this;
-    }
-
-    public char getNumericShortcut() {
-        // Noop
-        return 0;
-    }
-
-    public MenuItem setAlphabeticShortcut(char c) {
-        // Noop
-        return this;
-    }
-
-    public char getAlphabeticShortcut() {
-        // Noop
-        return 0;
-    }
-
-    public MenuItem setCheckable(boolean b) {
-        // Noop
-        return this;
-    }
-
-    public boolean isCheckable() {
-        // Noop
-        return false;
-    }
-
-    public MenuItem setChecked(boolean b) {
-        // Noop
-        return this;
-    }
-
-    public boolean isChecked() {
-        // Noop
-        return false;
-    }
-
-    public MenuItem setVisible(boolean b) {
-        // Noop
-        return this;
-    }
-
-    public boolean isVisible() {
-        // Noop
-        return true;
-    }
-
-    public boolean hasSubMenu() {
-        // Noop
-        return false;
-    }
-
-    public SubMenu getSubMenu() {
-        // Noop
-        return null;
-    }
-
-    public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
-        // Noop
-        return this;
-    }
-
-    public ContextMenu.ContextMenuInfo getMenuInfo() {
-        // Noop
-        return null;
-    }
-
-    public void setShowAsAction(int i) {
-        // Noop
-    }
-
-    public MenuItem setShowAsActionFlags(int i) {
-        // Noop
-        return null;
-    }
-
-    public MenuItem setActionView(View view) {
-        // Noop
-        return this;
-    }
-
-    public MenuItem setActionView(int i) {
-        // Noop
-        return this;
-    }
-}
index 62fbddb9d1f5a58ea3ad7b45c41b55d6a3098cfd..a1f5bee9456cafc5670fddbe0332cdc5ef56b133 100644 (file)
@@ -4,6 +4,8 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;\r
 import java.io.ObjectInputStream;\r
 import java.io.ObjectOutputStream;\r
+import java.util.ArrayList;\r
+import java.util.List;\r
 \r
 import net.sf.openrocket.motor.Motor;\r
 import net.sf.openrocket.util.Coordinate;\r
@@ -46,6 +48,25 @@ public abstract class ConversionUtils {
                return s.toString();\r
        }\r
        \r
+       public static List<String> delaysToStringList( double[] delays ) {\r
+               ArrayList<String> list = new ArrayList<String>( delays.length );\r
+               for( double d: delays ) {\r
+                       if ( d == Motor.PLUGGED ) {\r
+                               list.add("P");\r
+                       } else {\r
+                               list.add(String.valueOf(Math.round(d)));\r
+                       }\r
+               }\r
+               return list;\r
+       }\r
+       \r
+       public static double stringToDelay( String s ) {\r
+               if ( "P".equals(s) ) {\r
+                       return Motor.PLUGGED;\r
+               }\r
+               return Long.parseLong(s);\r
+       }\r
+       \r
        static double[] deserializeArrayOfDouble( byte[] bytes ) throws Exception {\r
                double[] data = null;\r
                if (bytes != null ) {\r
index 5ea8caec119477b4c823df30031aae8d30a06ea2..8c865437c8fd4d468918d486e4c95cfcd5dc21db 100644 (file)
@@ -2,6 +2,7 @@ package net.sf.openrocket.android.db;
 \r
 import net.sf.openrocket.android.motor.ExtendedThrustCurveMotor;\r
 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper.LogHelper;\r
 import net.sf.openrocket.motor.Manufacturer;\r
 import net.sf.openrocket.motor.Motor;\r
 import net.sf.openrocket.motor.ThrustCurveMotor;\r
@@ -93,25 +94,24 @@ public class MotorDao {
        \r
        public long insertOrUpdateMotor(ExtendedThrustCurveMotor mi) throws Exception {\r
                ContentValues initialValues = new ContentValues();\r
-               final ThrustCurveMotor tcm = mi.getThrustCurveMotor();\r
                initialValues.put(ID, mi.getId());\r
-               initialValues.put(UNIQUE_NAME, tcm.getManufacturer() + tcm.getDesignation());\r
-               initialValues.put(DIGEST, tcm.getDigest());\r
-               initialValues.put(DESIGNATION, tcm.getDesignation());\r
-               initialValues.put(DELAYS, ConversionUtils.delaysToString(tcm.getStandardDelays()));\r
-               initialValues.put(DIAMETER, tcm.getDiameter());\r
-               initialValues.put(TOTAL_IMPULSE, tcm.getTotalImpulseEstimate());\r
-               initialValues.put(AVG_THRUST, tcm.getAverageThrustEstimate());\r
-               initialValues.put(MAX_THRUST, tcm.getMaxThrustEstimate());\r
-               initialValues.put(BURN_TIME, tcm.getBurnTimeEstimate());\r
-               initialValues.put(LENGTH, tcm.getLength());\r
+               initialValues.put(UNIQUE_NAME, mi.getManufacturer() + mi.getDesignation());\r
+               initialValues.put(DIGEST, mi.getDigest());\r
+               initialValues.put(DESIGNATION, mi.getDesignation());\r
+               initialValues.put(DELAYS, ConversionUtils.delaysToString(mi.getStandardDelays()));\r
+               initialValues.put(DIAMETER, mi.getDiameter());\r
+               initialValues.put(TOTAL_IMPULSE, mi.getTotalImpulseEstimate());\r
+               initialValues.put(AVG_THRUST, mi.getAverageThrustEstimate());\r
+               initialValues.put(MAX_THRUST, mi.getMaxThrustEstimate());\r
+               initialValues.put(BURN_TIME, mi.getBurnTimeEstimate());\r
+               initialValues.put(LENGTH, mi.getLength());\r
                initialValues.put(CASE_INFO, mi.getCaseInfo());\r
-               initialValues.put(TYPE, tcm.getMotorType().name());\r
+               initialValues.put(TYPE, mi.getMotorType().name());\r
                initialValues.put(IMPULSE_CLASS, mi.getImpulseClass());\r
-               initialValues.put(MANUFACTURER, tcm.getManufacturer().getSimpleName());\r
-               initialValues.put(THRUST_DATA, ConversionUtils.serializeArrayOfDouble(tcm.getThrustPoints()));\r
-               initialValues.put(TIME_DATA, ConversionUtils.serializeArrayOfDouble(tcm.getTimePoints()));\r
-               initialValues.put(CG_DATA, ConversionUtils.serializeArrayOfCoordinate(tcm.getCGPoints()));\r
+               initialValues.put(MANUFACTURER, mi.getManufacturer().getSimpleName());\r
+               initialValues.put(THRUST_DATA, ConversionUtils.serializeArrayOfDouble(mi.getThrustPoints()));\r
+               initialValues.put(TIME_DATA, ConversionUtils.serializeArrayOfDouble(mi.getTimePoints()));\r
+               initialValues.put(CG_DATA, ConversionUtils.serializeArrayOfCoordinate(mi.getCGPoints()));\r
                \r
                AndroidLogWrapper.d(MotorDao.class, "insertOrUpdate Motor");\r
                long rv = mDb.insertWithOnConflict(DATABASE_TABLE, null, initialValues, SQLiteDatabase.CONFLICT_REPLACE);\r
@@ -143,7 +143,7 @@ public class MotorDao {
                                /* selection args*/new String[] { groupVal },\r
                                /* groupby */null,\r
                                /* having*/null,\r
-                               /* orderby*/DESIGNATION);\r
+                               /* orderby*/TOTAL_IMPULSE);\r
                \r
        }\r
        \r
@@ -161,7 +161,7 @@ public class MotorDao {
                                /* selection args*/null,\r
                                /* groupby */null,\r
                                /* having*/null,\r
-                               /* orderby*/null,\r
+                               /* orderby*/groupCol,\r
                                /* limit*/null);\r
                \r
        }\r
@@ -183,12 +183,7 @@ public class MotorDao {
        }\r
        \r
        private ExtendedThrustCurveMotor hydrateMotor(Cursor mCursor) throws Exception {\r
-               ExtendedThrustCurveMotor mi = new ExtendedThrustCurveMotor();\r
-               \r
-               mi.setId(mCursor.getLong(mCursor.getColumnIndex(ID)));\r
-               mi.setCaseInfo(mCursor.getString(mCursor.getColumnIndex(CASE_INFO)));\r
-               mi.setImpulseClass(mCursor.getString(mCursor.getColumnIndex(IMPULSE_CLASS)));\r
-               \r
+               ExtendedThrustCurveMotor mi;\r
                {\r
                        String digest = mCursor.getString(mCursor.getColumnIndex(DIGEST));\r
                        String designation = mCursor.getString(mCursor.getColumnIndex(DESIGNATION));\r
@@ -222,7 +217,12 @@ public class MotorDao {
                                        cgData,\r
                                        digest\r
                                        );\r
-                       mi.setThrustCurveMotor(tcm);\r
+                       mi = new ExtendedThrustCurveMotor(tcm);\r
+                       \r
+                       mi.setId(mCursor.getLong(mCursor.getColumnIndex(ID)));\r
+                       mi.setCaseInfo(mCursor.getString(mCursor.getColumnIndex(CASE_INFO)));\r
+                       mi.setImpulseClass(mCursor.getString(mCursor.getColumnIndex(IMPULSE_CLASS)));\r
+                       \r
                }\r
                return mi;\r
                \r
@@ -268,6 +268,9 @@ public class MotorDao {
                        }\r
                        mCursor.moveToFirst();\r
                        return hydrateMotor(mCursor);\r
+               } catch( Exception ex ) {\r
+                       LogHelper.getInstance().debug("whoa!", ex);\r
+                       throw ex;\r
                } finally {\r
                        mCursor.close();\r
                }\r
diff --git a/android/src/net/sf/openrocket/android/events/ChangeEventBroadcastReceiver.java b/android/src/net/sf/openrocket/android/events/ChangeEventBroadcastReceiver.java
new file mode 100644 (file)
index 0000000..69da625
--- /dev/null
@@ -0,0 +1,44 @@
+package net.sf.openrocket.android.events;\r
+\r
+import android.content.BroadcastReceiver;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.content.IntentFilter;\r
+import android.support.v4.content.LocalBroadcastManager;\r
+\r
+public abstract class ChangeEventBroadcastReceiver extends BroadcastReceiver {\r
+\r
+       public void register( Context context ) {\r
+               LocalBroadcastManager.getInstance(context).registerReceiver( this, \r
+                               new IntentFilter(Events.MESSAGE_ACTION) );\r
+       }\r
+       \r
+       public void unregister( Context context ) {\r
+               LocalBroadcastManager.getInstance(context).unregisterReceiver(this);\r
+       }\r
+\r
+       @Override\r
+       public void onReceive(Context context, Intent intent) {\r
+               \r
+               int type = intent.getIntExtra(Events.TYPE, -1);\r
+               switch( type ) {\r
+               case Events.CONFIGS_CHANGED:\r
+                       doMotorConfigsChanged();\r
+                       doSimsChanged();\r
+                       break;\r
+               case Events.SIMS_CHANGED:\r
+                       doSimsChanged();\r
+                       break;\r
+               case Events.SIM_COMPLETE:\r
+                       doSimComplete();\r
+                       break;\r
+               }\r
+       }\r
+\r
+       protected abstract void doSimComplete();\r
+\r
+       protected abstract void doSimsChanged();\r
+       \r
+       protected abstract void doMotorConfigsChanged();\r
+\r
+}\r
diff --git a/android/src/net/sf/openrocket/android/events/Events.java b/android/src/net/sf/openrocket/android/events/Events.java
new file mode 100644 (file)
index 0000000..75114d9
--- /dev/null
@@ -0,0 +1,14 @@
+package net.sf.openrocket.android.events;\r
+\r
+public abstract class Events {\r
+\r
+       public final static int SIMS_CHANGED=0;\r
+       public final static int SIM_COMPLETE=1;\r
+       public final static int CONFIGS_CHANGED=2;\r
+       \r
+       public final static String MESSAGE_ACTION = "net.sf.openrocket.Message";\r
+       \r
+       public final static String TYPE = "type";\r
+       \r
+       \r
+}\r
index 85c51b0243dcfc633fb93efdb0be43e1c79e677f..1ca68f65c3a21a0c34aad10fe045906ef158ca57 100644 (file)
@@ -8,7 +8,6 @@ import java.util.Comparator;
 import java.util.List;\r
 \r
 import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.actionbarcompat.ActionBarListActivity;\r
 import android.app.AlertDialog;\r
 import android.app.Dialog;\r
 import android.content.DialogInterface;\r
@@ -26,7 +25,9 @@ import android.widget.ImageView;
 import android.widget.ListView;\r
 import android.widget.TextView;\r
 \r
-public class SimpleFileBrowser extends ActionBarListActivity {\r
+import com.actionbarsherlock.app.SherlockListActivity;\r
+\r
+public class SimpleFileBrowser extends SherlockListActivity {\r
 \r
        private List<File> path = null;\r
        private final static File root = new File("/");\r
@@ -160,7 +161,7 @@ public class SimpleFileBrowser extends ActionBarListActivity {
                final File file = path.get(position);\r
                if (file.isDirectory()) {\r
                        if (file.canRead())\r
-                               getDir(path.get(position));\r
+                               getDir(file);\r
                        else {\r
                                new AlertDialog.Builder(this).setIcon(R.drawable.or_launcher)\r
                                .setTitle("[" + file.getName() + "] folder can't be read!")\r
@@ -243,13 +244,10 @@ public class SimpleFileBrowser extends ActionBarListActivity {
                                }\r
                        }\r
 \r
-                       // Set the "base directory" thing.\r
+                       // Set the "favorite directory" thing.\r
                        {\r
                                ImageView v = (ImageView) (convertView.findViewById(R.id.filebrowser_list_item_homeicon));\r
-                               if ( !file.isDirectory() ) {\r
-                                       v.setVisibility(View.INVISIBLE);\r
-                                       v.setClickable(false);\r
-                               } else {\r
+                               if ( file.isDirectory() && hasUp && position > 1 ) {\r
                                        v.setVisibility(View.VISIBLE);\r
                                        if ( baseDirName.equals( file.getAbsolutePath() ) )  {\r
                                                v.setSelected(true);\r
@@ -258,6 +256,9 @@ public class SimpleFileBrowser extends ActionBarListActivity {
                                                v.setClickable(true);\r
                                                v.setOnClickListener( new ChangeBaseDirectory(file.getAbsolutePath()));\r
                                        }\r
+                               } else {\r
+                                       v.setVisibility(View.INVISIBLE);\r
+                                       v.setClickable(false);\r
                                }\r
                        }\r
                        return convertView;\r
@@ -277,8 +278,8 @@ public class SimpleFileBrowser extends ActionBarListActivity {
                        if ( v.isSelected() == false ) {\r
                                SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(SimpleFileBrowser.this);\r
                                baseDirName = dirname;\r
-                               pref.edit().putString(baseDirPrefKey, dirname).apply();\r
-                               SimpleFileBrowser.this.getDir(new File(dirname));\r
+                               pref.edit().putString(baseDirPrefKey, dirname).commit();\r
+                               ((BaseAdapter)SimpleFileBrowser.this.getListAdapter()).notifyDataSetChanged();\r
                        }\r
                }\r
                \r
index 53ff92054d3a4689f9236b6a7a77f83b76db6714..eff07756a696c5a4d7e2b202b879d95cb8de07ae 100644 (file)
@@ -98,7 +98,7 @@ public class BurnPlotFragment extends Fragment {
                renderer.setAxesColor(Color.LTGRAY);\r
                renderer.setLabelsColor(Color.LTGRAY);\r
 \r
-               renderer.setChartTitle(motor.getThrustCurveMotor().getManufacturer() + " " + motor.getThrustCurveMotor().getDesignation());\r
+               renderer.setChartTitle(motor.getManufacturer() + " " + motor.getDesignation());\r
 \r
                renderer.setXTitle("time (s)");\r
                renderer.setXLabelsAlign(Align.RIGHT);\r
@@ -122,17 +122,17 @@ public class BurnPlotFragment extends Fragment {
 \r
                XYMultipleSeriesDataset dataset = new XYMultipleSeriesDataset();\r
 \r
-               XYSeries series = new XYSeries(motor.getThrustCurveMotor().getDesignation(), 0);\r
+               XYSeries series = new XYSeries(motor.getDesignation(), 0);\r
                \r
-               double[] timePoints = motor.getThrustCurveMotor().getTimePoints();\r
-               double[] thrustPoints = motor.getThrustCurveMotor().getThrustPoints();\r
+               double[] timePoints = motor.getTimePoints();\r
+               double[] thrustPoints = motor.getThrustPoints();\r
 \r
                // We are going to abuse this loop to also compute the Y axis max.\r
                int maxy = 0;\r
                int datasize = timePoints.length;\r
                for( int i = 0; i<datasize; i++ ) {\r
                        series.add(timePoints[i], thrustPoints[i]);\r
-                       int ceil = new Double(Math.ceil(thrustPoints[i])).intValue();\r
+                       int ceil =(int) Math.ceil(thrustPoints[i]);\r
                        if ( ceil > maxy ) {\r
                                maxy = ceil;\r
                        }\r
@@ -144,7 +144,7 @@ public class BurnPlotFragment extends Fragment {
                if ( maxx >= 2.0 ) {\r
                        maxx = Math.ceil(maxx);\r
                } else {\r
-                       maxx = new Double( Math.ceil(maxx*10.0) ).intValue() /10.0;\r
+                       maxx = Math.ceil(maxx*10.0) /10.0;\r
                }\r
                renderer.setXAxisMax(maxx);\r
                \r
index 41e4c4fda73e157ff9873349144ee6222308d035..cd72be489738a77a14c4617a39a45d68ba9440f7 100644 (file)
@@ -2,12 +2,16 @@ package net.sf.openrocket.android.motor;
 \r
 import net.sf.openrocket.motor.ThrustCurveMotor;\r
 \r
-public class ExtendedThrustCurveMotor {\r
+public class ExtendedThrustCurveMotor extends ThrustCurveMotor {\r
 \r
        private Long id;\r
        private String caseInfo;\r
        private String impulseClass;\r
-       private ThrustCurveMotor thrustCurveMotor;\r
+       \r
+       public ExtendedThrustCurveMotor( ThrustCurveMotor tcm ) {\r
+               super(tcm);\r
+       }\r
+       \r
        /**\r
         * @return the id\r
         */\r
@@ -44,19 +48,6 @@ public class ExtendedThrustCurveMotor {
        public void setImpulseClass(String impulseClass) {\r
                this.impulseClass = impulseClass;\r
        }\r
-       /**\r
-        * @return the thrustCurveMotor\r
-        */\r
-       public ThrustCurveMotor getThrustCurveMotor() {\r
-               return thrustCurveMotor;\r
-       }\r
-       /**\r
-        * @param thrustCurveMotor the thrustCurveMotor to set\r
-        */\r
-       public void setThrustCurveMotor(ThrustCurveMotor thrustCurveMotor) {\r
-               this.thrustCurveMotor = thrustCurveMotor;\r
-       }\r
-       \r
-       \r
+\r
        \r
 }\r
index 2d3f77489aa89723509171fc8cae6f7f1a52b59d..60bb7be1beae87cb9245f416b79c144df8bddfba 100644 (file)
@@ -3,18 +3,19 @@ package net.sf.openrocket.android.motor;
 import net.sf.openrocket.R;\r
 import net.sf.openrocket.android.ActivityHelpers;\r
 import net.sf.openrocket.android.PreferencesActivity;\r
-import net.sf.openrocket.android.actionbarcompat.ActionBarFragmentActivity;\r
 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
 import android.content.Intent;\r
 import android.os.Bundle;\r
 import android.support.v4.app.Fragment;\r
 import android.support.v4.app.FragmentTransaction;\r
-import android.view.Menu;\r
-import android.view.MenuInflater;\r
-import android.view.MenuItem;\r
 import android.view.View;\r
 \r
-public class MotorBrowserActivity extends ActionBarFragmentActivity\r
+import com.actionbarsherlock.app.SherlockFragmentActivity;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+public class MotorBrowserActivity extends SherlockFragmentActivity\r
 implements MotorListFragment.OnMotorSelectedListener\r
 {\r
 \r
@@ -28,7 +29,8 @@ implements MotorListFragment.OnMotorSelectedListener
        public void onCreate(Bundle savedInstanceState) {\r
                super.onCreate(savedInstanceState);\r
                setContentView(R.layout.motorbrowser);\r
-               getActionBarHelper().setDisplayHomeAsUpEnabled(true);\r
+               getSupportActionBar().setDisplayHomeAsUpEnabled(true);\r
+               getSupportActionBar().setTitle(R.string.motorbrowsertitle);\r
                // Only create the motorBrowser fragment if it doesn't already exist.\r
                Fragment motorBrowser = getSupportFragmentManager().findFragmentByTag(MOTOR_LIST_FRAGMENT);\r
                if ( motorBrowser == null ) {\r
@@ -41,7 +43,7 @@ implements MotorListFragment.OnMotorSelectedListener
 \r
        @Override\r
        public boolean onCreateOptionsMenu(Menu menu) {\r
-               MenuInflater inflater = getMenuInflater();\r
+               MenuInflater inflater = getSupportMenuInflater();\r
                inflater.inflate(R.menu.motor_browser_option_menu, menu);\r
                return true;\r
        }\r
@@ -51,7 +53,9 @@ implements MotorListFragment.OnMotorSelectedListener
                AndroidLogWrapper.d(MotorBrowserActivity.class,"onMenuItemSelected" + item.getItemId());\r
                switch(item.getItemId()) {\r
                case android.R.id.home:\r
-                       ActivityHelpers.goHome(this);\r
+                       // we implement home in the motor browser as "back" since then it will return to\r
+                       // either main or the viewer.\r
+                       finish();\r
                        return true;\r
                case R.id.download_from_thrustcurve_menu_option:\r
                        ActivityHelpers.downloadFromThrustcurve(this,DOWNLOAD_REQUEST_CODE);\r
diff --git a/android/src/net/sf/openrocket/android/motor/MotorDelayDialogFragment.java b/android/src/net/sf/openrocket/android/motor/MotorDelayDialogFragment.java
new file mode 100644 (file)
index 0000000..b83c95b
--- /dev/null
@@ -0,0 +1,112 @@
+package net.sf.openrocket.android.motor;\r
+\r
+import java.util.List;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.db.ConversionUtils;\r
+import android.app.AlertDialog;\r
+import android.app.Dialog;\r
+import android.os.Bundle;\r
+import android.support.v4.app.DialogFragment;\r
+import android.view.KeyEvent;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.view.inputmethod.EditorInfo;\r
+import android.widget.ArrayAdapter;\r
+import android.widget.EditText;\r
+import android.widget.ListView;\r
+import android.widget.TextView;\r
+\r
+public class MotorDelayDialogFragment extends DialogFragment \r
+implements View.OnClickListener, TextView.OnEditorActionListener {\r
+\r
+       public interface OnDelaySelectedListener {\r
+               public void onDelaySelected( double delay );\r
+       }\r
+\r
+       private OnDelaySelectedListener delaySelectedListener;\r
+\r
+       public void setDelaySelectedListener(OnDelaySelectedListener delaySelectedListener) {\r
+               this.delaySelectedListener = delaySelectedListener;\r
+       }\r
+\r
+       private final static String delaysArg = "delaysArg";\r
+       \r
+       public static MotorDelayDialogFragment newInstance( double[] delays ) {\r
+               MotorDelayDialogFragment f = new MotorDelayDialogFragment();\r
+               Bundle b = new Bundle();\r
+               b.putDoubleArray(delaysArg, delays);\r
+               f.setArguments(b);\r
+               return f;\r
+       }\r
+\r
+       @Override\r
+       public void onClick(View v) {\r
+               String s = ((TextView)v).getText().toString();\r
+               double value = ConversionUtils.stringToDelay(s);\r
+               if ( delaySelectedListener != null ) {\r
+                       delaySelectedListener.onDelaySelected(value);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {\r
+\r
+               if ( actionId == EditorInfo.IME_ACTION_DONE ) {\r
+                       String s = v.getText().toString();\r
+                       if ( s != null ) { // note requires ems=10\r
+                               long value = Long.parseLong(s);\r
+                               if ( delaySelectedListener != null ) {\r
+                                       delaySelectedListener.onDelaySelected(value);\r
+                               }\r
+                       }\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       @Override\r
+       public Dialog onCreateDialog(Bundle savedInstanceState) {\r
+               \r
+               if (savedInstanceState == null ) {\r
+                       savedInstanceState = getArguments();\r
+               }\r
+               double[] delays = savedInstanceState.getDoubleArray(delaysArg);\r
+               List<String> delayList = ConversionUtils.delaysToStringList(delays);\r
+               \r
+               AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());\r
+               builder.setTitle("Enter or Choose Delay");\r
+               \r
+               LayoutInflater li = getActivity().getLayoutInflater();\r
+               View v = li.inflate(R.layout.motor_config_delay_dialog, null);\r
+               builder.setView(v);\r
+               \r
+               ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,delayList) {\r
+\r
+                       @Override\r
+                       public View getView(int position, View convertView, ViewGroup parent) {\r
+                               if ( convertView == null ) {\r
+                                       convertView = getActivity().getLayoutInflater().inflate( android.R.layout.simple_list_item_1, null);\r
+                               }\r
+                               TextView tv = (TextView) convertView.findViewById(android.R.id.text1);\r
+                               tv.setText( getItem(position) );\r
+                               tv.setOnClickListener( MotorDelayDialogFragment.this );\r
+                               return convertView;\r
+                       }\r
+                       \r
+                       \r
+               };\r
+               \r
+               ListView lv = (ListView) v.findViewById(R.id.motor_config_delay_diag_list);\r
+               lv.setAdapter(listAdapter);\r
+               \r
+               EditText et = (EditText) v.findViewById(R.id.motor_config_delay_diag_edit);\r
+               et.setOnEditorActionListener(MotorDelayDialogFragment.this);\r
+               return builder.create();\r
+               \r
+       }\r
+       \r
+       \r
+       \r
+}\r
index b1fac2cb5e5a1eb2651ef8f80ff858d6ceb59494..5bd42b9af43dca571fc32aa8de6f82539e13679a 100644 (file)
@@ -3,13 +3,12 @@ package net.sf.openrocket.android.motor;
 import net.sf.openrocket.R;\r
 import net.sf.openrocket.android.db.ConversionUtils;\r
 import net.sf.openrocket.android.db.DbAdapter;\r
-import net.sf.openrocket.motor.ThrustCurveMotor;\r
+import net.sf.openrocket.unit.UnitGroup;\r
 import android.os.Bundle;\r
 import android.support.v4.app.DialogFragment;\r
 import android.view.LayoutInflater;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
-import android.widget.Button;\r
 import android.widget.EditText;\r
 \r
 public class MotorDetailsFragment extends DialogFragment {\r
@@ -84,14 +83,13 @@ public class MotorDetailsFragment extends DialogFragment {
        }\r
 \r
        private void init( ) {\r
-               ThrustCurveMotor tcm = motor.getThrustCurveMotor();\r
-               manuField.setText( tcm.getManufacturer().getDisplayName());\r
-               nameField.setText( tcm.getDesignation() );\r
-               delaysField.setText( ConversionUtils.delaysToString(tcm.getStandardDelays()) );\r
+               manuField.setText( motor.getManufacturer().getDisplayName());\r
+               nameField.setText( motor.getDesignation() );\r
+               delaysField.setText( ConversionUtils.delaysToString(motor.getStandardDelays()) );\r
                caseField.setText( motor.getCaseInfo());\r
                impulseClassField.setText( motor.getImpulseClass());\r
-               diameterField.setText( String.valueOf(tcm.getDiameter()*1000.0) );\r
-               lengthField.setText( String.valueOf(tcm.getLength()*1000.0) );\r
+               diameterField.setText( UnitGroup.UNITS_MOTOR_DIMENSIONS.toString(motor.getDiameter()) );\r
+               lengthField.setText( UnitGroup.UNITS_LENGTH.getUnit("mm").toString(motor.getLength()) );\r
        }\r
 \r
        private void saveChanges() {\r
diff --git a/android/src/net/sf/openrocket/android/motor/MotorListDialogFragment.java b/android/src/net/sf/openrocket/android/motor/MotorListDialogFragment.java
new file mode 100644 (file)
index 0000000..680e577
--- /dev/null
@@ -0,0 +1,157 @@
+package net.sf.openrocket.android.motor;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.db.DbAdapter;\r
+import net.sf.openrocket.android.db.MotorDao;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.android.util.PersistentExpandableListView;\r
+import android.app.AlertDialog;\r
+import android.app.Dialog;\r
+import android.content.Context;\r
+import android.database.Cursor;\r
+import android.os.Bundle;\r
+import android.view.View;\r
+import android.widget.ExpandableListView;\r
+import android.widget.ResourceCursorTreeAdapter;\r
+import android.widget.TextView;\r
+\r
+import com.actionbarsherlock.app.SherlockDialogFragment;\r
+\r
+public class MotorListDialogFragment extends SherlockDialogFragment \r
+implements ExpandableListView.OnChildClickListener\r
+{\r
+\r
+       public interface OnMotorSelectedListener {\r
+               public void onMotorSelected( long motorId );\r
+       }\r
+\r
+       private final static String groupColumn = MotorDao.DIAMETER;\r
+\r
+       private DbAdapter mDbHelper;\r
+\r
+       private ExpandableListView list;\r
+\r
+       private OnMotorSelectedListener motorSelectedListener;\r
+\r
+       public void setMotorSelectedListener(\r
+                       OnMotorSelectedListener motorSelectedListener) {\r
+               this.motorSelectedListener = motorSelectedListener;\r
+       }\r
+\r
+       @Override\r
+       public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {\r
+               if( motorSelectedListener != null ) {\r
+                       motorSelectedListener.onMotorSelected(id);\r
+               }\r
+               return true;\r
+       }\r
+\r
+       @Override\r
+       public Dialog onCreateDialog(Bundle savedInstanceState) {\r
+               AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());\r
+               builder.setTitle("Select Motor");\r
+               list = new PersistentExpandableListView(getActivity());\r
+               list.setOnChildClickListener( this );\r
+               refreshData();\r
+               builder.setView( list );\r
+               return builder.create();\r
+       }\r
+\r
+       @Override\r
+       public void onPause() {\r
+               super.onPause();\r
+               mDbHelper.close();\r
+       }\r
+\r
+       public void refreshData() {\r
+               if ( mDbHelper == null ) {\r
+                       mDbHelper = new DbAdapter(getActivity());\r
+               }\r
+               mDbHelper.open();\r
+\r
+               Cursor motorCounter = mDbHelper.getMotorDao().fetchAllMotors();\r
+               int motorCount = motorCounter.getCount();\r
+               motorCounter.close();\r
+               \r
+               if ( motorCount == 0 ) {\r
+                       AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());\r
+                       builder.setTitle("No Motors Found");\r
+                       builder.setMessage("Motors can be downloaded from thrustcurve");\r
+                       builder.setCancelable(true);\r
+                       AlertDialog dialog = builder.create();\r
+                       dialog.setCanceledOnTouchOutside(true);\r
+                       dialog.show();\r
+               }\r
+\r
+               Cursor motorCursor = mDbHelper.getMotorDao().fetchGroups(groupColumn);\r
+               MotorHierarchicalListAdapter mAdapter = new MotorHierarchicalListAdapter( \r
+                               getActivity(),\r
+                               motorCursor,\r
+                               R.layout.motor_list_group,\r
+                               R.layout.motor_list_child);\r
+               list.setAdapter(mAdapter);\r
+       }\r
+\r
+       public class MotorHierarchicalListAdapter extends ResourceCursorTreeAdapter\r
+       {\r
+\r
+               // Note that the constructor does not take a Cursor. This is done to avoid querying the \r
+               // database on the main thread.\r
+               public MotorHierarchicalListAdapter(Context context, Cursor cursor, int groupLayout,\r
+                               int childLayout ) {\r
+\r
+                       super(context, cursor, groupLayout, childLayout);\r
+               }\r
+\r
+               @Override\r
+               protected Cursor getChildrenCursor(Cursor arg0) {\r
+                       AndroidLogWrapper.d(MotorListFragment.class,"getChildrenCursor");\r
+                       String group = arg0.getString(arg0.getColumnIndex(groupColumn));\r
+                       Cursor c = mDbHelper.getMotorDao().fetchAllInGroups(groupColumn,group);\r
+                       return c;\r
+               }\r
+\r
+               @Override\r
+               public long getGroupId(int groupPosition) {\r
+                       return groupPosition;\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see android.widget.CursorTreeAdapter#bindChildView(android.view.View, android.content.Context, android.database.Cursor, boolean)\r
+                */\r
+               @Override\r
+               protected void bindChildView(View arg0, Context arg1, Cursor arg2,\r
+                               boolean arg3) {\r
+\r
+                       TextView manu = (TextView) arg0.findViewById(R.id.motorChildManu);\r
+                       manu.setText( arg2.getString(arg2.getColumnIndex(MotorDao.MANUFACTURER)));\r
+\r
+                       TextView desig = (TextView) arg0.findViewById(R.id.motorChildName);\r
+                       desig.setText( arg2.getString(arg2.getColumnIndex(MotorDao.DESIGNATION)));\r
+\r
+                       TextView delays = (TextView) arg0.findViewById(R.id.motorChildDelays);\r
+                       delays.setText( arg2.getString(arg2.getColumnIndex(MotorDao.DELAYS)));\r
+\r
+                       TextView totImpulse = (TextView) arg0.findViewById(R.id.motorChildImpulse);\r
+                       totImpulse.setText( arg2.getString(arg2.getColumnIndex(MotorDao.TOTAL_IMPULSE)));\r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see android.widget.CursorTreeAdapter#bindGroupView(android.view.View, android.content.Context, android.database.Cursor, boolean)\r
+                */\r
+               @Override\r
+               protected void bindGroupView(View view, Context context, Cursor cursor,\r
+                               boolean isExpanded) {\r
+                       TextView v = (TextView) view.findViewById(R.id.motorGroup);\r
+                       if ( MotorDao.DIAMETER.equals(groupColumn)) {\r
+                               double d = cursor.getDouble( cursor.getColumnIndex(groupColumn));\r
+                               v.setText( String.valueOf(Math.round(d * 1000.0)) + " mm");\r
+                       } else {\r
+                               v.setText( cursor.getString( cursor.getColumnIndex(groupColumn)));\r
+                       }\r
+               }\r
+\r
+       }\r
+\r
+\r
+}\r
index 220eba3f4ca4673b7d6760a1c5fd46f084830d10..efe5f40f16ad7e788604785c194ebdd09f4535f9 100644 (file)
@@ -26,10 +26,6 @@ import android.widget.ResourceCursorTreeAdapter;
 import android.widget.TextView;\r
 \r
 \r
-/*\r
- * TODO - make this work with PersistentExpandableListFragment.\r
- * \r
- */\r
 public class MotorListFragment extends PersistentExpandableListFragment\r
 implements SharedPreferences.OnSharedPreferenceChangeListener\r
 {\r
index a19f2e7c66130cf850e74726f4e6d2e93899c909..ac8f1f993ec6115318971e7d94b10a5900110722 100644 (file)
@@ -1,7 +1,7 @@
 package net.sf.openrocket.android.rocket;\r
 \r
 import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.Application;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
 import net.sf.openrocket.android.rocket.RocketComponentTreeAdapter.RocketComponentWithId;\r
 import net.sf.openrocket.document.OpenRocketDocument;\r
 import net.sf.openrocket.rocketcomponent.Rocket;\r
@@ -31,13 +31,12 @@ public class Component extends Fragment {
        }\r
 \r
        @Override\r
-       public void onActivityCreated(Bundle savedInstanceState) {\r
-               super.onActivityCreated(savedInstanceState);\r
-\r
-               final OpenRocketDocument rocketDocument = ((Application)getActivity().getApplication()).getRocketDocument();\r
+       public void onResume() {\r
+               super.onResume();\r
+               final OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
                componentTree.setAdapter( buildAdapter( rocketDocument.getRocket() ) );\r
        }\r
-       \r
+\r
        private ListAdapter buildAdapter( Rocket rocket ) {\r
 \r
                TreeStateManager<RocketComponentWithId> manager = new InMemoryTreeStateManager<RocketComponentWithId>();\r
diff --git a/android/src/net/sf/openrocket/android/rocket/Configurations.java b/android/src/net/sf/openrocket/android/rocket/Configurations.java
new file mode 100644 (file)
index 0000000..9f381de
--- /dev/null
@@ -0,0 +1,336 @@
+package net.sf.openrocket.android.rocket;\r
+\r
+import java.util.List;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.android.db.DbAdapter;\r
+import net.sf.openrocket.android.motor.ExtendedThrustCurveMotor;\r
+import net.sf.openrocket.android.motor.MotorDelayDialogFragment;\r
+import net.sf.openrocket.android.motor.MotorListDialogFragment;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.android.util.ExpandableListFragment;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.motor.Motor;\r
+import net.sf.openrocket.rocketcomponent.MotorMount;\r
+import net.sf.openrocket.rocketcomponent.RocketComponent;\r
+import net.sf.openrocket.unit.UnitGroup;\r
+import android.app.AlertDialog;\r
+import android.app.Dialog;\r
+import android.content.DialogInterface;\r
+import android.os.Bundle;\r
+import android.support.v4.app.FragmentTransaction;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.BaseExpandableListAdapter;\r
+import android.widget.Button;\r
+import android.widget.ExpandableListAdapter;\r
+import android.widget.ListView;\r
+import android.widget.TextView;\r
+\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+public class Configurations extends ExpandableListFragment {\r
+\r
+       private final static String wizardFrag = "wizardFrag";\r
+       \r
+       @Override\r
+       public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+                       Bundle savedInstanceState) {\r
+               setHasOptionsMenu(true);\r
+               View v = inflater.inflate(R.layout.rocket_configurations, container, false);\r
+\r
+               return v;\r
+       }\r
+\r
+       @Override\r
+       public void onResume() {\r
+               setup();\r
+               super.onResume();\r
+       }\r
+\r
+       @Override\r
+       public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\r
+               inflater.inflate(R.menu.rocket_viewer_configurations_option_menu, menu);\r
+       }\r
+\r
+       @Override\r
+       public boolean onOptionsItemSelected(MenuItem item) {\r
+               switch (item.getItemId())\r
+               {\r
+               case R.id.menu_add:\r
+                       addConfiguration();\r
+                       return true;\r
+               default:\r
+                       return super.onOptionsItemSelected(item);\r
+               }\r
+       }\r
+\r
+       public void refreshConfigsList() {\r
+               setup();\r
+       }\r
+\r
+       private void addConfiguration() {\r
+               CurrentRocketHolder.getCurrentRocket().addNewMotorConfig(getActivity());\r
+       }\r
+       \r
+       private void removeConfiguration( String config ) {\r
+               CurrentRocketHolder.getCurrentRocket().deleteMotorConfig( getActivity(), config );\r
+       }\r
+       \r
+       private static class MotorMountInfo {\r
+\r
+               private RocketComponent mmt;\r
+               private String config;\r
+               private ExtendedThrustCurveMotor motor;\r
+               private double delay;\r
+\r
+               String getMotorMountDescription() {\r
+                       String mmtDesc = mmt.getComponentName();\r
+                       mmtDesc += " (" + UnitGroup.UNITS_MOTOR_DIMENSIONS.toStringUnit( ((MotorMount)mmt).getMotorMountDiameter()) + ")";\r
+                       return mmtDesc;\r
+               }\r
+\r
+               String getMotorDescription() {\r
+                       return motor.getManufacturer().getDisplayName() + " " + motor.getDesignation();\r
+               }\r
+\r
+       }\r
+\r
+       class ChildViewHolder {\r
+               MotorMountInfo info;\r
+               TextView motorMountName;\r
+               Button motorDescription;\r
+               Button motorDelay;\r
+               void setMotor( ExtendedThrustCurveMotor motor ) {\r
+                       this.info.motor = motor;\r
+                       ((MotorMount)info.mmt).setMotor(info.config, motor);\r
+               }\r
+               void setDelay( double delay ) {\r
+                       this.info.delay = delay;\r
+                       ((MotorMount)info.mmt).setMotorDelay(info.config, delay);\r
+               }\r
+       }\r
+\r
+       private void setup() {\r
+               final OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+\r
+               ExpandableListAdapter configurationAdapter = new BaseExpandableListAdapter() {\r
+\r
+                       // Note: the magic 1 you see below is so the "no motors" configuration\r
+                       // does not appear in the configuration list.\r
+                       List<MotorMount> mmts = rocketDocument.getRocket().getMotorMounts();\r
+\r
+                       @Override\r
+                       public int getGroupCount() {\r
+                               // don't show the "no motors" configuration, so we have one less than the\r
+                               // array length.\r
+                               return rocketDocument.getRocket().getMotorConfigurationIDs().length-1;\r
+                       }\r
+\r
+                       @Override\r
+                       public int getChildrenCount(int groupPosition) {\r
+                               return mmts.size();\r
+                       }\r
+\r
+                       @Override\r
+                       public Object getGroup(int groupPosition) {\r
+                               // Skip over the "no motors" configuration\r
+                               String config = rocketDocument.getRocket().getMotorConfigurationIDs()[groupPosition+1];\r
+                               return config;\r
+                       }\r
+\r
+                       @Override\r
+                       public Object getChild(int groupPosition, int childPosition) {\r
+                               MotorMountInfo info = new MotorMountInfo();\r
+                               info.mmt = (RocketComponent)(mmts.get(childPosition));\r
+\r
+                               String config = (String) getGroup(groupPosition);\r
+                               info.config = config;\r
+                               info.motor = (ExtendedThrustCurveMotor) ((MotorMount)info.mmt).getMotor(config);\r
+\r
+                               if ( info.motor != null ) {\r
+                                       info.delay = ((MotorMount)info.mmt).getMotorDelay(config);\r
+                               } else {\r
+                                       info.delay = -1;\r
+                               }\r
+\r
+                               return info;\r
+                       }\r
+\r
+                       @Override\r
+                       public long getGroupId(int groupPosition) {\r
+                               // TODO Auto-generated method stub\r
+                               return 0;\r
+                       }\r
+\r
+                       @Override\r
+                       public long getChildId(int groupPosition, int childPosition) {\r
+                               // TODO Auto-generated method stub\r
+                               return 0;\r
+                       }\r
+\r
+                       @Override\r
+                       public boolean hasStableIds() {\r
+                               // TODO Auto-generated method stub\r
+                               return false;\r
+                       }\r
+\r
+                       @Override\r
+                       public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {\r
+                               if ( convertView == null ) {\r
+                                       convertView = getActivity().getLayoutInflater().inflate(android.R.layout.simple_expandable_list_item_1,null);\r
+                               }\r
+\r
+                               String configDescription = rocketDocument.getRocket().getMotorConfigurationNameOrDescription((String) getGroup(groupPosition));\r
+                               ((TextView)convertView.findViewById(android.R.id.text1)).setText( configDescription );\r
+                               return convertView;\r
+                       }\r
+\r
+                       @Override\r
+                       public View getChildView(int groupPosition, int childPosition,\r
+                                       boolean isLastChild, View convertView, ViewGroup parent) {\r
+                               if ( convertView == null ) {\r
+                                       convertView = getActivity().getLayoutInflater().inflate(R.layout.motor_config_item,null);\r
+                                       ChildViewHolder holder = new ChildViewHolder();\r
+                                       holder.motorMountName = (TextView) convertView.findViewById(R.id.motor_config_motor_mount_name);\r
+                                       holder.motorDescription = (Button) convertView.findViewById(R.id.motor_config_motor_desc);\r
+                                       holder.motorDelay = (Button) convertView.findViewById(R.id.motor_config_motor_delay);\r
+                                       holder.info = (MotorMountInfo) getChild(groupPosition,childPosition);\r
+                                       convertView.setTag(holder);\r
+                               }\r
+\r
+                               ChildViewHolder cvHolder = (ChildViewHolder) convertView.getTag();\r
+\r
+                               cvHolder.motorMountName.setText(cvHolder.info.getMotorMountDescription());\r
+                               cvHolder.motorDescription.setOnClickListener( new MotorWizardOnClickListener() );\r
+                               if ( cvHolder.info.motor == null ) {\r
+                                       cvHolder.motorDelay.setClickable(false);\r
+                                       cvHolder.motorDelay.setOnClickListener(null);\r
+                                       cvHolder.motorDescription.setText(R.string.select_motor);\r
+                               } else {\r
+                                       cvHolder.motorDelay.setClickable(true);\r
+                                       cvHolder.motorDelay.setOnClickListener( new MotorDelayOnClickListener(cvHolder.info.motor) );\r
+                                       cvHolder.motorDescription.setText(cvHolder.info.getMotorDescription());\r
+                               }\r
+                               if( cvHolder.info.delay >=0 ) {\r
+                                       if( cvHolder.info.delay == Motor.PLUGGED ) {\r
+                                               cvHolder.motorDelay.setText("P");\r
+                                       } else {\r
+                                               cvHolder.motorDelay.setText( String.valueOf(Math.round(cvHolder.info.delay)));\r
+                                       }\r
+                               } else {\r
+                                       cvHolder.motorDelay.setText(R.string.select_delay);\r
+                               }\r
+\r
+                               return convertView;\r
+                       }\r
+\r
+                       @Override\r
+                       public boolean isChildSelectable(int groupPosition,     int childPosition) {\r
+                               return false;\r
+                       }\r
+\r
+               };\r
+\r
+               setListAdapter(configurationAdapter);\r
+       }\r
+\r
+       @Override\r
+       public boolean onListItemLongClick(ListView l, View v, int position, long id) {\r
+               \r
+               Object o = getExpandableListAdapter().getGroup(position);\r
+               \r
+               if ( o == null || ! (o instanceof String) ) {\r
+                       return false;\r
+               }\r
+               final String motorConfigId = (String)o;\r
+               \r
+               AlertDialog.Builder b = new AlertDialog.Builder( getActivity() );\r
+               b.setTitle(R.string.DeleteConfigTitle);\r
+               b.setCancelable(true);\r
+               b.setPositiveButton(R.string.Delete, new DialogInterface.OnClickListener() {\r
+                       @Override\r
+                       public void onClick(DialogInterface dialog, int which) {\r
+                               Configurations.this.removeConfiguration(motorConfigId);\r
+                       }\r
+                       \r
+               });\r
+               \r
+               Dialog dialog = b.create();\r
+               \r
+               dialog.setCanceledOnTouchOutside(true);\r
+               dialog.show();\r
+               return true;\r
+       }\r
+\r
+       private class MotorWizardOnClickListener implements View.OnClickListener {\r
+               @Override\r
+               public void onClick(View v) {\r
+                       final ViewGroup parent = (ViewGroup) v.getParent();\r
+                       final ChildViewHolder cvHolder = (ChildViewHolder) parent.getTag();\r
+                       final MotorListDialogFragment f = new MotorListDialogFragment();\r
+                       f.setMotorSelectedListener( new MotorListDialogFragment.OnMotorSelectedListener() {\r
+\r
+                               @Override\r
+                               public void onMotorSelected(long motorId) {\r
+                                       DbAdapter mdbHelper = new DbAdapter(getActivity());\r
+                                       mdbHelper.open();\r
+                                       try {\r
+                                               ExtendedThrustCurveMotor motor = mdbHelper.getMotorDao().fetchMotor(motorId);\r
+                                               cvHolder.setMotor( motor );\r
+                                               ((BaseExpandableListAdapter)Configurations.this.getExpandableListAdapter()).notifyDataSetInvalidated();\r
+                                       } catch (Exception ex) {\r
+                                               AndroidLogWrapper.d(Configurations.class, "BlewUp looking for motor", ex);\r
+                                       } finally {\r
+                                               mdbHelper.close();\r
+                                       }\r
+                                       FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();\r
+                                       ft.remove(f);\r
+                                       ft.commit();\r
+\r
+                               }\r
+                       });\r
+                       FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();\r
+                       ft.add(f, wizardFrag);\r
+                       ft.commit();\r
+               }\r
+\r
+       }\r
+\r
+       private class MotorDelayOnClickListener implements View.OnClickListener {\r
+\r
+               double[] standardDelays;\r
+\r
+               public MotorDelayOnClickListener(ExtendedThrustCurveMotor motor) {\r
+                       super();\r
+                       this.standardDelays = motor.getStandardDelays();\r
+               }\r
+\r
+               @Override\r
+               public void onClick(View v) {\r
+                       final View parent = (View) v.getParent();\r
+                       final ChildViewHolder cvHolder = (ChildViewHolder) parent.getTag();\r
+                       final MotorDelayDialogFragment f = MotorDelayDialogFragment.newInstance(standardDelays);\r
+                       f.setDelaySelectedListener( new MotorDelayDialogFragment.OnDelaySelectedListener() {\r
+\r
+                               @Override\r
+                               public void onDelaySelected(double delay) {\r
+                                       cvHolder.setDelay( delay );\r
+                                       ((BaseExpandableListAdapter)Configurations.this.getExpandableListAdapter()).notifyDataSetInvalidated();\r
+                                       FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();\r
+                                       ft.remove(f);\r
+                                       ft.commit();\r
+\r
+                               }\r
+                       });\r
+                       FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();\r
+                       ft.add(f, wizardFrag);\r
+                       ft.commit();\r
+               }\r
+\r
+       }\r
+}\r
diff --git a/android/src/net/sf/openrocket/android/rocket/ErrorLoadingFileDialogFragment.java b/android/src/net/sf/openrocket/android/rocket/ErrorLoadingFileDialogFragment.java
new file mode 100644 (file)
index 0000000..8a957f8
--- /dev/null
@@ -0,0 +1,59 @@
+package net.sf.openrocket.android.rocket;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import android.app.AlertDialog;\r
+import android.app.Dialog;\r
+import android.content.DialogInterface;\r
+import android.os.Bundle;\r
+\r
+import com.actionbarsherlock.app.SherlockDialogFragment;\r
+\r
+public class ErrorLoadingFileDialogFragment extends SherlockDialogFragment {\r
+\r
+       public static ErrorLoadingFileDialogFragment newInstance( int titleRes, String message ) {\r
+               ErrorLoadingFileDialogFragment dialog = new ErrorLoadingFileDialogFragment();\r
+               Bundle b = new Bundle();\r
+               b.putString("message", message);\r
+               b.putInt("titleRes", titleRes);\r
+               dialog.setArguments(b);\r
+               dialog.setCancelable(true);\r
+               return dialog;\r
+       }\r
+       \r
+\r
+       @Override\r
+       public void onCancel(DialogInterface dialog) {\r
+               ((OpenRocketLoaderActivity)getActivity()).doDismissErrorDialog();\r
+       }\r
+\r
+\r
+       @Override\r
+       public Dialog onCreateDialog(Bundle savedInstanceState) {\r
+               AndroidLogWrapper.d(ErrorLoadingFileDialogFragment.class,"onCreateDialog");\r
+\r
+               String message = getArguments().getString("message");\r
+               final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());\r
+\r
+               if ( getArguments().containsKey("titleRes") ) {\r
+                       int titleRes = getArguments().getInt("titleRes");\r
+                       builder.setTitle(titleRes);\r
+               }\r
+               \r
+               builder.setMessage(message);\r
+               builder.setNeutralButton(R.string.dismiss,  new DialogInterface.OnClickListener() {\r
+\r
+                       @Override\r
+                       public void onClick(DialogInterface arg0, int arg1) {\r
+                               ((OpenRocketLoaderActivity)getActivity()).doDismissErrorDialog();\r
+                       }\r
+\r
+               });\r
+               \r
+               final AlertDialog dialog = builder.create();\r
+               dialog.setOwnerActivity(getActivity());\r
+               return dialog;\r
+       }\r
+\r
+\r
+}\r
index 731800a38d5170982408f1cae87ae40f6d4ed2d3..a0c08eecc9b2f0bfe8135118aa78a3704dea96c3 100644 (file)
@@ -2,80 +2,79 @@ package net.sf.openrocket.android.rocket;
 \r
 import java.util.Set;\r
 \r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
 import net.sf.openrocket.motor.ThrustCurveMotorPlaceholder;\r
 import android.app.AlertDialog;\r
 import android.app.Dialog;\r
 import android.content.DialogInterface;\r
 import android.os.Bundle;\r
-import android.support.v4.app.DialogFragment;\r
 \r
-public class MissingMotorDialogFragment extends DialogFragment {\r
-       \r
-       private final static String MESSAGE_ARG_KEY = "message";\r
+import com.actionbarsherlock.app.SherlockDialogFragment;\r
+\r
+public class MissingMotorDialogFragment extends SherlockDialogFragment {\r
+\r
+       private final static String MESSAGES_ARG_KEY = "messages";\r
 \r
        public static MissingMotorDialogFragment newInstance( Set<ThrustCurveMotorPlaceholder> missingMotors ) {\r
                MissingMotorDialogFragment frag = new MissingMotorDialogFragment();\r
                Bundle b = new Bundle();\r
-               b.putString(MESSAGE_ARG_KEY, buildMessage(missingMotors));\r
+               String[] messages = new String[ missingMotors.size() ];\r
+               int index = 0;\r
+               for( ThrustCurveMotorPlaceholder m : missingMotors ) {\r
+                       messages[index++] = m.getManufacturer() + " " + m.getDesignation();\r
+               }\r
+               b.putStringArray(MESSAGES_ARG_KEY, messages);\r
                frag.setArguments(b);\r
+               frag.setCancelable(false);\r
                return frag;\r
        }\r
 \r
-       private static String buildMessage( Set<ThrustCurveMotorPlaceholder> missingMotors ) {\r
+       private String buildMessage( String[] missingMotors ) {\r
                StringBuilder sb = new StringBuilder();\r
-               sb.append("The following motors are missing:");\r
-               for( ThrustCurveMotorPlaceholder m : missingMotors ) {\r
-                       sb.append("\n").append(m.getManufacturer()).append(" ").append(m.getDesignation());\r
+               sb.append(this.getString(R.string.missingMotorsMessageStart));\r
+               for( String m : missingMotors ) {\r
+                       sb.append("\n").append(m);\r
                }\r
-               sb.append("\nWould you like to download them from Thrustcurve?");\r
+               sb.append("\n").append(this.getString(R.string.missingMotorsMessageEnd));\r
                return sb.toString();\r
        }\r
-       \r
+\r
        @Override\r
-       public void onCreate(Bundle savedInstanceState) {\r
-               super.onCreate(savedInstanceState);\r
-               setRetainInstance(true);\r
-               setCancelable(false);\r
+       public void onCancel(DialogInterface dialog) {\r
+               ((OpenRocketLoaderActivity)getActivity()).doNotFixMissingMotors();\r
+               super.onCancel(dialog);\r
        }\r
 \r
-\r
        @Override\r
        public Dialog onCreateDialog(Bundle savedInstanceState) {\r
 \r
-               String message = getArguments().getString(MESSAGE_ARG_KEY);\r
-               \r
+               AndroidLogWrapper.d(MissingMotorDialogFragment.class,"onCreateDialog");\r
+\r
+               String[] messages = getArguments().getStringArray(MESSAGES_ARG_KEY);\r
+\r
                AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());\r
                //                      .setIcon(android.R.drawable.alert_dialog_icon)\r
-               builder.setTitle("Missing Motors");\r
-               builder.setMessage(message);\r
-               builder.setPositiveButton("OK",\r
+               builder.setTitle(R.string.missingMotors);\r
+               builder.setMessage(buildMessage(messages));\r
+               builder.setPositiveButton(R.string.yes,\r
                                new DialogInterface.OnClickListener() {\r
                        public void onClick(DialogInterface dialog, int whichButton) {\r
                                ((OpenRocketLoaderActivity)getActivity()).doFixMissingMotors();\r
                        }\r
-               }\r
-                               );\r
-               builder.setNegativeButton("Cancel",\r
+               });\r
+\r
+               builder.setNegativeButton(R.string.no,\r
                                new DialogInterface.OnClickListener() {\r
                        public void onClick(DialogInterface dialog, int whichButton) {\r
                                ((OpenRocketLoaderActivity)getActivity()).doNotFixMissingMotors();\r
                        }\r
-               }\r
-                               );\r
-               return builder.create();\r
-       }\r
+               });\r
 \r
-       /**\r
-        * Work around for dialog getting dismissed on orientation change.  See code.google.com/p/android/issues/detail?id=17423\r
-        */\r
-       @Override\r
-       public void onDestroyView() {\r
-               if ( getDialog() != null  && getRetainInstance() ) {\r
-                       getDialog().setDismissMessage(null);\r
-               }\r
-               super.onDestroyView();\r
+               AlertDialog dialog =  builder.create();\r
+               dialog.setOwnerActivity(getActivity());\r
+               return dialog;\r
        }\r
-       \r
-       \r
+\r
 }\r
 \r
diff --git a/android/src/net/sf/openrocket/android/rocket/MotorConfigSpinner.java b/android/src/net/sf/openrocket/android/rocket/MotorConfigSpinner.java
new file mode 100644 (file)
index 0000000..e850178
--- /dev/null
@@ -0,0 +1,87 @@
+package net.sf.openrocket.android.rocket;\r
+\r
+import net.sf.openrocket.rocketcomponent.Rocket;\r
+import android.content.Context;\r
+import android.util.AttributeSet;\r
+import android.widget.ArrayAdapter;\r
+import android.widget.Spinner;\r
+\r
+public class MotorConfigSpinner extends Spinner {\r
+\r
+       public MotorConfigSpinner(Context context, AttributeSet attrs,\r
+                       int defStyle, int mode) {\r
+               super(context, attrs, defStyle, mode);\r
+       }\r
+\r
+       public MotorConfigSpinner(Context context, AttributeSet attrs, int defStyle) {\r
+               super(context, attrs, defStyle);\r
+       }\r
+\r
+       public MotorConfigSpinner(Context context, AttributeSet attrs) {\r
+               super(context, attrs);\r
+       }\r
+\r
+       public MotorConfigSpinner(Context context, int mode) {\r
+               super(context, mode);\r
+       }\r
+\r
+       public MotorConfigSpinner(Context context) {\r
+               super(context);\r
+       }\r
+\r
+       public void createAdapter(Rocket rocket ) {\r
+       \r
+               setAdapter(new MotorConfigSpinnerAdapter(this.getContext(), rocket) );\r
+               \r
+       }\r
+       \r
+       public void setSelectedConfiguration( String configId ) {\r
+               this.setSelection( ((MotorConfigSpinnerAdapter)getAdapter()).getConfigurationPosition( configId ));\r
+       }\r
+       \r
+       public String getSelectedConfiguration() {\r
+               return ((MotorConfigSpinnerAdapter)getAdapter()).getConfiguration( this.getSelectedItemPosition() );\r
+       }\r
+       \r
+       public class MotorConfigSpinnerAdapter extends ArrayAdapter<String> {\r
+\r
+               private String[] motorConfigs;\r
+\r
+               public MotorConfigSpinnerAdapter(Context context, Rocket rocket) {\r
+                       super(context, android.R.layout.simple_spinner_item);\r
+                       setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);\r
+                       motorConfigs = rocket.getMotorConfigurationIDs();\r
+\r
+                       for( String config: motorConfigs ) {\r
+                               this.add(rocket.getMotorConfigurationNameOrDescription(config));\r
+                       }\r
+\r
+               }\r
+\r
+               public int getConfigurationPosition(String configId) {\r
+\r
+                       int selectedIndex = 0;\r
+\r
+                       if ( configId == null ) {\r
+                               return selectedIndex;\r
+                       }\r
+\r
+                       for( String s : motorConfigs ) {\r
+                               // Note - s may be null since it is a valid id.\r
+                               if ( configId.equals(s) ) {\r
+                                       break;\r
+                               }\r
+                               selectedIndex++;\r
+                       }\r
+                       if( selectedIndex >= motorConfigs.length ) {\r
+                               selectedIndex = 0;\r
+                       }\r
+\r
+                       return selectedIndex;\r
+               }\r
+               \r
+               public String getConfiguration( int position ) {\r
+                       return motorConfigs[position];\r
+               }\r
+       }\r
+}\r
index 151a6e0f63753339b2a3111aa1c911f055e3a4a5..9a3a84310d9890cfc508b68abf28f6ef9044e4a2 100644 (file)
@@ -5,52 +5,161 @@ import java.util.Set;
 \r
 import net.sf.openrocket.R;\r
 import net.sf.openrocket.aerodynamics.WarningSet;\r
-import net.sf.openrocket.android.Application;\r
-import net.sf.openrocket.android.actionbarcompat.ActionBarFragmentActivity;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.android.filebrowser.SimpleFileBrowser;\r
 import net.sf.openrocket.android.thrustcurve.TCMissingMotorDownloadAction;\r
 import net.sf.openrocket.android.thrustcurve.TCQueryAction;\r
 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
 import net.sf.openrocket.motor.ThrustCurveMotorPlaceholder;\r
 import net.sf.openrocket.rocketcomponent.Rocket;\r
-import android.app.AlertDialog;\r
-import android.content.DialogInterface;\r
+import android.content.ActivityNotFoundException;\r
 import android.content.Intent;\r
+import android.content.SharedPreferences;\r
+import android.content.res.Resources;\r
 import android.net.Uri;\r
 import android.os.Bundle;\r
+import android.preference.PreferenceManager;\r
 import android.support.v4.app.DialogFragment;\r
 \r
-public class OpenRocketLoaderActivity extends ActionBarFragmentActivity\r
+import com.actionbarsherlock.app.SherlockFragmentActivity;\r
+\r
+public class OpenRocketLoaderActivity extends SherlockFragmentActivity\r
 implements TCQueryAction.OnTCQueryCompleteListener, OpenRocketLoaderFragment.OnOpenRocketFileLoaded\r
 {\r
 \r
+       private static final int PICK_ORK_FILE_RESULT = 1;\r
+\r
        private final static String MISSING_MOTOR_DIAG_FRAGMENT_TAG = "missingmotordialog";\r
        private final static String MISSING_MOTOR_DOWNLOAD_FRAGMENT_TAG = "missingmotortask";\r
 \r
+       /*\r
+        * Set to true when we have started to load a file.  Is saved in InstanceState.\r
+        */\r
+       private boolean isLoading = false;\r
+       /*\r
+        * Set to the Uri of the file we are supposed to load.  Is saved in InstanceState.\r
+        */\r
+       private Uri fileToLoad = null;\r
+       \r
+       protected boolean isLoading() {\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class, "isLoading " + this.hashCode());\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class, "isLoading = " + isLoading);\r
+               return isLoading;\r
+       }\r
+\r
        @Override\r
-       protected void onCreate(Bundle savedInstanceState) {\r
-               super.onCreate(savedInstanceState);\r
-               setTitle("");\r
-               setContentView(R.layout.main);\r
-               if ( savedInstanceState == null || savedInstanceState.getBoolean("isLoading", false) == false ) {\r
-                       Intent i = getIntent();\r
+       protected void onPostCreate(Bundle savedInstanceState) {\r
+               super.onPostCreate(savedInstanceState);\r
+               Intent i = getIntent();\r
+               if (Intent.ACTION_VIEW.equals(i.getAction()) && i.getData() != null ) {\r
                        Uri file = i.getData();\r
-                       loadOrkFile(file);\r
+                       fileToLoad = file;\r
+                       loadOrkFile();\r
                } else {\r
                }\r
        }\r
 \r
        @Override\r
        protected void onSaveInstanceState(Bundle outState) {\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class, "onSaveInstanceState " + this.hashCode());\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class, "isLoading = " + isLoading);\r
+               outState.putBoolean("isLoading", isLoading);\r
+               if ( fileToLoad != null ) {\r
+                       outState.putParcelable("fileToLoad", fileToLoad);\r
+               }\r
                super.onSaveInstanceState(outState);\r
-               outState.putBoolean("isLoading", true);\r
        }\r
 \r
-       private void loadOrkFile( Uri file ) {\r
-               AndroidLogWrapper.d(OpenRocketLoaderActivity.class,"Use ork file: " + file);\r
-               String path = file.getPath();\r
+       @Override\r
+       protected void onRestoreInstanceState(Bundle savedInstanceState) {\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class, "onRestoreInstanceState");\r
+               isLoading = savedInstanceState.getBoolean("isLoading",false);\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class, "isLoading = " + isLoading);\r
+               if ( savedInstanceState.containsKey("fileToLoad") ) {\r
+                       fileToLoad = savedInstanceState.getParcelable("fileToLoad");\r
+               }\r
+               super.onRestoreInstanceState(savedInstanceState);\r
+       }\r
+\r
+       @Override\r
+       protected void onResume() {\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class, "onResume");\r
+               super.onResume();\r
+               // Start loading a file if we have a file and are not already loading one.\r
+               if ( fileToLoad != null && !isLoading ) {\r
+                       loadOrkFile();\r
+               }\r
+       }\r
+\r
+       /* (non-Javadoc)\r
+        * @see android.app.Activity#onActivityResult(int, int, android.content.Intent)\r
+        */\r
+       @Override\r
+       protected void onActivityResult(int requestCode, int resultCode, Intent data) {\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class, "onActivityResult");\r
+               switch ( requestCode ) {\r
+               case PICK_ORK_FILE_RESULT:\r
+                       if(resultCode==RESULT_OK){\r
+                               Uri file = data.getData();\r
+                               fileToLoad = file;\r
+                               // It would be nice to just start loading the file - but that doesn't work correctly.\r
+                               // I'm uncertain if it is a bug in Android 14/15 or a bug in the v4 support library.\r
+                               // essentially what happens is, when the FileBrowserActivity is brought up,\r
+                               // this activity goes through the saveInstanceState calls to push it to the background.\r
+                               // When the FileBrowserActivity returns the result, this.onActivityResult is called\r
+                               // prior to any of the other lifecycle methods (onRestoreInstanceState as documented, but onStart is\r
+                               // a bug. Since onStart hasn't been called, this activity is not able to create fragments - which \r
+                               // are used to indicate progress etc.\r
+                               // Instead of calling loadOrkFile() here, we push the file Uri into a member variable,\r
+                               // then check the member variable in onResume to actuall kick off the work.\r
+                       }\r
+                       break;\r
+               default:\r
+                       super.onActivityResult(requestCode, resultCode, data);\r
+               }\r
+       }\r
+\r
+       protected void pickOrkFiles( ) {\r
+               Resources resources = this.getResources();\r
+               String key = resources.getString(R.string.PreferenceUseInternalFileBrowserOption);\r
+               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);\r
+\r
+               boolean useinternalbrowser = pref.getBoolean(key, true);\r
+\r
+               if ( useinternalbrowser ) {\r
+                       Intent intent = new Intent(OpenRocketLoaderActivity.this, SimpleFileBrowser.class);\r
+                       startActivityForResult(intent,PICK_ORK_FILE_RESULT);\r
+               } else {\r
+                       try {\r
+                               Intent intent = new Intent(Intent.ACTION_GET_CONTENT);\r
+                               intent.setType("file/*");\r
+                               startActivityForResult(intent,PICK_ORK_FILE_RESULT);\r
+                       } catch ( ActivityNotFoundException ex ) { \r
+                               // No activity for ACTION_GET_CONTENT  use internal file browser\r
+                               // update the preference value.\r
+                               pref.edit().putBoolean(key, false).commit();\r
+                               // fire our browser\r
+                               Intent intent = new Intent(OpenRocketLoaderActivity.this, SimpleFileBrowser.class);\r
+                               startActivityForResult(intent,PICK_ORK_FILE_RESULT);\r
+                       }\r
+               }               \r
+       }\r
+\r
+       private void loadOrkFile( ) {\r
+               // a little protection.\r
+               if ( fileToLoad == null ) {\r
+                       return;\r
+               }\r
+               isLoading = true;\r
+               CurrentRocketHolder.getCurrentRocket().setFileUri( fileToLoad );\r
+               AndroidLogWrapper.d(OpenRocketLoaderActivity.class,"Use ork file: " + fileToLoad);\r
+               String path = fileToLoad.getPath();\r
                File orkFile = new File(path);\r
 \r
-               getSupportFragmentManager().beginTransaction().add( OpenRocketLoaderFragment.newInstance(orkFile), "loader").commit();\r
+               // Also need commitAllowingState loss because of a bug in v4 dialog show.\r
+               getSupportFragmentManager().beginTransaction()\r
+                 .add( OpenRocketLoaderFragment.newInstance(orkFile), "loader")\r
+                 .commitAllowingStateLoss();\r
 \r
        }\r
 \r
@@ -62,33 +171,25 @@ implements TCQueryAction.OnTCQueryCompleteListener, OpenRocketLoaderFragment.OnO
         */\r
        public void onOpenRocketFileLoaded(OpenRocketLoaderResult result) {\r
                if ( result.loadingError != null ) {\r
-                       \r
-                       AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(this);\r
-                       dialogBuilder.setTitle("Error Loading File" );\r
-                       dialogBuilder.setMessage( result.loadingError.getLocalizedMessage());\r
-                       dialogBuilder.setOnCancelListener( new DialogInterface.OnCancelListener() {\r
-                               @Override\r
-                               public void onCancel(DialogInterface dialog) {\r
-                                       OpenRocketLoaderActivity.this.finish();\r
-                               }\r
-                       });\r
-                       dialogBuilder.create().show();\r
+\r
+                       ErrorLoadingFileDialogFragment errorDialog = ErrorLoadingFileDialogFragment.newInstance(R.string.loadingErrorMessage, result.loadingError.getLocalizedMessage());\r
+                       errorDialog.show(getSupportFragmentManager(),"errorDialog");\r
 \r
                } else {\r
-                       ((Application)OpenRocketLoaderActivity.this.getApplication()).setRocketDocument( result.rocket );\r
-                       ((Application)OpenRocketLoaderActivity.this.getApplication()).setWarnings( result.warnings );\r
+                       CurrentRocketHolder.getCurrentRocket().setRocketDocument( result.rocket );\r
+                       CurrentRocketHolder.getCurrentRocket().setWarnings( result.warnings );\r
 \r
                        updateMissingMotors();\r
                }\r
        }\r
 \r
        private void updateMissingMotors() {\r
-               Rocket rocket = ((Application)OpenRocketLoaderActivity.this.getApplication()).getRocketDocument().getRocket();\r
+               Rocket rocket = CurrentRocketHolder.getCurrentRocket().getRocketDocument().getRocket();\r
                Set<ThrustCurveMotorPlaceholder> missingMotors = MissingMotorHelpers.findMissingMotors(rocket);\r
 \r
                if ( missingMotors.size() > 0 ) {\r
-                       DialogFragment missingMotorDialog = MissingMotorDialogFragment.newInstance( missingMotors );\r
-                       getSupportFragmentManager().beginTransaction().add(missingMotorDialog, MISSING_MOTOR_DIAG_FRAGMENT_TAG).commit();\r
+                       MissingMotorDialogFragment missingMotorDialog = MissingMotorDialogFragment.newInstance( missingMotors );\r
+                       missingMotorDialog.show(getSupportFragmentManager(), MISSING_MOTOR_DIAG_FRAGMENT_TAG);\r
                        return;\r
                }\r
 \r
@@ -101,8 +202,8 @@ implements TCQueryAction.OnTCQueryCompleteListener, OpenRocketLoaderFragment.OnO
        @Override\r
        public void onTCQueryComplete(String message) {\r
 \r
-               Rocket rocket = ((Application)OpenRocketLoaderActivity.this.getApplication()).getRocketDocument().getRocket();\r
-               WarningSet warnings = ((Application)OpenRocketLoaderActivity.this.getApplication()).getWarnings();\r
+               Rocket rocket = CurrentRocketHolder.getCurrentRocket().getRocketDocument().getRocket();\r
+               WarningSet warnings = CurrentRocketHolder.getCurrentRocket().getWarnings();\r
                // Need to update the motor references.\r
                MissingMotorHelpers.updateMissingMotors(rocket, warnings);\r
 \r
@@ -110,7 +211,7 @@ implements TCQueryAction.OnTCQueryCompleteListener, OpenRocketLoaderFragment.OnO
        }\r
 \r
        private void displayWarningDialog() {\r
-               WarningSet warnings = ((Application)OpenRocketLoaderActivity.this.getApplication()).getWarnings();\r
+               WarningSet warnings = CurrentRocketHolder.getCurrentRocket().getWarnings();\r
                if (warnings == null || warnings.isEmpty()) {\r
                } else {\r
                        DialogFragment newFragment = WarningDialogFragment.newInstance();\r
@@ -122,7 +223,7 @@ implements TCQueryAction.OnTCQueryCompleteListener, OpenRocketLoaderFragment.OnO
        }\r
 \r
        public void doFixMissingMotors() {\r
-               Rocket rocket = ((Application)OpenRocketLoaderActivity.this.getApplication()).getRocketDocument().getRocket();\r
+               Rocket rocket = CurrentRocketHolder.getCurrentRocket().getRocketDocument().getRocket();\r
                Set<ThrustCurveMotorPlaceholder> missingMotors = MissingMotorHelpers.findMissingMotors(rocket);\r
 \r
                TCMissingMotorDownloadAction motorfrag = TCMissingMotorDownloadAction.newInstance( missingMotors );\r
@@ -134,7 +235,13 @@ implements TCQueryAction.OnTCQueryCompleteListener, OpenRocketLoaderFragment.OnO
                displayWarningDialog();\r
        }\r
 \r
+       public void doDismissErrorDialog() {\r
+               isLoading = false;\r
+               fileToLoad = null;\r
+       }\r
+       \r
        public void moveOnToViewer() {\r
+               isLoading = false;\r
                Intent i = new Intent(this,OpenRocketViewer.class);\r
                startActivity(i);\r
                finish();\r
index 99922752a0798cce6243dd1410d101e16f851206..e6dc5dd3b2e751c2af2d0b43fdee85406abe872b 100644 (file)
@@ -2,6 +2,7 @@ package net.sf.openrocket.android.rocket;
 \r
 import java.io.File;\r
 \r
+import net.sf.openrocket.R;\r
 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
 import net.sf.openrocket.android.util.ProgressDialogFragment;\r
 import net.sf.openrocket.document.OpenRocketDocument;\r
@@ -17,12 +18,12 @@ import android.view.LayoutInflater;
 import android.view.View;\r
 import android.view.ViewGroup;\r
 \r
-public class OpenRocketLoaderFragment extends Fragment {\r
+import com.actionbarsherlock.app.SherlockFragment;\r
+\r
+public class OpenRocketLoaderFragment extends SherlockFragment {\r
        \r
        private final static String FILE_ARG_KEY = "file";\r
        \r
-       private final static String LOADING_MESSAGE = "Loading file...";\r
-\r
        public interface OnOpenRocketFileLoaded {\r
                public void onOpenRocketFileLoaded( OpenRocketLoaderResult result );\r
        }\r
@@ -74,7 +75,8 @@ public class OpenRocketLoaderFragment extends Fragment {
                @Override\r
                protected void onPreExecute() {\r
                        super.onPreExecute();\r
-                       DialogFragment newFragment = ProgressDialogFragment.newInstance("", LOADING_MESSAGE);\r
+                       String loading = getActivity().getResources().getString(R.string.loading);\r
+                       DialogFragment newFragment = ProgressDialogFragment.newInstance("", loading);\r
                        newFragment.show(getFragmentManager(), PROGRESS_DIALOG_TAG);\r
                }\r
 \r
@@ -89,6 +91,7 @@ public class OpenRocketLoaderFragment extends Fragment {
                        OpenRocketLoaderResult result = new OpenRocketLoaderResult();\r
                        try {\r
                                OpenRocketDocument rocket = rocketLoader.load(arg0[0], new DatabaseMotorFinderWithMissingMotors());\r
+                               rocket.getDefaultConfiguration().setAllStages();\r
                                result.rocket = rocket;\r
                                result.warnings = rocketLoader.getWarnings();\r
                        } catch (RocketLoadException ex) {\r
@@ -102,10 +105,12 @@ public class OpenRocketLoaderFragment extends Fragment {
                @Override\r
                protected void onPostExecute(OpenRocketLoaderResult result) {\r
                        super.onPostExecute(result);\r
-                       AndroidLogWrapper.d(OpenRocketLoaderActivity.class,"Finished loading " + OpenRocketLoaderTask.this);\r
+                       AndroidLogWrapper.d(OpenRocketLoaderFragment.class,"Finished loading " + OpenRocketLoaderTask.this);\r
                        Fragment progress = getActivity().getSupportFragmentManager().findFragmentByTag(PROGRESS_DIALOG_TAG);\r
                        if ( progress != null ) {\r
-                               ((DialogFragment)progress).dismiss();\r
+                               // Remove the fragment instead of trying to use DialogFragment.dismiss.\r
+                               // If the dialog is now currently shown, dismiss fails.\r
+                               getFragmentManager().beginTransaction().remove(progress).commitAllowingStateLoss();\r
                        }\r
                        if ( listener != null ) {\r
                                listener.onOpenRocketFileLoaded(result);\r
diff --git a/android/src/net/sf/openrocket/android/rocket/OpenRocketSaverFragment.java b/android/src/net/sf/openrocket/android/rocket/OpenRocketSaverFragment.java
new file mode 100644 (file)
index 0000000..6f6745b
--- /dev/null
@@ -0,0 +1,126 @@
+package net.sf.openrocket.android.rocket;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.android.util.ProgressDialogFragment;\r
+import android.app.Activity;\r
+import android.os.AsyncTask;\r
+import android.os.Bundle;\r
+import android.support.v4.app.DialogFragment;\r
+import android.support.v4.app.Fragment;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.view.Window;\r
+\r
+import com.actionbarsherlock.app.SherlockFragmentActivity;\r
+\r
+public class OpenRocketSaverFragment extends Fragment {\r
+       \r
+       public static OpenRocketSaverFragment newInstance( boolean showProgressDialog) {\r
+               OpenRocketSaverFragment frag = new OpenRocketSaverFragment();\r
+               Bundle b = new Bundle();\r
+               b.putBoolean(SHOW_PRGRESS_DIALOG_ARG, showProgressDialog);\r
+               frag.setArguments(b);\r
+               return frag;\r
+       }\r
+       \r
+       public interface OnOpenRocketFileSaved {\r
+               public void onOpenRocketFileSaved( Boolean result );\r
+       }\r
+\r
+       private final static String SHOW_PRGRESS_DIALOG_ARG = "net.sf.openrocket.android.ShowProgressDialog";\r
+       \r
+       private boolean showProgressDialog = true;\r
+       private OpenRocketSaverTask task;\r
+       private OnOpenRocketFileSaved listener;\r
+       \r
+       @Override\r
+       public void onCreate(Bundle savedInstanceState) {\r
+               super.onCreate(savedInstanceState);\r
+               setRetainInstance(true);\r
+               Bundle b = getArguments();\r
+               if ( b != null ) {\r
+                       showProgressDialog = b.getBoolean(SHOW_PRGRESS_DIALOG_ARG, true);\r
+               }\r
+               if ( task == null ) {\r
+                       // since we retain instance state, task will be non-null if it is already loading.\r
+                       task = new OpenRocketSaverTask();\r
+                       task.execute();\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+                       Bundle savedInstanceState) {\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public void onActivityCreated(Bundle arg0) {\r
+               super.onActivityCreated(arg0);\r
+               Activity parent = getActivity();\r
+               if ( parent instanceof OnOpenRocketFileSaved ) {\r
+                       listener = (OnOpenRocketFileSaved) parent;\r
+               }\r
+       }\r
+\r
+       public class OpenRocketSaverTask extends AsyncTask<Void, Void, Boolean> {\r
+               \r
+               private final static String PROGRESS_DIALOG_TAG = "progress_dialog";\r
+               \r
+               @Override\r
+               protected void onPreExecute() {\r
+                       super.onPreExecute();\r
+                       if ( showProgressDialog ) {\r
+                               String savingMessage = getActivity().getResources().getString(R.string.saving);\r
+                               DialogFragment newFragment = ProgressDialogFragment.newInstance("", savingMessage);\r
+                               newFragment.show(getFragmentManager(), PROGRESS_DIALOG_TAG);\r
+                       } else {\r
+                               ((SherlockFragmentActivity)getActivity()).setSupportProgressBarIndeterminate(true);\r
+                               ((SherlockFragmentActivity)getActivity()).setSupportProgress(0);\r
+                       }\r
+                       \r
+               }\r
+\r
+               /* (non-Javadoc)\r
+                * @see android.os.AsyncTask#doInBackground(Params[])\r
+                */\r
+               @Override\r
+               protected Boolean doInBackground(Void... arg0) {\r
+                       AndroidLogWrapper.d(OpenRocketSaverTask.class, "doInBackgroud");\r
+                       \r
+                       try {\r
+                               CurrentRocketHolder.getCurrentRocket().saveOpenRocketDocument();\r
+                               return true;\r
+                       } catch (Throwable ex) {\r
+                               AndroidLogWrapper.e(OpenRocketSaverTask.class, "doInBackground rocketLaoder.load threw {}", ex);\r
+                       }\r
+                       return false;\r
+                       \r
+               }\r
+\r
+               @Override\r
+               protected void onPostExecute(Boolean result) {\r
+                       super.onPostExecute(result);\r
+                       AndroidLogWrapper.d(OpenRocketSaverFragment.class,"Finished saving " + OpenRocketSaverTask.this);\r
+                       if ( showProgressDialog ) {\r
+                               Fragment progress = getActivity().getSupportFragmentManager().findFragmentByTag(PROGRESS_DIALOG_TAG);\r
+                               if ( progress != null ) {\r
+                                       // Remove the fragment instead of trying to use DialogFragment.dismiss.\r
+                                       // If the dialog is now currently shown, dismiss fails.\r
+                                       getFragmentManager().beginTransaction().remove(progress).commitAllowingStateLoss();\r
+                               }\r
+                       } else {\r
+                               ((SherlockFragmentActivity)getActivity()).setSupportProgress(Window.PROGRESS_END);\r
+                               ((SherlockFragmentActivity)getActivity()).setSupportProgressBarVisibility(false);\r
+                       }\r
+                       if ( listener != null ) {\r
+                               listener.onOpenRocketFileSaved(result);\r
+                       }\r
+               }\r
+\r
+       }\r
+\r
+}\r
index 57799332eabde206383570e59c829ce39afe0211..635d5264349e02e4f0b3190fa94820bdd448d30b 100644 (file)
@@ -3,51 +3,124 @@ package net.sf.openrocket.android.rocket;
 \r
 import net.sf.openrocket.R;\r
 import net.sf.openrocket.android.ActivityHelpers;\r
-import net.sf.openrocket.android.Application;\r
-import net.sf.openrocket.android.actionbarcompat.ActionBarFragmentActivity;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.android.events.ChangeEventBroadcastReceiver;\r
 import net.sf.openrocket.android.simulation.SimulationChart;\r
-import net.sf.openrocket.android.simulation.SimulationFragment;\r
 import net.sf.openrocket.android.simulation.SimulationViewActivity;\r
+import net.sf.openrocket.android.simulation.SimulationViewFragment;\r
+import net.sf.openrocket.android.simulation.Simulations;\r
 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
 import net.sf.openrocket.document.Simulation;\r
 import android.app.AlertDialog;\r
+import android.content.DialogInterface;\r
 import android.content.Intent;\r
+import android.content.SharedPreferences;\r
+import android.content.res.Resources;\r
 import android.os.Bundle;\r
+import android.preference.PreferenceManager;\r
 import android.support.v4.app.Fragment;\r
 import android.support.v4.app.FragmentManager;\r
 import android.support.v4.app.FragmentPagerAdapter;\r
 import android.support.v4.app.FragmentTransaction;\r
 import android.support.v4.view.ViewPager;\r
-import android.view.Menu;\r
-import android.view.MenuInflater;\r
-import android.view.MenuItem;\r
 import android.view.View;\r
+import android.widget.Toast;\r
 \r
-public class OpenRocketViewer extends ActionBarFragmentActivity\r
-implements Simulations.OnSimulationSelectedListener\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+import com.actionbarsherlock.view.Window;\r
+\r
+public class OpenRocketViewer extends OpenRocketLoaderActivity\r
+implements Simulations.OnSimulationSelectedListener, OpenRocketSaverFragment.OnOpenRocketFileSaved, SharedPreferences.OnSharedPreferenceChangeListener\r
 {\r
 \r
-       private Application app;\r
+       private final static int OVERVIEW_POS = 0;\r
+       private final static int COMPONENT_POS = 1;\r
+       private final static int SIMS_POS = 2;\r
+       private final static int CONFIGS_POS = 3;\r
+       private final static int TABSIZE = 4;\r
+\r
+       private OpenRocketViewerPagerAdapter viewPagerAdapter;\r
+\r
+       private final static String LOAD_AFTER_SAVE = "net.sf.openrocket.android.loadAfterSave";\r
+       private boolean loadAfterSave = false;\r
+       private String autoSaveEnabledKey;\r
+       private boolean autoSaveEnabled = false;\r
+       \r
+       private RocketChangedEventHandler handler = new RocketChangedEventHandler();\r
+\r
 \r
        @Override\r
        protected void onCreate(Bundle savedInstanceState) {\r
                super.onCreate(savedInstanceState);\r
 \r
-               app = (Application) this.getApplication();\r
+               // If the application sleeps for a long time, the CurrentRocketHolder might get cleaned\r
+               // up.  When this happens, we cannot restore this state, so instead we just\r
+               // go home.\r
+               OpenRocketDocument rocDoc = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+               if ( rocDoc == null ) {\r
+                       AndroidLogWrapper.d(OpenRocketViewer.class, "No document - go home");\r
+                       ActivityHelpers.goHome(this);\r
+                       finish();\r
+                       return;\r
+               }\r
+               if (savedInstanceState != null ) {\r
+                       loadAfterSave = savedInstanceState.getBoolean(LOAD_AFTER_SAVE);\r
+               }\r
+               // Must use com.actionbarsherlock.view.Window.FEATURE_INDETERMINATE_PROGRESS\r
+               requestWindowFeature(Window.FEATURE_PROGRESS);\r
+               setSupportProgressBarIndeterminate(true);\r
+\r
+               setTitle(rocDoc.getRocket().getName());\r
+               getSupportActionBar().setHomeButtonEnabled(true);\r
+\r
                setContentView(R.layout.openrocketviewer);\r
                ViewPager viewPager = (ViewPager)findViewById(R.id.pager);\r
-               viewPager.setAdapter( new OpenRocketViewerPager( this.getSupportFragmentManager()));\r
-               \r
-               setTitle(app.getRocketDocument().getRocket().getName());\r
-               \r
-               getActionBarHelper().setDisplayHomeAsUpEnabled(true);\r
-               \r
+               viewPagerAdapter = new OpenRocketViewerPagerAdapter( this.getSupportFragmentManager() );\r
+               viewPager.setAdapter( viewPagerAdapter );\r
        }\r
-       \r
+\r
+       @Override\r
+       protected void onPause() {\r
+               handler.unregister(this);\r
+               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);\r
+               pref.unregisterOnSharedPreferenceChangeListener(this);\r
+               super.onPause();\r
+       }\r
+\r
+       @Override\r
+       protected void onResume() {\r
+               Resources resources = this.getResources();\r
+               autoSaveEnabledKey = resources.getString(R.string.PreferenceAutoSaveOption);\r
+               SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);\r
+               autoSaveEnabled = pref.getBoolean(autoSaveEnabledKey, false);\r
+\r
+               pref.registerOnSharedPreferenceChangeListener(this);\r
+\r
+               handler.register(this);\r
+               super.onResume();\r
+       }\r
+\r
+       @Override\r
+       protected void onSaveInstanceState(Bundle outState) {\r
+               super.onSaveInstanceState(outState);\r
+               outState.putBoolean(LOAD_AFTER_SAVE, loadAfterSave);\r
+       }\r
+\r
        @Override\r
        public boolean onCreateOptionsMenu(Menu menu) {\r
-               MenuInflater inflater = getMenuInflater();\r
+               MenuInflater inflater = getSupportMenuInflater();\r
                inflater.inflate(R.menu.rocket_viewer_option_menu, menu);\r
+               MenuItem saveAction = menu.findItem(R.id.menu_save);\r
+               if ( CurrentRocketHolder.getCurrentRocket().canSave() ) {\r
+                       saveAction.setVisible(true);\r
+                       saveAction.setShowAsAction( MenuItem.SHOW_AS_ACTION_ALWAYS );\r
+               } else {\r
+                       saveAction.setVisible(false);\r
+                       saveAction.setShowAsAction( MenuItem.SHOW_AS_ACTION_NEVER );\r
+               }\r
                return true;\r
        }\r
 \r
@@ -55,6 +128,31 @@ implements Simulations.OnSimulationSelectedListener
        public boolean onMenuItemSelected(int featureId, MenuItem item) {\r
                AndroidLogWrapper.d(OpenRocketViewer.class,"onMenuItemSelected" + item.getItemId());\r
                switch(item.getItemId()) {\r
+               case R.id.menu_load:\r
+                       if ( CurrentRocketHolder.getCurrentRocket().isModified() ) {\r
+                               AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
+                               builder.setMessage(R.string.loadWarnUnsaved);\r
+                               builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {\r
+                                       @Override\r
+                                       public void onClick(DialogInterface dialog, int which) {\r
+                                               pickOrkFiles();\r
+                                       }\r
+                               });\r
+                               builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {\r
+                                       @Override\r
+                                       public void onClick(DialogInterface dialog, int which) {\r
+                                               OpenRocketViewer.this.loadAfterSave = true;\r
+                                               OpenRocketViewer.this.saveRocketDocument();\r
+                                       }\r
+                               });\r
+                               builder.create().show();\r
+                       } else {\r
+                               pickOrkFiles();\r
+                       }\r
+                       return true;\r
+               case R.id.menu_save:\r
+                       OpenRocketViewer.this.saveRocketDocument();\r
+                       return true;\r
                case android.R.id.home:\r
                        ActivityHelpers.goHome(this);\r
                        return true;\r
@@ -71,24 +169,28 @@ implements Simulations.OnSimulationSelectedListener
                return super.onMenuItemSelected(featureId, item);\r
        }\r
 \r
+       @Override\r
+       public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1) {\r
+               if ( autoSaveEnabledKey.equals(arg1) ) {\r
+                       autoSaveEnabled = arg0.getBoolean(autoSaveEnabledKey, false);\r
+               }\r
+       }\r
+\r
        @Override\r
        public void onSimulationSelected(int simulationId) {\r
-               \r
-               Simulation sim = app.getRocketDocument().getSimulation(simulationId);\r
+\r
+               Simulation sim = CurrentRocketHolder.getCurrentRocket().getRocketDocument().getSimulation(simulationId);\r
                // Check if there is data for this simulation.\r
-               if ( sim.getSimulatedData().getBranchCount() == 0 ) {\r
-                       AlertDialog.Builder builder = new AlertDialog.Builder(this);\r
-                       builder.setMessage("The selected simulation does not have saved data.");\r
-                       builder.setCancelable(true);\r
-                       builder.show();\r
+               if ( sim.getSimulatedData() == null || sim.getSimulatedData().getBranchCount() == 0 ) {\r
+                       // This shouldn't happen because the Simulations list does the check.\r
                        return;\r
                }\r
-               \r
+\r
                View sidepane = findViewById(R.id.sidepane);\r
                if ( /* if multi pane */ sidepane != null ) {\r
                        SimulationChart chart = new SimulationChart(simulationId);\r
 \r
-                       Fragment graph = SimulationFragment.newInstance(chart);\r
+                       Fragment graph = SimulationViewFragment.newInstance(chart);\r
 \r
                        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
                        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);\r
@@ -106,39 +208,96 @@ implements Simulations.OnSimulationSelectedListener
                }\r
        }\r
 \r
-       private class OpenRocketViewerPager extends FragmentPagerAdapter {\r
+       private void saveRocketDocument() {\r
+               getSupportFragmentManager().beginTransaction()\r
+               .add( OpenRocketSaverFragment.newInstance(true), "saver")\r
+               .commitAllowingStateLoss();\r
+       }\r
 \r
-               public OpenRocketViewerPager( FragmentManager fm ) {\r
+       @Override\r
+       public void onOpenRocketFileSaved(Boolean result) {\r
+               invalidateOptionsMenu();\r
+               if ( loadAfterSave ) {\r
+                       loadAfterSave = false;\r
+                       pickOrkFiles();\r
+               }\r
+       }\r
+\r
+       private class RocketChangedEventHandler extends ChangeEventBroadcastReceiver {\r
+\r
+               @Override\r
+               protected void doSimComplete() {\r
+                       if ( autoSaveEnabled && CurrentRocketHolder.getCurrentRocket().canSave() ) {\r
+                               Toast.makeText(OpenRocketViewer.this, R.string.autoSaveMessage, Toast.LENGTH_SHORT).show();\r
+                               OpenRocketViewer.this.saveRocketDocument();\r
+                       }\r
+                       doSimsChanged();\r
+               }\r
+\r
+               @Override\r
+               protected void doSimsChanged() {\r
+                       invalidateOptionsMenu();\r
+                       Simulations sims = (Simulations) viewPagerAdapter.getFragmentAtPos(SIMS_POS);\r
+                       if ( sims != null ) {\r
+                               sims.refreshSimulationList();\r
+                       }\r
+               }\r
+\r
+               @Override\r
+               protected void doMotorConfigsChanged() {\r
+                       invalidateOptionsMenu();\r
+                       Configurations configs = (Configurations) viewPagerAdapter.getFragmentAtPos(CONFIGS_POS);\r
+                       if ( configs != null ) {\r
+                               configs.refreshConfigsList();\r
+                       }\r
+               }\r
+\r
+       };\r
+\r
+\r
+       private class OpenRocketViewerPagerAdapter extends FragmentPagerAdapter {\r
+\r
+               public OpenRocketViewerPagerAdapter( FragmentManager fm ) {\r
                        super(fm);\r
                }\r
                @Override\r
                public int getCount() {\r
-                       return 3;\r
+                       return TABSIZE;\r
                }\r
                @Override\r
                public Fragment getItem( int position ) {\r
                        switch (position) {\r
-                       case 0:\r
+                       case OVERVIEW_POS:\r
                                return new Overview();\r
-                       case 1:\r
+                       case COMPONENT_POS:\r
                                return new Component();\r
-                       case 2:\r
+                       case SIMS_POS:\r
                                return new Simulations();\r
+                       case CONFIGS_POS:\r
+                               return new Configurations();\r
                        }\r
                        return null;\r
                }\r
                @Override\r
                public CharSequence getPageTitle(int position) {\r
                        switch (position) {\r
-                       case 0:\r
+                       case OVERVIEW_POS:\r
                                return "Overview";\r
-                       case 1:\r
+                       case COMPONENT_POS:\r
                                return "Components";\r
-                       case 2:\r
+                       case SIMS_POS:\r
                                return "Simulations";\r
+                       case CONFIGS_POS:\r
+                               return "Configurations";\r
                        }\r
                        return null;\r
                }\r
+\r
+               public Fragment getFragmentAtPos( int pos ) {\r
+                       String tag = "android:switcher:"+R.id.pager+":"+pos;\r
+                       Fragment f = OpenRocketViewer.this.getSupportFragmentManager().findFragmentByTag(tag);\r
+                       return f;\r
+               }\r
        }\r
 \r
 }\r
index 8692abf5a84746802ab2c237deee372d4920d88d..33cedaeb7b9744995bc802f8934a7fd6551a6769 100644 (file)
@@ -5,7 +5,7 @@ import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
 import net.sf.openrocket.aerodynamics.BarrowmanCalculator;\r
 import net.sf.openrocket.aerodynamics.FlightConditions;\r
 import net.sf.openrocket.aerodynamics.WarningSet;\r
-import net.sf.openrocket.android.Application;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
 import net.sf.openrocket.document.OpenRocketDocument;\r
 import net.sf.openrocket.masscalc.BasicMassCalculator;\r
@@ -25,8 +25,6 @@ import android.view.LayoutInflater;
 import android.view.View;\r
 import android.view.ViewGroup;\r
 import android.widget.AdapterView;\r
-import android.widget.ArrayAdapter;\r
-import android.widget.Spinner;\r
 import android.widget.TextView;\r
 \r
 public class Overview extends Fragment\r
@@ -37,7 +35,7 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
        private AerodynamicCalculator aerodynamicCalculator = new BarrowmanCalculator();\r
        private MassCalculator massCalculator  = new BasicMassCalculator();\r
 \r
-       private Spinner configurationSpinner;\r
+       private MotorConfigSpinner configurationSpinner;\r
 \r
 \r
        @Override\r
@@ -45,7 +43,7 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
                        Bundle savedInstanceState) {\r
                AndroidLogWrapper.d(Overview.class, "Created View");\r
                View v = inflater.inflate(R.layout.rocket_overview, container, false);\r
-               configurationSpinner = (Spinner) v.findViewById(R.id.openrocketviewerConfigurationSpinner);\r
+               configurationSpinner = (MotorConfigSpinner) v.findViewById(R.id.openrocketviewerConfigurationSpinner);\r
 \r
                return v;\r
        }\r
@@ -53,10 +51,15 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
        @Override\r
        public void onActivityCreated(Bundle savedInstanceState) {\r
                super.onActivityCreated(savedInstanceState);\r
-               \r
+\r
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());\r
                prefs.registerOnSharedPreferenceChangeListener(this);\r
 \r
+       }\r
+\r
+       @Override\r
+       public void onResume() {\r
+               super.onResume();\r
                setup();\r
 \r
        }\r
@@ -67,7 +70,7 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
 \r
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());\r
                prefs.unregisterOnSharedPreferenceChangeListener(this);\r
-}\r
+       }\r
 \r
        @Override\r
        public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1) {\r
@@ -75,22 +78,19 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
                        setup();\r
                }\r
        }\r
-       \r
+\r
        private void setup() {\r
-               final OpenRocketDocument rocketDocument = ((Application)getActivity().getApplication()).getRocketDocument();\r
-               final Configuration rocketConfiguration = rocketDocument.getDefaultConfiguration();\r
+               final OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
                Rocket rocket = rocketDocument.getRocket();\r
 \r
-               String[] motorConfigs = rocket.getMotorConfigurationIDs();\r
-               ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(getActivity(),R.layout.simple_spinner_item);\r
-               for( String config: motorConfigs ) {\r
-                       spinnerAdapter.add(rocket.getMotorConfigurationNameOrDescription(config));\r
-               }\r
-\r
-               AndroidLogWrapper.d(Overview.class, "spinnerAdapter = " + spinnerAdapter);\r
+               // Find the index of the default configuration so we can preselect it.\r
+               Configuration defaultConfiguration = rocketDocument.getDefaultConfiguration();\r
+               configurationSpinner.createAdapter(rocket);\r
                AndroidLogWrapper.d(Overview.class, "configurationSpinner = " + configurationSpinner);\r
 \r
-               configurationSpinner.setAdapter(spinnerAdapter);\r
+               if ( defaultConfiguration != null ) {\r
+                       configurationSpinner.setSelectedConfiguration(defaultConfiguration.getMotorConfigurationID());\r
+               }\r
                configurationSpinner.setOnItemSelectedListener( new AdapterView.OnItemSelectedListener() {\r
 \r
                        /* (non-Javadoc)\r
@@ -101,16 +101,17 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
                                        int arg2, long arg3) {\r
 \r
                                String selectedConfigId = rocketDocument.getRocket().getMotorConfigurationIDs()[arg2];\r
-                               rocketConfiguration.setMotorConfigurationID(selectedConfigId);\r
-                               Coordinate cp = aerodynamicCalculator.getWorstCP(rocketConfiguration,\r
-                                               new FlightConditions(rocketConfiguration),\r
+                               Configuration config = new Configuration(rocketDocument.getRocket());\r
+                               config.setMotorConfigurationID(selectedConfigId);\r
+                               Coordinate cp = aerodynamicCalculator.getWorstCP(config,\r
+                                               new FlightConditions(config),\r
                                                new WarningSet());\r
 \r
-                               Coordinate cg = massCalculator.getCG(rocketConfiguration, MassCalcType.LAUNCH_MASS);\r
+                               Coordinate cg = massCalculator.getCG(config, MassCalcType.LAUNCH_MASS);\r
 \r
                                Unit lengthUnit = UnitGroup.UNITS_LENGTH.getDefaultUnit();\r
                                Unit massUnit = UnitGroup.UNITS_MASS.getDefaultUnit();\r
-                               Unit stabilityUnit = UnitGroup.stabilityUnits(rocketConfiguration).getDefaultUnit();\r
+                               Unit stabilityUnit = UnitGroup.stabilityUnits(config).getDefaultUnit();\r
 \r
                                ((TextView)getActivity().findViewById(R.id.openrocketviewerCP)).setText(lengthUnit.toStringUnit(cp.x));\r
                                ((TextView)getActivity().findViewById(R.id.openrocketviewerCG)).setText(lengthUnit.toStringUnit(cg.x));\r
@@ -134,7 +135,7 @@ implements SharedPreferences.OnSharedPreferenceChangeListener
 \r
                Unit lengthUnit = UnitGroup.UNITS_LENGTH.getDefaultUnit();\r
                Unit massUnit = UnitGroup.UNITS_MASS.getDefaultUnit();\r
-               \r
+\r
                Coordinate cg = RocketUtils.getCG(rocket, MassCalcType.NO_MOTORS);\r
                double length = RocketUtils.getLength(rocket);\r
                ((TextView)getActivity().findViewById(R.id.openrocketviewerDesigner)).setText(rocket.getDesigner());\r
index 9cf216bed11686cc7dba6d20086ee14c420bcadd..4bcd6fde6c7b123873adaa13a8e79787e5dba73f 100644 (file)
@@ -4,13 +4,11 @@ import net.sf.openrocket.R;
 import net.sf.openrocket.android.rocket.RocketComponentTreeAdapter.RocketComponentWithId;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import pl.polidea.treeview.AbstractTreeViewAdapter;
-import pl.polidea.treeview.InMemoryTreeStateManager;
 import pl.polidea.treeview.TreeNodeInfo;
 import pl.polidea.treeview.TreeStateManager;
 import android.app.Activity;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 /**
diff --git a/android/src/net/sf/openrocket/android/rocket/Simulations.java b/android/src/net/sf/openrocket/android/rocket/Simulations.java
deleted file mode 100644 (file)
index b306141..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-package net.sf.openrocket.android.rocket;\r
-\r
-import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.Application;\r
-import net.sf.openrocket.android.util.AndroidLogWrapper;\r
-import net.sf.openrocket.document.OpenRocketDocument;\r
-import net.sf.openrocket.document.Simulation;\r
-import net.sf.openrocket.unit.Unit;\r
-import net.sf.openrocket.unit.UnitGroup;\r
-import android.app.Activity;\r
-import android.content.SharedPreferences;\r
-import android.os.Bundle;\r
-import android.preference.PreferenceManager;\r
-import android.support.v4.app.Fragment;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
-import android.widget.AdapterView;\r
-import android.widget.AdapterView.OnItemClickListener;\r
-import android.widget.ArrayAdapter;\r
-import android.widget.ListView;\r
-import android.widget.TextView;\r
-\r
-public class Simulations extends Fragment\r
-implements SharedPreferences.OnSharedPreferenceChangeListener\r
-{\r
-\r
-       public interface OnSimulationSelectedListener {\r
-               public void onSimulationSelected( int simulationId );\r
-       }\r
-\r
-       private ListView simulationList;\r
-       private OnSimulationSelectedListener listener;\r
-\r
-       @Override\r
-       public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
-                       Bundle savedInstanceState) {\r
-               View v = inflater.inflate(R.layout.rocket_simulations, container, false);\r
-               simulationList = (ListView) v.findViewById(R.id.openrocketviewerSimulationList);\r
-\r
-               return v;\r
-       }\r
-\r
-       @Override\r
-       public void onAttach(Activity activity) {\r
-               super.onAttach(activity);\r
-               if ( activity instanceof OnSimulationSelectedListener ) {\r
-                       listener = (OnSimulationSelectedListener) activity;\r
-               }\r
-       }\r
-\r
-\r
-       public void setListener(OnSimulationSelectedListener listener) {\r
-               this.listener = listener;\r
-       }\r
-\r
-       @Override\r
-       public void onActivityCreated(Bundle savedInstanceState) {\r
-               super.onActivityCreated(savedInstanceState);\r
-\r
-               SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());\r
-               prefs.registerOnSharedPreferenceChangeListener(this);\r
-\r
-               setup();\r
-\r
-       }\r
-\r
-       @Override\r
-       public void onDestroy() {\r
-               super.onDestroy();\r
-\r
-               SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());\r
-               prefs.unregisterOnSharedPreferenceChangeListener(this);\r
-       }\r
-\r
-       @Override\r
-       public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1) {\r
-               if ( this.isVisible() ) {\r
-                       setup();\r
-               }\r
-       }\r
-\r
-\r
-       private void setup() {\r
-               final OpenRocketDocument rocketDocument = ((Application)getActivity().getApplication()).getRocketDocument();\r
-               AndroidLogWrapper.d(Simulations.class,"activity = {0}", this.getActivity());\r
-\r
-               ArrayAdapter<Simulation> sims = new ArrayAdapter<Simulation>(this.getActivity(),android.R.layout.simple_list_item_2,rocketDocument.getSimulations()) {\r
-\r
-                       @Override\r
-                       public View getView(int position, View convertView,     ViewGroup parent) {\r
-                               View v = convertView;\r
-                               if ( v == null ) {\r
-                                       LayoutInflater li = getActivity().getLayoutInflater();\r
-                                       v = li.inflate(android.R.layout.simple_list_item_2,null);\r
-                               }\r
-                               Simulation sim = this.getItem(position);\r
-                               ((TextView)v.findViewById(android.R.id.text1)).setText( sim.getName() );\r
-                               StringBuilder sb = new StringBuilder();\r
-                               sb.append("motors: ").append(sim.getConfiguration().getMotorConfigurationDescription());\r
-                               Unit distanceUnit = UnitGroup.UNITS_DISTANCE.getDefaultUnit();\r
-                               sb.append(" apogee: ").append( distanceUnit.toStringUnit(sim.getSimulatedData().getMaxAltitude()));\r
-                               sb.append(" time: ").append(sim.getSimulatedData().getFlightTime()).append("s");\r
-                               ((TextView)v.findViewById(android.R.id.text2)).setText( sb.toString() );\r
-                               return v;\r
-                       }\r
-\r
-               };\r
-               simulationList.setOnItemClickListener( new OnItemClickListener() {\r
-                       @Override\r
-                       public void onItemClick(AdapterView l, View v, int position, long id) {\r
-                               if (listener != null ) {\r
-                                       listener.onSimulationSelected(position);\r
-                               }\r
-                       }\r
-\r
-               });\r
-               simulationList.setAdapter(sims);\r
-\r
-       }\r
-\r
-}\r
index bab2cc916170a096e78333e90da253f511230ac8..891062bfe0ca28e49cd43cfd537c502a05c93a32 100644 (file)
@@ -2,7 +2,7 @@ package net.sf.openrocket.android.rocket;
 \r
 import net.sf.openrocket.aerodynamics.Warning;\r
 import net.sf.openrocket.aerodynamics.WarningSet;\r
-import net.sf.openrocket.android.Application;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
 import android.app.AlertDialog;\r
 import android.app.Dialog;\r
 import android.content.DialogInterface;\r
@@ -15,6 +15,7 @@ public class WarningDialogFragment extends DialogFragment {
                WarningDialogFragment frag = new WarningDialogFragment();\r
                Bundle args = new Bundle();\r
                frag.setArguments(args);\r
+               frag.setCancelable(false);\r
                return frag;\r
        }\r
 \r
@@ -24,7 +25,7 @@ public class WarningDialogFragment extends DialogFragment {
                AlertDialog.Builder builder =  new AlertDialog.Builder(getActivity());\r
                //                      .setIcon(android.R.drawable.alert_dialog_icon)\r
                builder.setTitle("Warnings");\r
-               WarningSet warnings = ((Application)(getActivity().getApplication())).getWarnings();\r
+               WarningSet warnings = CurrentRocketHolder.getCurrentRocket().getWarnings();\r
                StringBuilder message = new StringBuilder();\r
                for ( Warning w : warnings ) {\r
                        message.append(w.toString()).append("\n");\r
@@ -35,11 +36,7 @@ public class WarningDialogFragment extends DialogFragment {
                                ((OpenRocketLoaderActivity)getActivity()).moveOnToViewer();\r
                        }\r
                });\r
-               builder.setOnCancelListener(new DialogInterface.OnCancelListener() {\r
-                       public void onCancel(DialogInterface dialog) {\r
-                               ((OpenRocketLoaderActivity)getActivity()).moveOnToViewer();\r
-                       }\r
-               });\r
-               return builder.create();\r
+               Dialog dialog = builder.create();\r
+               return dialog;\r
        }\r
 }\r
diff --git a/android/src/net/sf/openrocket/android/simservice/SimulationService.java b/android/src/net/sf/openrocket/android/simservice/SimulationService.java
new file mode 100644 (file)
index 0000000..9a1dd49
--- /dev/null
@@ -0,0 +1,96 @@
+package net.sf.openrocket.android.simservice;\r
+\r
+import java.util.List;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.document.Simulation;\r
+import net.sf.openrocket.simulation.customexpression.CustomExpression;\r
+import net.sf.openrocket.simulation.customexpression.CustomExpressionSimulationListener;\r
+import net.sf.openrocket.simulation.exception.SimulationException;\r
+import net.sf.openrocket.simulation.listeners.SimulationListener;\r
+import android.app.IntentService;\r
+import android.app.Notification;\r
+import android.app.PendingIntent;\r
+import android.content.Context;\r
+import android.content.Intent;\r
+import android.os.IBinder;\r
+import android.widget.Toast;\r
+\r
+public class SimulationService extends IntentService {\r
+\r
+       // We use an id (from a dummy string) as the notificationID because it is unique.\r
+       private final static int notificationID = R.string.SimulationServiceNotificationID;\r
+       \r
+       private Notification notification;\r
+       \r
+       public static void executeSimulationTask( Context c, SimulationTask t ) {\r
+               AndroidLogWrapper.d(SimulationService.class, "Submitting simulation " + t.simulationId );\r
+\r
+               CurrentRocketHolder.getCurrentRocket().lockSimulation( c, t.simulationId );\r
+               \r
+               Intent intent = new Intent( c, SimulationService.class );\r
+               intent.putExtra("net.sf.openrocket.simulationtask", t);\r
+               c.startService(intent);\r
+       }\r
+       \r
+       public SimulationService() {\r
+               super("OpenRocket Simulation Execution Service");\r
+       }\r
+\r
+       @Override\r
+       protected void onHandleIntent(Intent intent) {\r
+               SimulationTask t = (SimulationTask) intent.getSerializableExtra("net.sf.openrocket.simulationtask");\r
+               try {\r
+                       Simulation sim = CurrentRocketHolder.getCurrentRocket().getRocketDocument().getSimulation(t.simulationId);\r
+\r
+                       List<CustomExpression> exprs = CurrentRocketHolder.getCurrentRocket().getRocketDocument().getCustomExpressions();\r
+                       SimulationListener exprListener = new CustomExpressionSimulationListener(exprs);\r
+\r
+                       AndroidLogWrapper.d(SimulationService.class, "simulating " + t.simulationId );\r
+                       sim.simulate(exprListener);\r
+                       CurrentRocketHolder.getCurrentRocket().unlockSimulation(this, t.simulationId);\r
+               }\r
+               catch (SimulationException simex) {\r
+                       Toast.makeText(this, "Error in simulation:" + simex.getMessage(), Toast.LENGTH_LONG ).show();\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public IBinder onBind(Intent intent) {\r
+               return null;\r
+       }\r
+\r
+       @Override\r
+       public void onCreate() {\r
+               super.onCreate();\r
+               \r
+               this.notification = buildNotification();\r
+               startForeground(notificationID, notification);\r
+               \r
+       }\r
+\r
+       @Override\r
+       public int onStartCommand(Intent intent, int flags, int startId) {\r
+               super.onStartCommand(intent, flags, startId);\r
+               return START_STICKY;\r
+       }\r
+\r
+       \r
+       @Override\r
+       public void onDestroy() {\r
+               super.onDestroy();\r
+               stopForeground(true);\r
+       }\r
+\r
+       private Notification buildNotification( ) {\r
+               String message = "OpenRocket Simulation Execution";\r
+               Notification notification = new Notification(R.drawable.or_launcher, message, System.currentTimeMillis());\r
+               \r
+               notification.flags = Notification.FLAG_NO_CLEAR;\r
+               PendingIntent contentIntent = PendingIntent.getActivity( this, 0 , new Intent( ), PendingIntent.FLAG_UPDATE_CURRENT );\r
+               notification.setLatestEventInfo(this, "OpenRocket", message, contentIntent);\r
+               return notification;\r
+       }\r
+}\r
diff --git a/android/src/net/sf/openrocket/android/simservice/SimulationTask.java b/android/src/net/sf/openrocket/android/simservice/SimulationTask.java
new file mode 100644 (file)
index 0000000..12abc3a
--- /dev/null
@@ -0,0 +1,13 @@
+package net.sf.openrocket.android.simservice;\r
+\r
+import java.io.Serializable;\r
+\r
+public class SimulationTask implements Serializable {\r
+\r
+       int simulationId;\r
+\r
+       public SimulationTask(int simulationId) {\r
+               this.simulationId = simulationId;\r
+       }\r
+       \r
+}\r
index 807c58a77a48c74007ca2f9d709e8e7ac1db27b5..9fa41d7ec15924f73836ef85ed1867d6f9e293d8 100644 (file)
@@ -24,6 +24,7 @@ import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;\r
 import net.sf.openrocket.simulation.FlightDataBranch;\r
 import net.sf.openrocket.simulation.FlightDataType;\r
+import net.sf.openrocket.simulation.FlightEvent;\r
 import net.sf.openrocket.unit.Unit;\r
 \r
 import org.achartengine.chart.LineChart;\r
@@ -51,11 +52,12 @@ import android.graphics.Paint.Align;
  * \r
  */\r
 public class SimulationChart implements Serializable {\r
-       \r
+\r
        private final int simulationIndex;\r
        private transient FlightDataType series1;\r
        private transient FlightDataType series2;\r
-       \r
+       private transient List<FlightEvent> events;\r
+\r
        // Define 4 different colors and point styles to use for the series.\r
        // For now only 2 series are supported though.\r
        private final static int[] colors = new int[] { Color.BLUE, Color.YELLOW, Color.GREEN, Color.RED };\r
@@ -75,10 +77,26 @@ public class SimulationChart implements Serializable {
                this.series1 = series1;\r
        }\r
 \r
+       public FlightDataType getSeries1() {\r
+               return series1;\r
+       }\r
+\r
        public void setSeries2(FlightDataType series2) {\r
                this.series2 = series2;\r
        }\r
 \r
+       public FlightDataType getSeries2() {\r
+               return series2;\r
+       }\r
+\r
+       public void setEvents( List<FlightEvent> events ) {\r
+               this.events = events;\r
+       }\r
+\r
+       public List<FlightEvent> getEvents() {\r
+               return events;\r
+       }\r
+\r
        public FlightDataBranch getFlightDataBranch( OpenRocketDocument rocketDocument ) {\r
                Simulation sim = rocketDocument.getSimulation(simulationIndex);\r
                FlightDataBranch flightDataBranch = sim.getSimulatedData().getBranch(0);\r
@@ -102,6 +120,21 @@ public class SimulationChart implements Serializable {
                        series2 = flightDataBranch.getTypes()[2];\r
                }\r
 \r
+               if ( events == null ) {\r
+                       events = new ArrayList<FlightEvent>();\r
+                       for ( FlightEvent event : flightDataBranch.getEvents() ) {\r
+                               switch( event.getType()) {\r
+                               case LAUNCHROD:\r
+                               case APOGEE:\r
+                               case BURNOUT:\r
+                               case EJECTION_CHARGE:\r
+                                       events.add(event);\r
+                               default:\r
+                                       break;\r
+                               }\r
+                       }\r
+               }\r
+\r
                /*\r
                 * TODO -\r
                 * Figure out why you can pan all over the place even where there are no visible points.\r
@@ -124,6 +157,12 @@ public class SimulationChart implements Serializable {
                renderer.setShowGrid(true);\r
                renderer.setZoomButtonsVisible(true);\r
                renderer.setChartTitle(sim.getName());\r
+               renderer.setShowCustomTextGrid(true);\r
+               renderer.setXLabelsAlign(Align.RIGHT);\r
+               renderer.setXLabelsAngle(90);  // rotate right\r
+               for( FlightEvent event : events ) {\r
+                       renderer.addXTextLabel(event.getTime(), event.getType().toString());\r
+               }\r
 \r
                renderer.setMargins(new int[] { 50, 30, 0, 20 });\r
                {\r
@@ -172,7 +211,7 @@ public class SimulationChart implements Serializable {
 \r
                double ymax = computeMaxValueWithPadding( series1values );\r
                double xmax = Math.ceil( timevalues.get( timevalues.size()-1));\r
-               \r
+\r
                AndroidLogWrapper.d(SimulationChart.class,"ymax = " + ymax);\r
                renderer.setXAxisMax(xmax);\r
                renderer.setYAxisMax(ymax);\r
@@ -197,7 +236,7 @@ public class SimulationChart implements Serializable {
                        addXYSeries(dataset, series2.getName(), timevalues, series2values, 1);\r
                }\r
                XYChart chart = new LineChart(dataset, renderer);\r
-               \r
+\r
                return chart;\r
        }\r
 \r
@@ -227,7 +266,7 @@ public class SimulationChart implements Serializable {
                //  next 100 if 1000 < max < 10,000\r
                //  next 1000 if max >= 10,000\r
                double numdigits = Math.floor(Math.log10(max));\r
-               \r
+\r
                if ( numdigits <= 1.0 ) {\r
                        return 10.0;\r
                } else if ( numdigits <= 3.0 ) {\r
@@ -237,7 +276,7 @@ public class SimulationChart implements Serializable {
                } else {\r
                        return 1000.0 * ( Math.ceil( max / 1000.0 ));\r
                }\r
-               \r
+\r
        }\r
-       \r
+\r
 }\r
diff --git a/android/src/net/sf/openrocket/android/simulation/SimulationEditFragment.java b/android/src/net/sf/openrocket/android/simulation/SimulationEditFragment.java
new file mode 100644 (file)
index 0000000..b66a3d7
--- /dev/null
@@ -0,0 +1,132 @@
+\r
+package net.sf.openrocket.android.simulation;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.android.rocket.MotorConfigSpinner;\r
+import net.sf.openrocket.android.simservice.SimulationService;\r
+import net.sf.openrocket.android.simservice.SimulationTask;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.document.Simulation;\r
+import net.sf.openrocket.simulation.SimulationOptions;\r
+import net.sf.openrocket.unit.UnitGroup;\r
+import android.os.Bundle;\r
+import android.support.v4.app.DialogFragment;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.View.OnClickListener;\r
+import android.view.ViewGroup;\r
+import android.widget.Button;\r
+import android.widget.EditText;\r
+\r
+import com.actionbarsherlock.app.SherlockDialogFragment;\r
+\r
+/**\r
+ * An activity that encapsulates a graphical view of the chart.\r
+ */\r
+public class SimulationEditFragment extends SherlockDialogFragment {\r
+\r
+       private int simulationId;\r
+\r
+       private EditText windspeedField;\r
+       private EditText rodlengthField;\r
+       private EditText rodangleField;\r
+       private EditText roddirectionField;\r
+       private MotorConfigSpinner motorSpinner;\r
+\r
+       public static SimulationEditFragment newInstance( int simulationId ) {\r
+               SimulationEditFragment frag = new SimulationEditFragment();\r
+               Bundle b = new Bundle();\r
+               b.putInt("simulationId", simulationId);\r
+               frag.setArguments(b);\r
+               return frag;\r
+       }\r
+\r
+       @Override\r
+       public void onCreate(Bundle savedInstanceState) {\r
+               super.onCreate(savedInstanceState);\r
+               setStyle(DialogFragment.STYLE_NO_TITLE,getTheme());\r
+\r
+               if ( savedInstanceState != null ) {\r
+                       simulationId = savedInstanceState.getInt("simulationId");\r
+               } else {\r
+                       Bundle b = getArguments();\r
+                       simulationId = b.getInt("simulationId");\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+                       Bundle savedInstanceState) {\r
+               View v = inflater.inflate(R.layout.simulation_condition_dialog, container, false);\r
+               \r
+               Button deleteButton = (Button) v.findViewById(R.id.simulationConditionDelete);\r
+               deleteButton.setOnClickListener( new OnClickListener() {\r
+                       @Override\r
+                       public void onClick(View v) {\r
+                               onDelete();\r
+                       }\r
+               });\r
+               \r
+               Button runButton = (Button) v.findViewById(R.id.simulationConditionRun);\r
+               runButton.setOnClickListener( new OnClickListener() {\r
+                       @Override\r
+                       public void onClick(View v) {\r
+                               onRun();\r
+                       }\r
+               });\r
+\r
+               windspeedField = (EditText) v.findViewById(R.id.simulation_condition_windspeed);\r
+               rodlengthField = (EditText) v.findViewById(R.id.simulation_condition_rodlength);\r
+               rodangleField = (EditText) v.findViewById(R.id.simulation_condition_rodangle);\r
+               roddirectionField = (EditText) v.findViewById(R.id.simulation_condition_roddirection);\r
+\r
+               motorSpinner = (MotorConfigSpinner) v.findViewById(R.id.simulationConditionConfigurationSpinner);\r
+\r
+               OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+\r
+               motorSpinner.createAdapter(rocketDocument.getRocket());\r
+\r
+               Simulation sim = rocketDocument.getSimulation(simulationId);\r
+\r
+               SimulationOptions options = sim.getOptions();\r
+               if ( options != null ) {\r
+                       windspeedField.setText( UnitGroup.UNITS_VELOCITY.toString( options.getWindSpeedAverage() ));\r
+                       rodlengthField.setText( UnitGroup.UNITS_LENGTH.toString( options.getLaunchRodLength() ));\r
+                       rodangleField.setText( UnitGroup.UNITS_ANGLE.toString( options.getLaunchRodAngle() ));\r
+                       roddirectionField.setText( UnitGroup.UNITS_ANGLE.toString( options.getLaunchRodDirection() ));\r
+                       motorSpinner.setSelectedConfiguration(options.getMotorConfigurationID());\r
+               }\r
+\r
+               return v;\r
+       }\r
+\r
+       @Override\r
+       public void onSaveInstanceState(Bundle outState) {\r
+               super.onSaveInstanceState(outState);\r
+               outState.putInt("simulationId", simulationId);\r
+\r
+       }\r
+\r
+       public void onDelete( ) {\r
+               CurrentRocketHolder.getCurrentRocket().deleteSimulation(getActivity(), simulationId);\r
+               getDialog().dismiss();\r
+       }\r
+       \r
+       public void onRun() {\r
+               \r
+               OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+               Simulation sim = rocketDocument.getSimulation(simulationId);\r
+               SimulationOptions options = sim.getOptions();\r
+\r
+               options.setWindSpeedAverage( UnitGroup.UNITS_VELOCITY.fromUnit(Double.parseDouble( windspeedField.getText().toString() )));\r
+               options.setLaunchRodLength( UnitGroup.UNITS_LENGTH.fromUnit(Double.parseDouble( rodlengthField.getText().toString() )));\r
+               options.setLaunchRodAngle( UnitGroup.UNITS_ANGLE.fromUnit(Double.parseDouble( rodangleField.getText().toString() )));\r
+               options.setLaunchRodDirection( UnitGroup.UNITS_ANGLE.fromUnit(Double.parseDouble( roddirectionField.getText().toString() )));\r
+               options.setMotorConfigurationID( motorSpinner.getSelectedConfiguration() );\r
+               \r
+               SimulationTask t = new SimulationTask(simulationId);\r
+               SimulationService.executeSimulationTask(getActivity(), t);\r
+               getDialog().dismiss();\r
+       }\r
+}
\ No newline at end of file
index 21a7e78d9454b68b51135d2b8ef05e792e0b08a9..8fc0d1ba9e1b97d000931ef8e7188cc95d152122 100644 (file)
@@ -1,22 +1,27 @@
 package net.sf.openrocket.android.simulation;\r
 \r
+import java.util.List;\r
+\r
 import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.Application;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
 import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.simulation.FlightDataBranch;\r
+import net.sf.openrocket.simulation.FlightDataType;\r
 import net.sf.openrocket.simulation.FlightEvent;\r
+import net.sf.openrocket.unit.UnitGroup;\r
+import net.sf.openrocket.util.MathUtil;\r
 import android.os.Bundle;\r
 import android.support.v4.app.DialogFragment;\r
 import android.view.LayoutInflater;\r
 import android.view.View;\r
 import android.view.ViewGroup;\r
-import android.widget.ArrayAdapter;\r
-import android.widget.ListView;\r
+import android.widget.TableLayout;\r
 import android.widget.TextView;\r
 \r
 public class SimulationEventsDialog extends DialogFragment {\r
 \r
        private SimulationChart chart;\r
-       private ListView eventList;\r
+       private TableLayout eventList;\r
 \r
        public static SimulationEventsDialog newInstance( SimulationChart chart ) {\r
                SimulationEventsDialog d = new SimulationEventsDialog();\r
@@ -29,32 +34,29 @@ public class SimulationEventsDialog extends DialogFragment {
 \r
                View v = inflater.inflate(R.layout.simulation_event_dialog, container, false);\r
 \r
-               eventList = (ListView) v.findViewById(R.id.simulationEventsList);\r
-\r
-               OpenRocketDocument rocketDocument = ((Application)getActivity().getApplication()).getRocketDocument();\r
-               // Initialize the eventList\r
-               ArrayAdapter<FlightEvent> events = new ArrayAdapter<FlightEvent>(\r
-                               getActivity(),\r
-                               android.R.layout.simple_list_item_1,\r
-                               chart.getFlightDataBranch(rocketDocument).getEvents() ) {\r
-\r
-                       @Override\r
-                       public View getView(int position, View convertView,\r
-                                       ViewGroup parent) {\r
-                               View v = convertView;\r
-                               if ( v == null ) {\r
-                                       LayoutInflater li = inflater;\r
-                                       v = li.inflate(android.R.layout.simple_list_item_1,null);\r
-                               }\r
-                               FlightEvent event = this.getItem(position);\r
-                               ((TextView)v.findViewById(android.R.id.text1)).setText( event.getType().toString() + " " + event.getTime() + " (s)" );\r
-                               return v;\r
-                       }\r
-\r
-               };\r
-               // Events are not selectable for plotting right now.\r
-               //eventList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);\r
-               eventList.setAdapter(events);\r
+               eventList = (TableLayout) v.findViewById(R.id.simulationEventsList);\r
+               eventList.setColumnShrinkable(0, true);\r
+\r
+               final OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+\r
+               List<FlightEvent> events = chart.getFlightDataBranch(rocketDocument).getEvents();\r
+               \r
+               for ( FlightEvent event : events ) {\r
+\r
+                       View tableRow = inflater.inflate(R.layout.simulation_event_item,null);\r
+                       ((TextView)tableRow.findViewById(R.id.eventName)).setText( event.getType().toString() );\r
+                       ((TextView)tableRow.findViewById(R.id.eventTime)).setText( event.getTime() + " (s)" );\r
+                       \r
+                       FlightDataBranch data = chart.getFlightDataBranch(rocketDocument);\r
+                       double vel = MathUtil.interpolate(data.get(FlightDataType.TYPE_TIME), data.get(FlightDataType.TYPE_VELOCITY_TOTAL), event.getTime());\r
+                       ((TextView)tableRow.findViewById(R.id.eventVelocity)).setText( UnitGroup.UNITS_VELOCITY.getDefaultUnit().toStringUnit(vel) );\r
+\r
+                       double alt = MathUtil.interpolate(data.get(FlightDataType.TYPE_TIME), data.get(FlightDataType.TYPE_ALTITUDE), event.getTime());\r
+                       ((TextView)tableRow.findViewById(R.id.eventAltitude)).setText( UnitGroup.UNITS_DISTANCE.getDefaultUnit().toStringUnit(alt) );\r
+\r
+                       eventList.addView( tableRow );\r
+               }\r
+               \r
                return v;\r
        }\r
 \r
diff --git a/android/src/net/sf/openrocket/android/simulation/SimulationFragment.java b/android/src/net/sf/openrocket/android/simulation/SimulationFragment.java
deleted file mode 100644 (file)
index 60c8682..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-\r
-package net.sf.openrocket.android.simulation;\r
-\r
-import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.Application;\r
-import net.sf.openrocket.document.OpenRocketDocument;\r
-\r
-import org.achartengine.GraphicalView;\r
-import org.achartengine.chart.XYChart;\r
-\r
-import android.os.Bundle;\r
-import android.support.v4.app.Fragment;\r
-import android.view.LayoutInflater;\r
-import android.view.Menu;\r
-import android.view.MenuInflater;\r
-import android.view.MenuItem;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
-\r
-/**\r
- * An activity that encapsulates a graphical view of the chart.\r
- */\r
-public class SimulationFragment extends Fragment implements SimulationSeriesDialog.OnConfirmListener {\r
-       \r
-       SimulationChart chart;\r
-\r
-       ViewGroup container;\r
-       \r
-       /** The encapsulated graphical view. */\r
-       private GraphicalView mView;\r
-       /** The chart to be drawn. */\r
-       private XYChart mChart;\r
-\r
-       public static SimulationFragment newInstance( SimulationChart chart ) {\r
-               SimulationFragment frag = new SimulationFragment();\r
-               frag.chart = chart;\r
-               return frag;\r
-       }\r
-\r
-       @Override\r
-       public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r
-               setRetainInstance(true);\r
-               setHasOptionsMenu(true);\r
-               OpenRocketDocument rocketDocument = ((Application)getActivity().getApplication()).getRocketDocument();\r
-\r
-               this.container = container;\r
-               if (savedInstanceState != null ) {\r
-                       chart = (SimulationChart) savedInstanceState.getSerializable("chart");\r
-               }\r
-               mChart = chart.buildChart(rocketDocument);\r
-               mView = new GraphicalView(container.getContext(), mChart);\r
-               return mView;\r
-       }\r
-\r
-       @Override\r
-       public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\r
-               inflater.inflate(R.menu.simulation_option_menu, menu);\r
-       }\r
-\r
-       @Override\r
-       public boolean onOptionsItemSelected(MenuItem item) {\r
-               switch (item.getItemId())\r
-               {\r
-               case R.id.simulation_select_series_menu_option:\r
-                       SimulationSeriesDialog seriesDialog = SimulationSeriesDialog.newInstance(chart);\r
-                       seriesDialog.show(getFragmentManager(), "AbraCadaver");\r
-                       seriesDialog.setOnConfirmListener(this);\r
-                       return true;\r
-               case R.id.simulation_select_events_menu_option:\r
-                       SimulationEventsDialog eventsDialog = SimulationEventsDialog.newInstance(chart);\r
-                       eventsDialog.show(getFragmentManager(), "AbraCadaver");\r
-                       return true;\r
-               default:\r
-                       return super.onOptionsItemSelected(item);\r
-               }\r
-       }\r
-\r
-       @Override\r
-       public void onConfirm() {\r
-               OpenRocketDocument rocketDocument = ((Application)getActivity().getApplication()).getRocketDocument();\r
-\r
-               mChart = chart.buildChart(rocketDocument);\r
-               ViewGroup parent = (ViewGroup) mView.getParent();\r
-               parent.removeView(mView);\r
-               mView = new GraphicalView(container.getContext(), mChart);\r
-               parent.addView(mView);\r
-       }\r
-\r
-       @Override\r
-       public void onSaveInstanceState(Bundle outState) {\r
-               super.onSaveInstanceState(outState);\r
-               outState.putSerializable("chart", chart);\r
-\r
-       }\r
-       \r
-}
\ No newline at end of file
diff --git a/android/src/net/sf/openrocket/android/simulation/SimulationListItem.java b/android/src/net/sf/openrocket/android/simulation/SimulationListItem.java
new file mode 100644 (file)
index 0000000..16d12ba
--- /dev/null
@@ -0,0 +1,91 @@
+package net.sf.openrocket.android.simulation;\r
+\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.document.Simulation;\r
+import net.sf.openrocket.document.Simulation.Status;\r
+import net.sf.openrocket.simulation.FlightData;\r
+import net.sf.openrocket.unit.Unit;\r
+import net.sf.openrocket.unit.UnitGroup;\r
+import android.content.Context;\r
+import android.util.AttributeSet;\r
+import android.view.LayoutInflater;\r
+import android.widget.LinearLayout;\r
+import android.widget.TextView;\r
+\r
+public class SimulationListItem extends LinearLayout {\r
+\r
+       private int[] SIMULATION_INVALID = { R.attr.simulation_invalid };\r
+       private int[] SIMULATION_STALE = { R.attr.simulation_stale };\r
+       \r
+       private TextView text1;\r
+       private TextView text2;\r
+       private Status simStatus;\r
+       \r
+       public SimulationListItem(Context context, AttributeSet attrs, int defStyle) {\r
+               super(context, attrs, defStyle);\r
+               loadViews();\r
+       }\r
+\r
+       public SimulationListItem(Context context, AttributeSet attrs) {\r
+               super(context, attrs);\r
+               loadViews();\r
+       }\r
+\r
+       public SimulationListItem(Context context) {\r
+               this(context, null);\r
+       }\r
+\r
+       public void setSimulation(Simulation sim) {\r
+\r
+               text1.setText( sim.getName() );\r
+\r
+               StringBuilder sb = new StringBuilder();\r
+               String motorConfig = sim.getOptions().getMotorConfigurationID();\r
+               sb.append("motors: ").append(sim.getRocket().getMotorConfigurationNameOrDescription(motorConfig));\r
+               Unit distanceUnit = UnitGroup.UNITS_DISTANCE.getDefaultUnit();\r
+               FlightData flightData  = sim.getSimulatedData();\r
+               if ( flightData != null ) {\r
+                       sb.append(" apogee: ").append( distanceUnit.toStringUnit(flightData.getMaxAltitude()));\r
+                       sb.append(" time: ").append(flightData.getFlightTime()).append("s");\r
+               } else {\r
+                       sb.append(" No simulation data");\r
+               }\r
+               text2.setText( sb.toString() );\r
+               \r
+               simStatus = sim.getStatus();\r
+\r
+               // Refresh the drawable state so that it includes the status if required.\r
+               refreshDrawableState();\r
+\r
+       }\r
+\r
+       private void loadViews() {\r
+               this.setOrientation(LinearLayout.HORIZONTAL);\r
+               \r
+               LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);\r
+               layoutInflater.inflate(R.layout.simulation_list_item, this, true);\r
+\r
+               //        setPadding(fiveDPInPixels, fiveDPInPixels, fiveDPInPixels, fiveDPInPixels);\r
+               //        setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, fiftyDPInPixels));\r
+               //        setBackgroundResource(R.drawable.message_list_item_background);\r
+\r
+               text1 = (TextView) findViewById(android.R.id.text1);\r
+               text2 = (TextView) findViewById(android.R.id.text2);\r
+       }\r
+\r
+       @Override\r
+       protected int[] onCreateDrawableState(int extraSpace) {\r
+        // We are going to add extra state.\r
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);\r
+        if ( simStatus == Status.OUTDATED || simStatus == Status.NOT_SIMULATED ) {\r
+                       return mergeDrawableStates(drawableState, SIMULATION_INVALID );\r
+               \r
+        } else if ( simStatus == Status.LOADED || simStatus == Status.EXTERNAL ) {\r
+                       return mergeDrawableStates(drawableState, SIMULATION_STALE);\r
+        } else {\r
+                       return super.onCreateDrawableState(extraSpace);\r
+               }\r
+       }\r
+\r
+}\r
diff --git a/android/src/net/sf/openrocket/android/simulation/SimulationPlotConfigDialog.java b/android/src/net/sf/openrocket/android/simulation/SimulationPlotConfigDialog.java
new file mode 100644 (file)
index 0000000..d22b8d7
--- /dev/null
@@ -0,0 +1,166 @@
+package net.sf.openrocket.android.simulation;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.simulation.FlightDataBranch;\r
+import net.sf.openrocket.simulation.FlightDataType;\r
+import net.sf.openrocket.simulation.FlightEvent;\r
+import android.app.AlertDialog;\r
+import android.app.Dialog;\r
+import android.os.Bundle;\r
+import android.support.v4.app.DialogFragment;\r
+import android.util.SparseBooleanArray;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.ArrayAdapter;\r
+import android.widget.Button;\r
+import android.widget.ListView;\r
+import android.widget.Spinner;\r
+import android.widget.TextView;\r
+\r
+public class SimulationPlotConfigDialog extends DialogFragment {\r
+       \r
+       public interface OnConfirmListener {\r
+               public void onConfirm();\r
+       }\r
+\r
+       private ListView eventList;\r
+       private Spinner series1Spinner;\r
+       private Spinner series2Spinner;\r
+\r
+       private SimulationChart chart;\r
+       private OnConfirmListener listener;\r
+\r
+       public static SimulationPlotConfigDialog newInstance( SimulationChart chart ) {\r
+               SimulationPlotConfigDialog d = new SimulationPlotConfigDialog();\r
+               d.chart = chart;\r
+               return d;\r
+       }\r
+\r
+       public void setOnConfirmListener(OnConfirmListener listener) {\r
+               this.listener = listener;\r
+       }\r
+\r
+       @Override\r
+       public Dialog onCreateDialog(Bundle savedInstanceState) {\r
+               if (savedInstanceState != null ) {\r
+                       chart = (SimulationChart) savedInstanceState.getSerializable("chart");\r
+               }\r
+               \r
+               AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());\r
+               builder.setTitle(R.string.simulationPlotDialogTitle);\r
+               \r
+               final LayoutInflater inflater = getActivity().getLayoutInflater();\r
+               View v = inflater.inflate(R.layout.simulation_plot_config_dialog, null);\r
+               builder.setView(v);\r
+\r
+               OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+\r
+               Button okButton = (Button) v.findViewById(R.id.simulationOkButton);\r
+               okButton.setOnClickListener( new View.OnClickListener() {\r
+\r
+                       @Override\r
+                       public void onClick(View v) {\r
+                               List<FlightEvent> eventsToShow = new ArrayList<FlightEvent>();\r
+                               {\r
+                                       SparseBooleanArray eventsSelected = eventList.getCheckedItemPositions();\r
+                                       List<FlightEvent> flightEvents = chart.getFlightDataBranch(CurrentRocketHolder.getCurrentRocket().getRocketDocument()).getEvents();\r
+                                       for( int i=0; i< flightEvents.size(); i++ ) {\r
+                                               if ( eventsSelected.get(i) ) {\r
+                                                       FlightEvent event = flightEvents.get(i);\r
+                                                       eventsToShow.add( event );\r
+                                               }\r
+                                       }\r
+                               }\r
+                               chart.setEvents(eventsToShow);\r
+\r
+                               chart.setSeries1((FlightDataType)series1Spinner.getSelectedItem());\r
+                               chart.setSeries2((FlightDataType)series2Spinner.getSelectedItem());\r
+\r
+                               if ( listener != null ) {\r
+                                       listener.onConfirm();\r
+                               }\r
+                               SimulationPlotConfigDialog.this.dismiss();\r
+                       }\r
+                       \r
+               });\r
+\r
+               series1Spinner = (Spinner) v.findViewById(R.id.simulationSeries1);\r
+               series2Spinner = (Spinner) v.findViewById(R.id.simulationSeries2);\r
+\r
+               List<FlightDataType> selectableSeries = new ArrayList<FlightDataType>();\r
+               int index = 0;\r
+               for( FlightDataType fdt : chart.getFlightDataBranch(rocketDocument).getTypes() ) {\r
+                       if ( fdt == FlightDataType.TYPE_TIME ) { \r
+                       } else {\r
+                               selectableSeries.add(fdt);\r
+                       }\r
+                       index++;\r
+               }\r
+               ArrayAdapter<FlightDataType> serieses = new ArrayAdapter<FlightDataType>(getActivity(),android.R.layout.simple_spinner_item,selectableSeries) {\r
+\r
+                       @Override\r
+                       public View getView(int position, View convertView,     ViewGroup parent) {\r
+                               View v = convertView;\r
+                               if ( v == null ) {\r
+                                       LayoutInflater li = inflater;\r
+                                       v = li.inflate(android.R.layout.simple_spinner_item,null);\r
+                               }\r
+                               FlightDataType fdt = this.getItem(position);\r
+                               ((TextView)v.findViewById(android.R.id.text1)).setText( fdt.toString() );\r
+                               return v;\r
+                       }\r
+\r
+               };\r
+               \r
+               series1Spinner.setAdapter(serieses);\r
+               int selection1 = serieses.getPosition(chart.getSeries1());\r
+               series1Spinner.setSelection(selection1);\r
+               series2Spinner.setAdapter(serieses);\r
+               int selection2 = serieses.getPosition(chart.getSeries2());\r
+               series2Spinner.setSelection(selection2);\r
+\r
+               eventList = (ListView) v.findViewById(R.id.simulationEventsList);\r
+\r
+               FlightDataBranch data = chart.getFlightDataBranch(CurrentRocketHolder.getCurrentRocket().getRocketDocument());\r
+               // Initialize the eventList\r
+               \r
+               ArrayAdapter<FlightEvent> events = new ArrayAdapter<FlightEvent>(getActivity(),android.R.layout.simple_list_item_1,data.getEvents()) {\r
+\r
+                       @Override\r
+                       public View getView(int position, View convertView,\r
+                                       ViewGroup parent) {\r
+                               View v = convertView;\r
+                               if ( v == null ) {\r
+                                       LayoutInflater li = inflater;\r
+                                       v = li.inflate(android.R.layout.simple_list_item_multiple_choice,null);\r
+                               }\r
+                               FlightEvent event = this.getItem(position);\r
+                               ((TextView)v.findViewById(android.R.id.text1)).setText( event.getType().toString() + " " + event.getTime() + " (s)" );\r
+                               return v;\r
+                       }\r
+\r
+               };\r
+               eventList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);\r
+               eventList.setAdapter(events);\r
+\r
+               for( FlightEvent evt : chart.getEvents() ) {\r
+                       eventList.setItemChecked( events.getPosition(evt), true);\r
+               }\r
+               \r
+               return builder.create();\r
+\r
+       }\r
+\r
+       @Override\r
+       public void onSaveInstanceState(Bundle arg0) {\r
+               super.onSaveInstanceState(arg0);\r
+               arg0.putSerializable("chart", chart);\r
+       }\r
+\r
+}\r
diff --git a/android/src/net/sf/openrocket/android/simulation/SimulationSeriesDialog.java b/android/src/net/sf/openrocket/android/simulation/SimulationSeriesDialog.java
deleted file mode 100644 (file)
index bdcb4d4..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-package net.sf.openrocket.android.simulation;\r
-\r
-import java.util.ArrayList;\r
-import java.util.List;\r
-\r
-import net.sf.openrocket.R;\r
-import net.sf.openrocket.android.Application;\r
-import net.sf.openrocket.document.OpenRocketDocument;\r
-import net.sf.openrocket.simulation.FlightDataType;\r
-import android.content.DialogInterface;\r
-import android.os.Bundle;\r
-import android.support.v4.app.DialogFragment;\r
-import android.view.LayoutInflater;\r
-import android.view.View;\r
-import android.view.ViewGroup;\r
-import android.widget.ArrayAdapter;\r
-import android.widget.Button;\r
-import android.widget.Spinner;\r
-import android.widget.TextView;\r
-\r
-public class SimulationSeriesDialog extends DialogFragment {\r
-       \r
-       public interface OnConfirmListener {\r
-               public void onConfirm();\r
-       }\r
-\r
-       private Spinner series1Spinner;\r
-       private Spinner series2Spinner;\r
-\r
-       private SimulationChart chart;\r
-       private OnConfirmListener listener;\r
-\r
-       public static SimulationSeriesDialog newInstance( SimulationChart chart ) {\r
-               SimulationSeriesDialog d = new SimulationSeriesDialog();\r
-               d.chart = chart;\r
-               return d;\r
-       }\r
-\r
-       public void setOnConfirmListener(OnConfirmListener listener) {\r
-               this.listener = listener;\r
-       }\r
-\r
-       @Override\r
-       public void onCreate(Bundle savedInstanceState) {\r
-               super.onCreate(savedInstanceState);\r
-               if (savedInstanceState != null ) {\r
-                       chart = (SimulationChart) savedInstanceState.getSerializable("chart");\r
-               }\r
-       }\r
-\r
-       @Override\r
-       public void onSaveInstanceState(Bundle arg0) {\r
-               super.onSaveInstanceState(arg0);\r
-               arg0.putSerializable("chart", chart);\r
-       }\r
-\r
-       @Override\r
-       public View onCreateView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r
-\r
-               View v = inflater.inflate(R.layout.simulation_series_dialog, container, false);\r
-               \r
-               OpenRocketDocument rocketDocument = ((Application)getActivity().getApplication()).getRocketDocument();\r
-\r
-               Button okButton = (Button) v.findViewById(R.id.simulationOkButton);\r
-               okButton.setOnClickListener( new View.OnClickListener() {\r
-\r
-                       @Override\r
-                       public void onClick(View v) {\r
-                               chart.setSeries1((FlightDataType)series1Spinner.getSelectedItem());\r
-                               chart.setSeries2((FlightDataType)series2Spinner.getSelectedItem());\r
-\r
-                               if ( listener != null ) {\r
-                                       listener.onConfirm();\r
-                               }\r
-                               SimulationSeriesDialog.this.dismiss();\r
-                       }\r
-                       \r
-               });\r
-\r
-               series1Spinner = (Spinner) v.findViewById(R.id.simulationSeries1);\r
-               series2Spinner = (Spinner) v.findViewById(R.id.simulationSeries2);\r
-\r
-               List<FlightDataType> selectableSeries = new ArrayList<FlightDataType>();\r
-               for( FlightDataType fdt : chart.getFlightDataBranch(rocketDocument).getTypes() ) {\r
-                       if ( fdt == FlightDataType.TYPE_TIME ) { \r
-\r
-                       } else {\r
-                               selectableSeries.add(fdt);\r
-                       }\r
-               }\r
-               ArrayAdapter<FlightDataType> serieses = new ArrayAdapter<FlightDataType>(getActivity(),R.layout.simple_spinner_item,selectableSeries) {\r
-\r
-                       @Override\r
-                       public View getView(int position, View convertView,     ViewGroup parent) {\r
-                               View v = convertView;\r
-                               if ( v == null ) {\r
-                                       LayoutInflater li = inflater;\r
-                                       v = li.inflate(R.layout.simple_spinner_item,null);\r
-                               }\r
-                               FlightDataType fdt = this.getItem(position);\r
-                               ((TextView)v.findViewById(android.R.id.text1)).setText( fdt.toString() );\r
-                               return v;\r
-                       }\r
-\r
-               };\r
-               series1Spinner.setAdapter(serieses);\r
-               series2Spinner.setAdapter(serieses);\r
-\r
-\r
-               return v;\r
-       }\r
-\r
-}\r
index 8a478ab4def6347225ea6df0967ad4865ff17803..cdfcf65da82298245c06a7d4d2520e63fd9981d7 100644 (file)
@@ -1,36 +1,22 @@
-/**\r
- * Copyright (C) 2009, 2010 SC 4ViewSoft SRL\r
- *  \r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *  \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- *  \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
 package net.sf.openrocket.android.simulation;\r
 \r
 import net.sf.openrocket.R;\r
 import net.sf.openrocket.android.ActivityHelpers;\r
-import net.sf.openrocket.android.Application;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
 import net.sf.openrocket.document.OpenRocketDocument;\r
 import net.sf.openrocket.document.Simulation;\r
 import android.os.Bundle;\r
 import android.support.v4.app.Fragment;\r
-import android.support.v4.app.FragmentActivity;\r
 import android.support.v4.app.FragmentTransaction;\r
-import android.view.Menu;\r
-import android.view.MenuItem;\r
+\r
+import com.actionbarsherlock.app.SherlockFragmentActivity;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuItem;\r
 \r
 /**\r
  * An activity that encapsulates a graphical view of the chart.\r
  */\r
-public class SimulationViewActivity extends FragmentActivity {\r
+public class SimulationViewActivity extends SherlockFragmentActivity {\r
 \r
        @Override\r
        protected void onCreate(Bundle savedInstanceState) {\r
@@ -38,7 +24,7 @@ public class SimulationViewActivity extends FragmentActivity {
                //setContentView(R.layout.simulation_graph_activity);\r
                int simulationNumber = getIntent().getIntExtra("Simulation", 0);\r
 \r
-               final OpenRocketDocument rocketDocument = ((Application)getApplication()).getRocketDocument();\r
+               final OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
 \r
                Simulation sim = rocketDocument.getSimulation(simulationNumber);\r
 \r
@@ -46,7 +32,7 @@ public class SimulationViewActivity extends FragmentActivity {
                chart.setSeries1(sim.getSimulatedData().getBranch(0).getTypes()[1]);\r
                chart.setSeries2(sim.getSimulatedData().getBranch(0).getTypes()[2]);\r
 \r
-               Fragment graph = SimulationFragment.newInstance(chart);\r
+               Fragment graph = SimulationViewFragment.newInstance(chart);\r
 \r
                FragmentTransaction ft = getSupportFragmentManager().beginTransaction();\r
                ft.replace(android.R.id.content, graph);\r
diff --git a/android/src/net/sf/openrocket/android/simulation/SimulationViewFragment.java b/android/src/net/sf/openrocket/android/simulation/SimulationViewFragment.java
new file mode 100644 (file)
index 0000000..659ea38
--- /dev/null
@@ -0,0 +1,97 @@
+\r
+package net.sf.openrocket.android.simulation;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+\r
+import org.achartengine.GraphicalView;\r
+import org.achartengine.chart.XYChart;\r
+\r
+import android.os.Bundle;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+\r
+import com.actionbarsherlock.app.SherlockFragment;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+/**\r
+ * An activity that encapsulates a graphical view of the chart.\r
+ */\r
+public class SimulationViewFragment extends SherlockFragment implements SimulationPlotConfigDialog.OnConfirmListener {\r
+       \r
+       SimulationChart chart;\r
+\r
+       ViewGroup container;\r
+       \r
+       /** The encapsulated graphical view. */\r
+       private GraphicalView mView;\r
+       /** The chart to be drawn. */\r
+       private XYChart mChart;\r
+\r
+       public static SimulationViewFragment newInstance( SimulationChart chart ) {\r
+               SimulationViewFragment frag = new SimulationViewFragment();\r
+               frag.chart = chart;\r
+               return frag;\r
+       }\r
+\r
+       @Override\r
+       public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {\r
+               setRetainInstance(true);\r
+               setHasOptionsMenu(true);\r
+               OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+\r
+               this.container = container;\r
+               if (savedInstanceState != null ) {\r
+                       chart = (SimulationChart) savedInstanceState.getSerializable("chart");\r
+               }\r
+               mChart = chart.buildChart(rocketDocument);\r
+               mView = new GraphicalView(container.getContext(), mChart);\r
+               return mView;\r
+       }\r
+\r
+       @Override\r
+       public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\r
+               inflater.inflate(R.menu.simulation_option_menu, menu);\r
+       }\r
+\r
+       @Override\r
+       public boolean onOptionsItemSelected(MenuItem item) {\r
+               switch (item.getItemId())\r
+               {\r
+               case R.id.simulation_config_plot_menu_option:\r
+                       SimulationPlotConfigDialog seriesDialog = SimulationPlotConfigDialog.newInstance(chart);\r
+                       seriesDialog.show(getFragmentManager(), "AbraCadaver");\r
+                       seriesDialog.setOnConfirmListener(this);\r
+                       return true;\r
+               case R.id.simulation_view_events_menu_option:\r
+                       SimulationEventsDialog eventsDialog = SimulationEventsDialog.newInstance(chart);\r
+                       eventsDialog.show(getFragmentManager(), "AbraCadaver");\r
+                       return true;\r
+               default:\r
+                       return super.onOptionsItemSelected(item);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void onConfirm() {\r
+               OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+\r
+               mChart = chart.buildChart(rocketDocument);\r
+               ViewGroup parent = (ViewGroup) mView.getParent();\r
+               parent.removeView(mView);\r
+               mView = new GraphicalView(container.getContext(), mChart);\r
+               parent.addView(mView);\r
+       }\r
+\r
+       @Override\r
+       public void onSaveInstanceState(Bundle outState) {\r
+               super.onSaveInstanceState(outState);\r
+               outState.putSerializable("chart", chart);\r
+\r
+       }\r
+       \r
+}
\ No newline at end of file
diff --git a/android/src/net/sf/openrocket/android/simulation/Simulations.java b/android/src/net/sf/openrocket/android/simulation/Simulations.java
new file mode 100644 (file)
index 0000000..4d8314a
--- /dev/null
@@ -0,0 +1,175 @@
+package net.sf.openrocket.android.simulation;\r
+\r
+import net.sf.openrocket.R;\r
+import net.sf.openrocket.android.CurrentRocketHolder;\r
+import net.sf.openrocket.android.util.AndroidLogWrapper;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.document.Simulation;\r
+import android.app.Activity;\r
+import android.content.SharedPreferences;\r
+import android.os.Bundle;\r
+import android.preference.PreferenceManager;\r
+import android.support.v4.app.FragmentTransaction;\r
+import android.view.LayoutInflater;\r
+import android.view.View;\r
+import android.view.ViewGroup;\r
+import android.widget.AdapterView;\r
+import android.widget.AdapterView.OnItemClickListener;\r
+import android.widget.AdapterView.OnItemLongClickListener;\r
+import android.widget.ArrayAdapter;\r
+import android.widget.ListView;\r
+\r
+import com.actionbarsherlock.app.SherlockFragment;\r
+import com.actionbarsherlock.view.Menu;\r
+import com.actionbarsherlock.view.MenuInflater;\r
+import com.actionbarsherlock.view.MenuItem;\r
+\r
+public class Simulations extends SherlockFragment\r
+implements SharedPreferences.OnSharedPreferenceChangeListener\r
+{\r
+\r
+       private final static String wizardFrag = "wizardFrag";\r
+\r
+       public interface OnSimulationSelectedListener {\r
+               public void onSimulationSelected( int simulationId );\r
+       }\r
+\r
+       private ListView simulationList;\r
+       private OnSimulationSelectedListener listener;\r
+\r
+       @Override\r
+       public View onCreateView(LayoutInflater inflater, ViewGroup container,\r
+                       Bundle savedInstanceState) {\r
+               setHasOptionsMenu(true);\r
+               View v = inflater.inflate(R.layout.rocket_simulations, container, false);\r
+               simulationList = (ListView) v.findViewById(R.id.openrocketviewerSimulationList);\r
+               return v;\r
+       }\r
+       \r
+       @Override\r
+       public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {\r
+               inflater.inflate(R.menu.rocket_viewer_simulation_option_menu, menu);\r
+       }\r
+\r
+       @Override\r
+       public boolean onOptionsItemSelected(MenuItem item) {\r
+               switch (item.getItemId())\r
+               {\r
+               case R.id.menu_add:\r
+                       addSimulation();\r
+                       return true;\r
+               default:\r
+                       return super.onOptionsItemSelected(item);\r
+               }\r
+       }\r
+\r
+       @Override\r
+       public void onAttach(Activity activity) {\r
+               super.onAttach(activity);\r
+               if ( activity instanceof OnSimulationSelectedListener ) {\r
+                       listener = (OnSimulationSelectedListener) activity;\r
+               }\r
+       }\r
+\r
+\r
+       public void setListener(OnSimulationSelectedListener listener) {\r
+               this.listener = listener;\r
+       }\r
+\r
+       @Override\r
+       public void onActivityCreated(Bundle savedInstanceState) {\r
+               super.onActivityCreated(savedInstanceState);\r
+\r
+               SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());\r
+               prefs.registerOnSharedPreferenceChangeListener(this);\r
+\r
+       }\r
+\r
+       @Override\r
+       public void onResume() {\r
+               super.onResume();\r
+               setup();\r
+\r
+       }\r
+\r
+       @Override\r
+       public void onDestroy() {\r
+               super.onDestroy();\r
+\r
+               SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());\r
+               prefs.unregisterOnSharedPreferenceChangeListener(this);\r
+       }\r
+\r
+       @Override\r
+       public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1) {\r
+               if ( this.isVisible() ) {\r
+                       setup();\r
+               }\r
+       }\r
+\r
+\r
+       public void refreshSimulationList() {\r
+               setup();\r
+       }\r
+       \r
+       private void setup() {\r
+               final OpenRocketDocument rocketDocument = CurrentRocketHolder.getCurrentRocket().getRocketDocument();\r
+               AndroidLogWrapper.d(Simulations.class,"activity = {0}", this.getActivity());\r
+\r
+               ArrayAdapter<Simulation> sims = new ArrayAdapter<Simulation>(this.getActivity(),android.R.layout.simple_list_item_2,rocketDocument.getSimulations()) {\r
+\r
+                       @Override\r
+                       public View getView(int position, View convertView,     ViewGroup parent) {\r
+                   SimulationListItem listItemView = (SimulationListItem) convertView;\r
+\r
+                   if (listItemView == null) {\r
+                       listItemView = new SimulationListItem(parent.getContext());\r
+                   }\r
+\r
+                               Simulation sim = this.getItem(position);\r
+                               listItemView.setSimulation(sim);\r
+\r
+                   return listItemView;\r
+                       }\r
+\r
+               };\r
+               simulationList.setOnItemClickListener( new OnItemClickListener() {\r
+                       @Override\r
+                       public void onItemClick(AdapterView l, View v, int position, long id) {\r
+                               Simulation sim = CurrentRocketHolder.getCurrentRocket().getRocketDocument().getSimulation(position);\r
+                               // Check if there is data for this simulation.\r
+                               if ( sim.getSimulatedData() == null || sim.getSimulatedData().getBranchCount() == 0 ) {\r
+                                       openEditor(position);\r
+                               } else if (listener != null ) {\r
+                                       listener.onSimulationSelected(position);\r
+                               }\r
+                       }\r
+\r
+               });\r
+               simulationList.setOnItemLongClickListener( new OnItemLongClickListener() {\r
+\r
+                       @Override\r
+                       public boolean onItemLongClick(AdapterView<?> parent, View view,\r
+                                       int position, long id) {\r
+                               openEditor(position);\r
+\r
+                               return true;\r
+                       }\r
+                       \r
+               });\r
+               simulationList.setAdapter(sims);\r
+\r
+       }\r
+       \r
+       private void openEditor( int position ) {\r
+               final SimulationEditFragment f = SimulationEditFragment.newInstance(position);\r
+               FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction();\r
+               ft.add(f, wizardFrag);\r
+               ft.commit();\r
+       }\r
+\r
+       private void addSimulation() {\r
+               CurrentRocketHolder.getCurrentRocket().addNewSimulation(getActivity());\r
+       }\r
+       \r
+}\r
index 7516f7f118f5efbf355c29dc4e76e2ed66ec193f..52d99a4050a4b738d6d426e9af1c1dda43c31342 100644 (file)
@@ -101,9 +101,7 @@ public abstract class TCQueryAction extends Fragment {
                DbAdapter mDbHelper = new DbAdapter(getActivity());\r
                mDbHelper.open();\r
                try {\r
-                       ExtendedThrustCurveMotor m = new ExtendedThrustCurveMotor();\r
-\r
-                       m.setThrustCurveMotor( thrustCurveMotor );\r
+                       ExtendedThrustCurveMotor m = new ExtendedThrustCurveMotor(thrustCurveMotor);\r
 \r
                        // Convert impulse class.  ThrustCurve puts mmx, 1/4a and 1/2a as A.\r
                        m.setImpulseClass(mi.getImpulse_class());\r
index c27c7744a28eeec796330e70919adb169931a325..9bb4e2dcc70df7a7e511c5384d68c2a9f38cef46 100644 (file)
@@ -4,19 +4,21 @@ import net.sf.openrocket.R;
 import net.sf.openrocket.android.util.AndroidLogWrapper;\r
 import net.sf.openrocket.android.util.ErrorDialogFragment;\r
 import android.os.Bundle;\r
-import android.support.v4.app.FragmentActivity;\r
 import android.view.View;\r
 import android.widget.Button;\r
 import android.widget.EditText;\r
 import android.widget.Spinner;\r
 \r
-public class TCQueryActivity extends FragmentActivity\r
+import com.actionbarsherlock.app.SherlockFragmentActivity;\r
+\r
+public class TCQueryActivity extends SherlockFragmentActivity\r
 implements TCQueryAction.OnTCQueryCompleteListener\r
 {\r
 \r
        @Override\r
        protected void onCreate(Bundle savedInstanceState) {\r
                super.onCreate(savedInstanceState);\r
+               setTitle(R.string.TCMotorSearchFormTitle);\r
                setContentView(R.layout.tcqueryform);\r
 \r
                final Spinner manufacturerField = (Spinner) findViewById(R.id.TCMotorSearchFormManufacturerField);\r
index 6b74c2856221cd5526d9e943f06cde5e7db784fc..3d9ac96906f952800aa3b9089980f1b5970bf98a 100644 (file)
@@ -18,14 +18,14 @@ import net.sf.openrocket.motor.ThrustCurveMotorPlaceholder;
 \r
 public abstract class ThrustCurveAPI {\r
 \r
-       private static String url_base = "http://www.thrustcurve.org/servlets/";\r
-       \r
        public static SearchResponse doSearch( SearchRequest request ) throws MalformedURLException, IOException {\r
                \r
                String requestString = request.toString();\r
                \r
                AndroidLogWrapper.d(ThrustCurveAPI.class, "doSearch: " + requestString);\r
-               URL url = new URL(url_base + "search");\r
+               // Froyo has troubles resolving URLS constructed with protocols.  Because of this\r
+               // we need to do it in parts.\r
+               URL url = new URL("http", "www.thrustcurve.org", "/servlets/search");\r
 \r
         OutputStream  stream;\r
 \r
@@ -58,7 +58,9 @@ public abstract class ThrustCurveAPI {
                String requestString = dr.toString();\r
 \r
                AndroidLogWrapper.d(ThrustCurveAPI.class, "downloadData: " + requestString);\r
-               URL url = new URL(url_base + "download");\r
+               // Froyo has troubles resolving URLS constructed with protocols.  Because of this\r
+               // we need to do it in parts.\r
+               URL url = new URL("http", "www.thrustcurve.org", "/servlets/download");\r
 \r
                OutputStream  stream;\r
 \r
index 0bc1e8144ad727bf5b30aa7978f1a43de814d61a..eac9a83ee43e4a39b17b1c15eb3d9e9615fc5dec 100644 (file)
@@ -9,7 +9,11 @@ import android.util.Log;
 \r
 public class AndroidLogWrapper {\r
 \r
-       private static final boolean logEnabled = false;\r
+       private static boolean logEnabled = false;\r
+       \r
+       public static void setLogEnabled( boolean value ) {\r
+               logEnabled = value;\r
+       }\r
        \r
        public static void d( Class clzz, String msg ) {\r
                \r
index 57e7142740a4b74f9cd217d1a8591866ccd94bbd..f246f171e1fb9aad26cff669d9044b016f55e59d 100644 (file)
@@ -17,12 +17,6 @@ public class ErrorDialogFragment extends DialogFragment {
        }\r
 \r
 \r
-\r
-       @Override\r
-       public void onCreate(Bundle savedInstanceState) {\r
-               super.onCreate(savedInstanceState);\r
-       }\r
-       \r
        @Override\r
        public Dialog onCreateDialog(Bundle savedInstanceState) {\r
                String message = getArguments().getString("message");\r
index e72cc36fd3ac21baa1e4c8410c09f623368b7257..4fab124627fb86bdfcda29a6cbb843a41a589afe 100644 (file)
@@ -2,7 +2,6 @@ package net.sf.openrocket.android.util;
 \r
 import android.os.Bundle;\r
 import android.os.Handler;\r
-import android.support.v4.app.Fragment;\r
 import android.view.ContextMenu;\r
 import android.view.ContextMenu.ContextMenuInfo;\r
 import android.view.Gravity;\r
@@ -19,6 +18,8 @@ import android.widget.ListAdapter;
 import android.widget.ListView;\r
 import android.widget.TextView;\r
 \r
+import com.actionbarsherlock.app.SherlockFragment;\r
+\r
 /**\r
  * \r
  * Pulled from https://gist.github.com/1316903\r
@@ -30,7 +31,7 @@ import android.widget.TextView;
  *\r
  * All ASLv2 licensed.\r
  */\r
-public class ExpandableListFragment extends Fragment\r
+public class ExpandableListFragment extends SherlockFragment\r
 implements OnCreateContextMenuListener, ExpandableListView.OnChildClickListener,\r
 ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandListener\r
 {\r
@@ -50,6 +51,14 @@ ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandList
                        onListItemClick((ListView) parent, v, position, id);\r
                }\r
        };\r
+       \r
+       final private AdapterView.OnItemLongClickListener mOnLongClickListener = new AdapterView.OnItemLongClickListener() {\r
+               @Override\r
+               public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {\r
+                       return onListItemLongClick( (ListView) parent, view, position, id);\r
+               }\r
+               \r
+       };\r
 \r
        ExpandableListAdapter mAdapter;\r
        ExpandableListView mList;\r
@@ -134,6 +143,10 @@ ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandList
        public void onListItemClick(ListView l, View v, int position, long id) {\r
        }\r
 \r
+       public boolean onListItemLongClick(ListView l, View v, int position, long id ) {\r
+               return false;\r
+       }\r
+       \r
        /** Provide the cursor for the list view. */\r
        public void setListAdapter(ExpandableListAdapter adapter) {\r
                boolean hadAdapter = mAdapter != null;\r
@@ -282,6 +295,7 @@ ExpandableListView.OnGroupCollapseListener, ExpandableListView.OnGroupExpandList
                }\r
                mListShown = true;\r
                mList.setOnItemClickListener(mOnClickListener);\r
+               mList.setOnItemLongClickListener(mOnLongClickListener);\r
                if (mAdapter != null) {\r
                        setListAdapter(mAdapter);\r
                } else {\r
diff --git a/android/src/net/sf/openrocket/android/util/PersistentExpandableListView.java b/android/src/net/sf/openrocket/android/util/PersistentExpandableListView.java
new file mode 100644 (file)
index 0000000..a22c586
--- /dev/null
@@ -0,0 +1,89 @@
+package net.sf.openrocket.android.util;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import android.content.Context;\r
+import android.os.Bundle;\r
+import android.os.Parcelable;\r
+import android.util.AttributeSet;\r
+import android.widget.ExpandableListAdapter;\r
+import android.widget.ExpandableListView;\r
+\r
+public class PersistentExpandableListView extends ExpandableListView {\r
+\r
+       public PersistentExpandableListView(Context context, AttributeSet attrs,\r
+                       int defStyle) {\r
+               super(context, attrs, defStyle);\r
+       }\r
+\r
+       public PersistentExpandableListView(Context context, AttributeSet attrs) {\r
+               super(context, attrs);\r
+       }\r
+\r
+       public PersistentExpandableListView(Context context) {\r
+               super(context);\r
+       }\r
+\r
+       @Override\r
+       public Parcelable onSaveInstanceState() {\r
+               Bundle b = new Bundle();\r
+               long[] expandedIds = getExpandedIds();\r
+               b.putLongArray("ExpandedIds", expandedIds);\r
+               return b;\r
+       }\r
+\r
+       @Override\r
+       public void onRestoreInstanceState(Parcelable state) {\r
+               Bundle b = (Bundle) state;\r
+               long[] expandedIds = b.getLongArray("ExpandedIds");\r
+               restoreExpandedState(expandedIds);\r
+       }\r
+\r
+       private long[] getExpandedIds() {\r
+               ExpandableListAdapter adapter = getExpandableListAdapter();\r
+               if (adapter != null) {\r
+                       int length = adapter.getGroupCount();\r
+                       ArrayList<Long> expandedIds = new ArrayList<Long>();\r
+                       for(int i=0; i < length; i++) {\r
+                               if(this.isGroupExpanded(i)) {\r
+                                       expandedIds.add(adapter.getGroupId(i));\r
+                               }\r
+                       }\r
+                       return toLongArray(expandedIds);\r
+               } else {\r
+                       return null;\r
+               }\r
+       }\r
+\r
+       private static long[] toLongArray(List<Long> list)  {\r
+               long[] ret = new long[list.size()];\r
+               int i = 0;\r
+               for (Long e : list)  \r
+                       ret[i++] = e.longValue();\r
+               return ret;\r
+       }\r
+\r
+       private void restoreExpandedState(long[] expandedIds) {\r
+               if (expandedIds != null) {\r
+                       ExpandableListAdapter adapter = getExpandableListAdapter();\r
+                       if (adapter != null) {\r
+                               for (int i=0; i<adapter.getGroupCount(); i++) {\r
+                                       long id = adapter.getGroupId(i);\r
+                                       if (inArray(expandedIds, id)) this.expandGroup(i);\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       private static boolean inArray(long[] array, long element) {\r
+               for (long l : array) {\r
+                       if (l == element) {\r
+                               return true;\r
+                       }\r
+               }\r
+               return false;\r
+       }\r
+\r
+\r
+}\r
index d095a5c9efd0515ad11895055ac535f81856013c..2c97d60ee3b2825ab07231c9ad3939dc19ce85be 100644 (file)
@@ -18,12 +18,6 @@ public class ProgressDialogFragment extends DialogFragment {
                return fragment;\r
        }\r
 \r
-\r
-       @Override\r
-       public void onCreate(Bundle savedInstanceState) {\r
-               super.onCreate(savedInstanceState);\r
-       }\r
-\r
        @Override\r
        public ProgressDialog onCreateDialog(Bundle savedInstanceState) {\r
                String title = null;\r
diff --git a/android/src/pl/polidea/treeview/AbstractTreeViewAdapter.java b/android/src/pl/polidea/treeview/AbstractTreeViewAdapter.java
deleted file mode 100644 (file)
index e8e7071..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-package pl.polidea.treeview;
-
-import net.sf.openrocket.R;
-import android.app.Activity;
-import android.content.Context;
-import android.database.DataSetObserver;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
-import android.widget.FrameLayout.LayoutParams;
-import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
-import android.widget.LinearLayout;
-import android.widget.ListAdapter;
-
-/**
- * Adapter used to feed the table view.
- * 
- * @param <T>
- *            class for ID of the tree
- */
-public abstract class AbstractTreeViewAdapter<T> extends BaseAdapter implements
-        ListAdapter {
-    private final TreeStateManager<T> treeStateManager;
-    private final int numberOfLevels;
-    private final LayoutInflater layoutInflater;
-
-    private int indentWidth = 0;
-    private int indicatorGravity = 0;
-    private Drawable collapsedDrawable;
-    private Drawable expandedDrawable;
-    private Drawable indicatorBackgroundDrawable;
-    private Drawable rowBackgroundDrawable;
-
-    private final OnClickListener indicatorClickListener = new OnClickListener() {
-        @Override
-        public void onClick(final View v) {
-            @SuppressWarnings("unchecked")
-            final T id = (T) v.getTag();
-            expandCollapse(id);
-        }
-    };
-
-    private boolean collapsible;
-    private final Activity activity;
-
-    public Activity getActivity() {
-        return activity;
-    }
-
-    protected TreeStateManager<T> getManager() {
-        return treeStateManager;
-    }
-
-    protected void expandCollapse(final T id) {
-        final TreeNodeInfo<T> info = treeStateManager.getNodeInfo(id);
-        if (!info.isWithChildren()) {
-            // ignore - no default action
-            return;
-        }
-        if (info.isExpanded()) {
-            treeStateManager.collapseChildren(id);
-        } else {
-            treeStateManager.expandDirectChildren(id);
-        }
-    }
-
-    private void calculateIndentWidth() {
-        if (expandedDrawable != null) {
-            indentWidth = Math.max(getIndentWidth(),
-                    expandedDrawable.getIntrinsicWidth());
-        }
-        if (collapsedDrawable != null) {
-            indentWidth = Math.max(getIndentWidth(),
-                    collapsedDrawable.getIntrinsicWidth());
-        }
-    }
-
-    public AbstractTreeViewAdapter(final Activity activity,
-            final TreeStateManager<T> treeStateManager, final int numberOfLevels) {
-        this.activity = activity;
-        this.treeStateManager = treeStateManager;
-        this.layoutInflater = (LayoutInflater) activity
-                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        this.numberOfLevels = numberOfLevels;
-        this.collapsedDrawable = null;
-        this.expandedDrawable = null;
-        this.rowBackgroundDrawable = null;
-        this.indicatorBackgroundDrawable = null;
-    }
-
-    @Override
-    public void registerDataSetObserver(final DataSetObserver observer) {
-        treeStateManager.registerDataSetObserver(observer);
-    }
-
-    @Override
-    public void unregisterDataSetObserver(final DataSetObserver observer) {
-        treeStateManager.unregisterDataSetObserver(observer);
-    }
-
-    @Override
-    public int getCount() {
-        return treeStateManager.getVisibleCount();
-    }
-
-    @Override
-    public Object getItem(final int position) {
-        return getItemId(position);
-    }
-
-    public T getTreeId(final int position) {
-        return treeStateManager.getVisibleList().get(position);
-    }
-
-    public TreeNodeInfo<T> getTreeNodeInfo(final int position) {
-        return treeStateManager.getNodeInfo(getTreeId(position));
-    }
-
-    @Override
-    public boolean hasStableIds() { // NOPMD
-        return true;
-    }
-
-    @Override
-    public int getItemViewType(final int position) {
-        return getTreeNodeInfo(position).getLevel();
-    }
-
-    @Override
-    public int getViewTypeCount() {
-        return numberOfLevels;
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return getCount() == 0;
-    }
-
-    @Override
-    public boolean areAllItemsEnabled() { // NOPMD
-        return true;
-    }
-
-    @Override
-    public boolean isEnabled(final int position) { // NOPMD
-        return true;
-    }
-
-    protected int getTreeListItemWrapperId() {
-        return R.layout.tree_list_item_wrapper;
-    }
-
-    @Override
-    public final View getView(final int position, final View convertView,
-            final ViewGroup parent) {
-        final TreeNodeInfo<T> nodeInfo = getTreeNodeInfo(position);
-        if (convertView == null) {
-            final LinearLayout layout = (LinearLayout) layoutInflater.inflate(
-                    getTreeListItemWrapperId(), null);
-            return populateTreeItem(layout, getNewChildView(nodeInfo),
-                    nodeInfo, true);
-        } else {
-            final LinearLayout linear = (LinearLayout) convertView;
-            final FrameLayout frameLayout = (FrameLayout) linear
-                    .findViewById(R.id.treeview_list_item_frame);
-            final View childView = frameLayout.getChildAt(0);
-            updateView(childView, nodeInfo);
-            return populateTreeItem(linear, childView, nodeInfo, false);
-        }
-    }
-
-    /**
-     * Called when new view is to be created.
-     * 
-     * @param treeNodeInfo
-     *            node info
-     * @return view that should be displayed as tree content
-     */
-    public abstract View getNewChildView(TreeNodeInfo<T> treeNodeInfo);
-
-    /**
-     * Called when new view is going to be reused. You should update the view
-     * and fill it in with the data required to display the new information. You
-     * can also create a new view, which will mean that the old view will not be
-     * reused.
-     * 
-     * @param view
-     *            view that should be updated with the new values
-     * @param treeNodeInfo
-     *            node info used to populate the view
-     * @return view to used as row indented content
-     */
-    public abstract View updateView(View view, TreeNodeInfo<T> treeNodeInfo);
-
-    /**
-     * Retrieves background drawable for the node.
-     * 
-     * @param treeNodeInfo
-     *            node info
-     * @return drawable returned as background for the whole row. Might be null,
-     *         then default background is used
-     */
-    public Drawable getBackgroundDrawable(final TreeNodeInfo<T> treeNodeInfo) { // NOPMD
-        return null;
-    }
-
-    private Drawable getDrawableOrDefaultBackground(final Drawable r) {
-        if (r == null) {
-            return activity.getResources()
-                    .getDrawable(R.drawable.list_selector_background).mutate();
-        } else {
-            return r;
-        }
-    }
-
-    public final LinearLayout populateTreeItem(final LinearLayout layout,
-            final View childView, final TreeNodeInfo<T> nodeInfo,
-            final boolean newChildView) {
-        final Drawable individualRowDrawable = getBackgroundDrawable(nodeInfo);
-        layout.setBackgroundDrawable(individualRowDrawable == null ? getDrawableOrDefaultBackground(rowBackgroundDrawable)
-                : individualRowDrawable);
-        final LinearLayout.LayoutParams indicatorLayoutParams = new LinearLayout.LayoutParams(
-                calculateIndentation(nodeInfo), LayoutParams.FILL_PARENT);
-        final LinearLayout indicatorLayout = (LinearLayout) layout
-                .findViewById(R.id.treeview_list_item_image_layout);
-        indicatorLayout.setGravity(indicatorGravity);
-        indicatorLayout.setLayoutParams(indicatorLayoutParams);
-        final ImageView image = (ImageView) layout
-                .findViewById(R.id.treeview_list_item_image);
-        image.setImageDrawable(getDrawable(nodeInfo));
-        image.setBackgroundDrawable(getDrawableOrDefaultBackground(indicatorBackgroundDrawable));
-        image.setScaleType(ScaleType.CENTER);
-        image.setTag(nodeInfo.getId());
-        if (nodeInfo.isWithChildren() && collapsible) {
-            image.setOnClickListener(indicatorClickListener);
-        } else {
-            image.setOnClickListener(null);
-        }
-        layout.setTag(nodeInfo.getId());
-        final FrameLayout frameLayout = (FrameLayout) layout
-                .findViewById(R.id.treeview_list_item_frame);
-        final FrameLayout.LayoutParams childParams = new FrameLayout.LayoutParams(
-                LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
-        if (newChildView) {
-            frameLayout.addView(childView, childParams);
-        }
-        frameLayout.setTag(nodeInfo.getId());
-        return layout;
-    }
-
-    protected int calculateIndentation(final TreeNodeInfo<T> nodeInfo) {
-        return getIndentWidth() * (nodeInfo.getLevel() + (collapsible ? 1 : 0));
-    }
-
-    private Drawable getDrawable(final TreeNodeInfo<T> nodeInfo) {
-        if (!nodeInfo.isWithChildren() || !collapsible) {
-            return getDrawableOrDefaultBackground(indicatorBackgroundDrawable);
-        }
-        if (nodeInfo.isExpanded()) {
-            return expandedDrawable;
-        } else {
-            return collapsedDrawable;
-        }
-    }
-
-    public void setIndicatorGravity(final int indicatorGravity) {
-        this.indicatorGravity = indicatorGravity;
-    }
-
-    public void setCollapsedDrawable(final Drawable collapsedDrawable) {
-        this.collapsedDrawable = collapsedDrawable;
-        calculateIndentWidth();
-    }
-
-    public void setExpandedDrawable(final Drawable expandedDrawable) {
-        this.expandedDrawable = expandedDrawable;
-        calculateIndentWidth();
-    }
-
-    public void setIndentWidth(final int indentWidth) {
-        this.indentWidth = indentWidth;
-        calculateIndentWidth();
-    }
-
-    public void setRowBackgroundDrawable(final Drawable rowBackgroundDrawable) {
-        this.rowBackgroundDrawable = rowBackgroundDrawable;
-    }
-
-    public void setIndicatorBackgroundDrawable(
-            final Drawable indicatorBackgroundDrawable) {
-        this.indicatorBackgroundDrawable = indicatorBackgroundDrawable;
-    }
-
-    public void setCollapsible(final boolean collapsible) {
-        this.collapsible = collapsible;
-    }
-
-    public void refresh() {
-        treeStateManager.refresh();
-    }
-
-    private int getIndentWidth() {
-        return indentWidth;
-    }
-
-    @SuppressWarnings("unchecked")
-    public void handleItemClick(final View view, final Object id) {
-        expandCollapse((T) id);
-    }
-
-}
diff --git a/android/src/pl/polidea/treeview/InMemoryTreeNode.java b/android/src/pl/polidea/treeview/InMemoryTreeNode.java
deleted file mode 100644 (file)
index 6035369..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-package pl.polidea.treeview;
-
-import java.io.Serializable;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Node. It is package protected so that it cannot be used outside.
- * 
- * @param <T>
- *            type of the identifier used by the tree
- */
-class InMemoryTreeNode<T> implements Serializable {
-    private static final long serialVersionUID = 1L;
-    private final T id;
-    private final T parent;
-    private final int level;
-    private boolean visible = true;
-    private final List<InMemoryTreeNode<T>> children = new LinkedList<InMemoryTreeNode<T>>();
-    private List<T> childIdListCache = null;
-
-    public InMemoryTreeNode(final T id, final T parent, final int level,
-            final boolean visible) {
-        super();
-        this.id = id;
-        this.parent = parent;
-        this.level = level;
-        this.visible = visible;
-    }
-
-    public int indexOf(final T id) {
-        return getChildIdList().indexOf(id);
-    }
-
-    /**
-     * Cache is built lasily only if needed. The cache is cleaned on any
-     * structure change for that node!).
-     * 
-     * @return list of ids of children
-     */
-    public synchronized List<T> getChildIdList() {
-        if (childIdListCache == null) {
-            childIdListCache = new LinkedList<T>();
-            for (final InMemoryTreeNode<T> n : children) {
-                childIdListCache.add(n.getId());
-            }
-        }
-        return childIdListCache;
-    }
-
-    public boolean isVisible() {
-        return visible;
-    }
-
-    public void setVisible(final boolean visible) {
-        this.visible = visible;
-    }
-
-    public int getChildrenListSize() {
-        return children.size();
-    }
-
-    public synchronized InMemoryTreeNode<T> add(final int index, final T child,
-            final boolean visible) {
-        childIdListCache = null;
-        // Note! top levell children are always visible (!)
-        final InMemoryTreeNode<T> newNode = new InMemoryTreeNode<T>(child,
-                getId(), getLevel() + 1, getId() == null ? true : visible);
-        children.add(index, newNode);
-        return newNode;
-    }
-
-    /**
-     * Note. This method should technically return unmodifiable collection, but
-     * for performance reason on small devices we do not do it.
-     * 
-     * @return children list
-     */
-    public List<InMemoryTreeNode<T>> getChildren() {
-        return children;
-    }
-
-    public synchronized void clearChildren() {
-        children.clear();
-        childIdListCache = null;
-    }
-
-    public synchronized void removeChild(final T child) {
-        final int childIndex = indexOf(child);
-        if (childIndex != -1) {
-            children.remove(childIndex);
-            childIdListCache = null;
-        }
-    }
-
-    @Override
-    public String toString() {
-        return "InMemoryTreeNode [id=" + getId() + ", parent=" + getParent()
-                + ", level=" + getLevel() + ", visible=" + visible
-                + ", children=" + children + ", childIdListCache="
-                + childIdListCache + "]";
-    }
-
-    T getId() {
-        return id;
-    }
-
-    T getParent() {
-        return parent;
-    }
-
-    int getLevel() {
-        return level;
-    }
-
-}
\ No newline at end of file
diff --git a/android/src/pl/polidea/treeview/InMemoryTreeStateManager.java b/android/src/pl/polidea/treeview/InMemoryTreeStateManager.java
deleted file mode 100644 (file)
index bae675b..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-package pl.polidea.treeview;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import android.database.DataSetObserver;
-
-/**
- * In-memory manager of tree state.
- * 
- * @param <T>
- *            type of identifier
- */
-public class InMemoryTreeStateManager<T> implements TreeStateManager<T> {
-    private static final long serialVersionUID = 1L;
-    private final Map<T, InMemoryTreeNode<T>> allNodes = new HashMap<T, InMemoryTreeNode<T>>();
-    private final InMemoryTreeNode<T> topSentinel = new InMemoryTreeNode<T>(
-            null, null, -1, true);
-    private transient List<T> visibleListCache = null; // lasy initialised
-    private transient List<T> unmodifiableVisibleList = null;
-    private boolean visibleByDefault = true;
-    private final transient Set<DataSetObserver> observers = new HashSet<DataSetObserver>();
-
-    private synchronized void internalDataSetChanged() {
-        visibleListCache = null;
-        unmodifiableVisibleList = null;
-        for (final DataSetObserver observer : observers) {
-            observer.onChanged();
-        }
-    }
-
-    /**
-     * If true new nodes are visible by default.
-     * 
-     * @param visibleByDefault
-     *            if true, then newly added nodes are expanded by default
-     */
-    public void setVisibleByDefault(final boolean visibleByDefault) {
-        this.visibleByDefault = visibleByDefault;
-    }
-
-    private InMemoryTreeNode<T> getNodeFromTreeOrThrow(final T id) {
-        if (id == null) {
-            throw new NodeNotInTreeException("(null)");
-        }
-        final InMemoryTreeNode<T> node = allNodes.get(id);
-        if (node == null) {
-            throw new NodeNotInTreeException(id.toString());
-        }
-        return node;
-    }
-
-    private InMemoryTreeNode<T> getNodeFromTreeOrThrowAllowRoot(final T id) {
-        if (id == null) {
-            return topSentinel;
-        }
-        return getNodeFromTreeOrThrow(id);
-    }
-
-    private void expectNodeNotInTreeYet(final T id) {
-        final InMemoryTreeNode<T> node = allNodes.get(id);
-        if (node != null) {
-            throw new NodeAlreadyInTreeException(id.toString(), node.toString());
-        }
-    }
-
-    @Override
-    public synchronized TreeNodeInfo<T> getNodeInfo(final T id) {
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrow(id);
-        final List<InMemoryTreeNode<T>> children = node.getChildren();
-        boolean expanded = false;
-        if (!children.isEmpty() && children.get(0).isVisible()) {
-            expanded = true;
-        }
-        return new TreeNodeInfo<T>(id, node.getLevel(), !children.isEmpty(),
-                node.isVisible(), expanded);
-    }
-
-    @Override
-    public synchronized List<T> getChildren(final T id) {
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
-        return node.getChildIdList();
-    }
-
-    @Override
-    public synchronized T getParent(final T id) {
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
-        return node.getParent();
-    }
-
-    private boolean getChildrenVisibility(final InMemoryTreeNode<T> node) {
-        boolean visibility;
-        final List<InMemoryTreeNode<T>> children = node.getChildren();
-        if (children.isEmpty()) {
-            visibility = visibleByDefault;
-        } else {
-            visibility = children.get(0).isVisible();
-        }
-        return visibility;
-    }
-
-    @Override
-    public synchronized void addBeforeChild(final T parent, final T newChild,
-            final T beforeChild) {
-        expectNodeNotInTreeYet(newChild);
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(parent);
-        final boolean visibility = getChildrenVisibility(node);
-        // top nodes are always expanded.
-        if (beforeChild == null) {
-            final InMemoryTreeNode<T> added = node.add(0, newChild, visibility);
-            allNodes.put(newChild, added);
-        } else {
-            final int index = node.indexOf(beforeChild);
-            final InMemoryTreeNode<T> added = node.add(index == -1 ? 0 : index,
-                    newChild, visibility);
-            allNodes.put(newChild, added);
-        }
-        if (visibility) {
-            internalDataSetChanged();
-        }
-    }
-
-    @Override
-    public synchronized void addAfterChild(final T parent, final T newChild,
-            final T afterChild) {
-        expectNodeNotInTreeYet(newChild);
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(parent);
-        final boolean visibility = getChildrenVisibility(node);
-        if (afterChild == null) {
-            final InMemoryTreeNode<T> added = node.add(
-                    node.getChildrenListSize(), newChild, visibility);
-            allNodes.put(newChild, added);
-        } else {
-            final int index = node.indexOf(afterChild);
-            final InMemoryTreeNode<T> added = node.add(
-                    index == -1 ? node.getChildrenListSize() : index, newChild,
-                    visibility);
-            allNodes.put(newChild, added);
-        }
-        if (visibility) {
-            internalDataSetChanged();
-        }
-    }
-
-    @Override
-    public synchronized void removeNodeRecursively(final T id) {
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
-        final boolean visibleNodeChanged = removeNodeRecursively(node);
-        final T parent = node.getParent();
-        final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
-        parentNode.removeChild(id);
-        if (visibleNodeChanged) {
-            internalDataSetChanged();
-        }
-    }
-
-    private boolean removeNodeRecursively(final InMemoryTreeNode<T> node) {
-        boolean visibleNodeChanged = false;
-        for (final InMemoryTreeNode<T> child : node.getChildren()) {
-            if (removeNodeRecursively(child)) {
-                visibleNodeChanged = true;
-            }
-        }
-        node.clearChildren();
-        if (node.getId() != null) {
-            allNodes.remove(node.getId());
-            if (node.isVisible()) {
-                visibleNodeChanged = true;
-            }
-        }
-        return visibleNodeChanged;
-    }
-
-    private void setChildrenVisibility(final InMemoryTreeNode<T> node,
-            final boolean visible, final boolean recursive) {
-        for (final InMemoryTreeNode<T> child : node.getChildren()) {
-            child.setVisible(visible);
-            if (recursive) {
-                setChildrenVisibility(child, visible, true);
-            }
-        }
-    }
-
-    @Override
-    public synchronized void expandDirectChildren(final T id) {
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
-        setChildrenVisibility(node, true, false);
-        internalDataSetChanged();
-    }
-
-    @Override
-    public synchronized void expandEverythingBelow(final T id) {
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
-        setChildrenVisibility(node, true, true);
-        internalDataSetChanged();
-    }
-
-    @Override
-    public synchronized void collapseChildren(final T id) {
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
-        if (node == topSentinel) {
-            for (final InMemoryTreeNode<T> n : topSentinel.getChildren()) {
-                setChildrenVisibility(n, false, true);
-            }
-        } else {
-            setChildrenVisibility(node, false, true);
-        }
-        internalDataSetChanged();
-    }
-
-    @Override
-    public synchronized T getNextSibling(final T id) {
-        final T parent = getParent(id);
-        final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
-        boolean returnNext = false;
-        for (final InMemoryTreeNode<T> child : parentNode.getChildren()) {
-            if (returnNext) {
-                return child.getId();
-            }
-            if (child.getId().equals(id)) {
-                returnNext = true;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public synchronized T getPreviousSibling(final T id) {
-        final T parent = getParent(id);
-        final InMemoryTreeNode<T> parentNode = getNodeFromTreeOrThrowAllowRoot(parent);
-        final T previousSibling = null;
-        for (final InMemoryTreeNode<T> child : parentNode.getChildren()) {
-            if (child.getId().equals(id)) {
-                return previousSibling;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public synchronized boolean isInTree(final T id) {
-        return allNodes.containsKey(id);
-    }
-
-    @Override
-    public synchronized int getVisibleCount() {
-        return getVisibleList().size();
-    }
-
-    @Override
-    public synchronized List<T> getVisibleList() {
-        T currentId = null;
-        if (visibleListCache == null) {
-            visibleListCache = new ArrayList<T>(allNodes.size());
-            do {
-                currentId = getNextVisible(currentId);
-                if (currentId == null) {
-                    break;
-                } else {
-                    visibleListCache.add(currentId);
-                }
-            } while (true);
-        }
-        if (unmodifiableVisibleList == null) {
-            unmodifiableVisibleList = Collections
-                    .unmodifiableList(visibleListCache);
-        }
-        return unmodifiableVisibleList;
-    }
-
-    public synchronized T getNextVisible(final T id) {
-        final InMemoryTreeNode<T> node = getNodeFromTreeOrThrowAllowRoot(id);
-        if (!node.isVisible()) {
-            return null;
-        }
-        final List<InMemoryTreeNode<T>> children = node.getChildren();
-        if (!children.isEmpty()) {
-            final InMemoryTreeNode<T> firstChild = children.get(0);
-            if (firstChild.isVisible()) {
-                return firstChild.getId();
-            }
-        }
-        final T sibl = getNextSibling(id);
-        if (sibl != null) {
-            return sibl;
-        }
-        T parent = node.getParent();
-        do {
-            if (parent == null) {
-                return null;
-            }
-            final T parentSibling = getNextSibling(parent);
-            if (parentSibling != null) {
-                return parentSibling;
-            }
-            parent = getNodeFromTreeOrThrow(parent).getParent();
-        } while (true);
-    }
-
-    @Override
-    public synchronized void registerDataSetObserver(
-            final DataSetObserver observer) {
-        observers.add(observer);
-    }
-
-    @Override
-    public synchronized void unregisterDataSetObserver(
-            final DataSetObserver observer) {
-        observers.remove(observer);
-    }
-
-    @Override
-    public int getLevel(final T id) {
-        return getNodeFromTreeOrThrow(id).getLevel();
-    }
-
-    @Override
-    public Integer[] getHierarchyDescription(final T id) {
-        final int level = getLevel(id);
-        final Integer[] hierarchy = new Integer[level + 1];
-        int currentLevel = level;
-        T currentId = id;
-        T parent = getParent(currentId);
-        while (currentLevel >= 0) {
-            hierarchy[currentLevel--] = getChildren(parent).indexOf(currentId);
-            currentId = parent;
-            parent = getParent(parent);
-        }
-        return hierarchy;
-    }
-
-    private void appendToSb(final StringBuilder sb, final T id) {
-        if (id != null) {
-            final TreeNodeInfo<T> node = getNodeInfo(id);
-            final int indent = node.getLevel() * 4;
-            final char[] indentString = new char[indent];
-            Arrays.fill(indentString, ' ');
-            sb.append(indentString);
-            sb.append(node.toString());
-            sb.append(Arrays.asList(getHierarchyDescription(id)).toString());
-            sb.append("\n");
-        }
-        final List<T> children = getChildren(id);
-        for (final T child : children) {
-            appendToSb(sb, child);
-        }
-    }
-
-    @Override
-    public synchronized String toString() {
-        final StringBuilder sb = new StringBuilder();
-        appendToSb(sb, null);
-        return sb.toString();
-    }
-
-    @Override
-    public synchronized void clear() {
-        allNodes.clear();
-        topSentinel.clearChildren();
-        internalDataSetChanged();
-    }
-
-    @Override
-    public void refresh() {
-        internalDataSetChanged();
-    }
-
-}
diff --git a/android/src/pl/polidea/treeview/NodeAlreadyInTreeException.java b/android/src/pl/polidea/treeview/NodeAlreadyInTreeException.java
deleted file mode 100644 (file)
index 680d026..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-package pl.polidea.treeview;
-
-/**
- * The node being added is already in the tree.
- * 
- */
-public class NodeAlreadyInTreeException extends RuntimeException {
-    private static final long serialVersionUID = 1L;
-
-    public NodeAlreadyInTreeException(final String id, final String oldNode) {
-        super("The node has already been added to the tree: " + id + ". Old node is:" + oldNode);
-    }
-
-}
diff --git a/android/src/pl/polidea/treeview/NodeNotInTreeException.java b/android/src/pl/polidea/treeview/NodeNotInTreeException.java
deleted file mode 100644 (file)
index f20450e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package pl.polidea.treeview;
-
-/**
- * This exception is thrown when the tree does not contain node requested.
- * 
- */
-public class NodeNotInTreeException extends RuntimeException {
-
-    private static final long serialVersionUID = 1L;
-
-    public NodeNotInTreeException(final String id) {
-        super("The tree does not contain the node specified: " + id);
-    }
-
-}
diff --git a/android/src/pl/polidea/treeview/TreeBuilder.java b/android/src/pl/polidea/treeview/TreeBuilder.java
deleted file mode 100644 (file)
index cfb6d00..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-package pl.polidea.treeview;
-
-import net.sf.openrocket.android.util.AndroidLogWrapper;
-
-/**
- * Allows to build tree easily in sequential mode (you have to know levels of
- * all the tree elements upfront). You should rather use this class rather than
- * manager if you build initial tree from some external data source.
- * 
- * @param <T>
- */
-public class TreeBuilder<T> {
-
-    private final TreeStateManager<T> manager;
-
-    private T lastAddedId = null;
-    private int lastLevel = -1;
-
-    public TreeBuilder(final TreeStateManager<T> manager) {
-        this.manager = manager;
-    }
-
-    public void clear() {
-        manager.clear();
-    }
-
-    /**
-     * Adds new relation to existing tree. Child is set as the last child of the
-     * parent node. Parent has to already exist in the tree, child cannot yet
-     * exist. This method is mostly useful in case you add entries layer by
-     * layer - i.e. first top level entries, then children for all parents, then
-     * grand-children and so on.
-     * 
-     * @param parent
-     *            parent id
-     * @param child
-     *            child id
-     */
-    public synchronized void addRelation(final T parent, final T child) {
-        AndroidLogWrapper.d(TreeBuilder.class, "Adding relation parent:" + parent + " -> child: " + child);
-        manager.addAfterChild(parent, child, null);
-        lastAddedId = child;
-        lastLevel = manager.getLevel(child);
-    }
-
-    /**
-     * Adds sequentially new node. Using this method is the simplest way of
-     * building tree - if you have all the elements in the sequence as they
-     * should be displayed in fully-expanded tree. You can combine it with add
-     * relation - for example you can add information about few levels using
-     * {@link addRelation} and then after the right level is added as parent,
-     * you can continue adding them using sequential operation.
-     * 
-     * @param id
-     *            id of the node
-     * @param level
-     *            its level
-     */
-    public synchronized void sequentiallyAddNextNode(final T id, final int level) {
-        AndroidLogWrapper.d(TreeBuilder.class, "Adding sequentiall node " + id + " at level " + level);
-        if (lastAddedId == null) {
-            addNodeToParentOneLevelDown(null, id, level);
-        } else {
-            if (level <= lastLevel) {
-                final T parent = findParentAtLevel(lastAddedId, level - 1);
-                addNodeToParentOneLevelDown(parent, id, level);
-            } else {
-                addNodeToParentOneLevelDown(lastAddedId, id, level);
-            }
-        }
-    }
-
-    /**
-     * Find parent of the node at the level specified.
-     * 
-     * @param node
-     *            node from which we start
-     * @param levelToFind
-     *            level which we are looking for
-     * @return the node found (null if it is topmost node).
-     */
-    private T findParentAtLevel(final T node, final int levelToFind) {
-        T parent = manager.getParent(node);
-        while (parent != null) {
-            if (manager.getLevel(parent) == levelToFind) {
-                break;
-            }
-            parent = manager.getParent(parent);
-        }
-        return parent;
-    }
-
-    /**
-     * Adds note to parent at the level specified. But it verifies that the
-     * level is one level down than the parent!
-     * 
-     * @param parent
-     *            parent parent
-     * @param id
-     *            new node id
-     * @param level
-     *            should always be parent's level + 1
-     */
-    private void addNodeToParentOneLevelDown(final T parent, final T id,
-            final int level) {
-        if (parent == null && level != 0) {
-            throw new TreeConfigurationException("Trying to add new id " + id
-                    + " to top level with level != 0 (" + level + ")");
-        }
-        if (parent != null && manager.getLevel(parent) != level - 1) {
-            throw new TreeConfigurationException("Trying to add new id " + id
-                    + " <" + level + "> to " + parent + " <"
-                    + manager.getLevel(parent)
-                    + ">. The difference in levels up is bigger than 1.");
-        }
-        manager.addAfterChild(parent, id, null);
-        setLastAdded(id, level);
-    }
-
-    private void setLastAdded(final T id, final int level) {
-        lastAddedId = id;
-        lastLevel = level;
-    }
-
-}
diff --git a/android/src/pl/polidea/treeview/TreeConfigurationException.java b/android/src/pl/polidea/treeview/TreeConfigurationException.java
deleted file mode 100644 (file)
index 1fa72e0..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-package pl.polidea.treeview;
-
-/**
- * Exception thrown when there is a problem with configuring tree.
- * 
- */
-public class TreeConfigurationException extends RuntimeException {
-
-    private static final long serialVersionUID = 1L;
-
-    public TreeConfigurationException(final String detailMessage) {
-        super(detailMessage);
-    }
-
-}
diff --git a/android/src/pl/polidea/treeview/TreeNodeInfo.java b/android/src/pl/polidea/treeview/TreeNodeInfo.java
deleted file mode 100644 (file)
index 32d18dd..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-package pl.polidea.treeview;
-
-/**
- * Information about the node.
- * 
- * @param <T>
- *            type of the id for the tree
- */
-public class TreeNodeInfo<T> {
-    private final T id;
-    private final int level;
-    private final boolean withChildren;
-    private final boolean visible;
-    private final boolean expanded;
-
-    /**
-     * Creates the node information.
-     * 
-     * @param id
-     *            id of the node
-     * @param level
-     *            level of the node
-     * @param withChildren
-     *            whether the node has children.
-     * @param visible
-     *            whether the tree node is visible.
-     * @param expanded
-     *            whether the tree node is expanded
-     * 
-     */
-    public TreeNodeInfo(final T id, final int level,
-            final boolean withChildren, final boolean visible,
-            final boolean expanded) {
-        super();
-        this.id = id;
-        this.level = level;
-        this.withChildren = withChildren;
-        this.visible = visible;
-        this.expanded = expanded;
-    }
-
-    public T getId() {
-        return id;
-    }
-
-    public boolean isWithChildren() {
-        return withChildren;
-    }
-
-    public boolean isVisible() {
-        return visible;
-    }
-
-    public boolean isExpanded() {
-        return expanded;
-    }
-
-    public int getLevel() {
-        return level;
-    }
-
-    @Override
-    public String toString() {
-        return "TreeNodeInfo [id=" + id + ", level=" + level
-                + ", withChildren=" + withChildren + ", visible=" + visible
-                + ", expanded=" + expanded + "]";
-    }
-
-}
\ No newline at end of file
diff --git a/android/src/pl/polidea/treeview/TreeStateManager.java b/android/src/pl/polidea/treeview/TreeStateManager.java
deleted file mode 100644 (file)
index 781b70e..0000000
+++ /dev/null
@@ -1,193 +0,0 @@
-package pl.polidea.treeview;
-
-import java.io.Serializable;
-import java.util.List;
-
-import android.database.DataSetObserver;
-
-/**
- * Manages information about state of the tree. It only keeps information about
- * tree elements, not the elements themselves.
- * 
- * @param <T>
- *            type of the identifier for nodes in the tree
- */
-public interface TreeStateManager<T> extends Serializable {
-
-    /**
-     * Returns array of integers showing the location of the node in hierarchy.
-     * It corresponds to heading numbering. {0,0,0} in 3 level node is the first
-     * node {0,0,1} is second leaf (assuming that there are two leaves in first
-     * subnode of the first node).
-     * 
-     * @param id
-     *            id of the node
-     * @return textual description of the hierarchy in tree for the node.
-     */
-    Integer[] getHierarchyDescription(T id);
-
-    /**
-     * Returns level of the node.
-     * 
-     * @param id
-     *            id of the node
-     * @return level in the tree
-     */
-    int getLevel(T id);
-
-    /**
-     * Returns information about the node.
-     * 
-     * @param id
-     *            node id
-     * @return node info
-     */
-    TreeNodeInfo<T> getNodeInfo(T id);
-
-    /**
-     * Returns children of the node.
-     * 
-     * @param id
-     *            id of the node or null if asking for top nodes
-     * @return children of the node
-     */
-    List<T> getChildren(T id);
-
-    /**
-     * Returns parent of the node.
-     * 
-     * @param id
-     *            id of the node
-     * @return parent id or null if no parent
-     */
-    T getParent(T id);
-
-    /**
-     * Adds the node before child or at the beginning.
-     * 
-     * @param parent
-     *            id of the parent node. If null - adds at the top level
-     * @param newChild
-     *            new child to add if null - adds at the beginning.
-     * @param beforeChild
-     *            child before which to add the new child
-     */
-    void addBeforeChild(T parent, T newChild, T beforeChild);
-
-    /**
-     * Adds the node after child or at the end.
-     * 
-     * @param parent
-     *            id of the parent node. If null - adds at the top level.
-     * @param newChild
-     *            new child to add. If null - adds at the end.
-     * @param afterChild
-     *            child after which to add the new child
-     */
-    void addAfterChild(T parent, T newChild, T afterChild);
-
-    /**
-     * Removes the node and all children from the tree.
-     * 
-     * @param id
-     *            id of the node to remove or null if all nodes are to be
-     *            removed.
-     */
-    void removeNodeRecursively(T id);
-
-    /**
-     * Expands all children of the node.
-     * 
-     * @param id
-     *            node which children should be expanded. cannot be null (top
-     *            nodes are always expanded!).
-     */
-    void expandDirectChildren(T id);
-
-    /**
-     * Expands everything below the node specified. Might be null - then expands
-     * all.
-     * 
-     * @param id
-     *            node which children should be expanded or null if all nodes
-     *            are to be expanded.
-     */
-    void expandEverythingBelow(T id);
-
-    /**
-     * Collapse children.
-     * 
-     * @param id
-     *            id collapses everything below node specified. If null,
-     *            collapses everything but top-level nodes.
-     */
-    void collapseChildren(T id);
-
-    /**
-     * Returns next sibling of the node (or null if no further sibling).
-     * 
-     * @param id
-     *            node id
-     * @return the sibling (or null if no next)
-     */
-    T getNextSibling(T id);
-
-    /**
-     * Returns previous sibling of the node (or null if no previous sibling).
-     * 
-     * @param id
-     *            node id
-     * @return the sibling (or null if no previous)
-     */
-    T getPreviousSibling(T id);
-
-    /**
-     * Checks if given node is already in tree.
-     * 
-     * @param id
-     *            id of the node
-     * @return true if node is already in tree.
-     */
-    boolean isInTree(T id);
-
-    /**
-     * Count visible elements.
-     * 
-     * @return number of currently visible elements.
-     */
-    int getVisibleCount();
-
-    /**
-     * Returns visible node list.
-     * 
-     * @return return the list of all visible nodes in the right sequence
-     */
-    List<T> getVisibleList();
-
-    /**
-     * Registers observers with the manager.
-     * 
-     * @param observer
-     *            observer
-     */
-    void registerDataSetObserver(final DataSetObserver observer);
-
-    /**
-     * Unregisters observers with the manager.
-     * 
-     * @param observer
-     *            observer
-     */
-    void unregisterDataSetObserver(final DataSetObserver observer);
-
-    /**
-     * Cleans tree stored in manager. After this operation the tree is empty.
-     * 
-     */
-    void clear();
-
-    /**
-     * Refreshes views connected to the manager.
-     */
-    void refresh();
-}
diff --git a/android/src/pl/polidea/treeview/TreeViewList.java b/android/src/pl/polidea/treeview/TreeViewList.java
deleted file mode 100644 (file)
index 637a63c..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-package pl.polidea.treeview;
-
-import net.sf.openrocket.R;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListAdapter;
-import android.widget.ListView;
-
-/**
- * Tree view, expandable multi-level.
- * 
- * <pre>
- * attr ref pl.polidea.treeview.R.styleable#TreeViewList_collapsible
- * attr ref pl.polidea.treeview.R.styleable#TreeViewList_src_expanded
- * attr ref pl.polidea.treeview.R.styleable#TreeViewList_src_collapsed
- * attr ref pl.polidea.treeview.R.styleable#TreeViewList_indent_width
- * attr ref pl.polidea.treeview.R.styleable#TreeViewList_handle_trackball_press
- * attr ref pl.polidea.treeview.R.styleable#TreeViewList_indicator_gravity
- * attr ref pl.polidea.treeview.R.styleable#TreeViewList_indicator_background
- * attr ref pl.polidea.treeview.R.styleable#TreeViewList_row_background
- * </pre>
- */
-public class TreeViewList extends ListView {
-    private static final int DEFAULT_COLLAPSED_RESOURCE = R.drawable.collapsed;
-    private static final int DEFAULT_EXPANDED_RESOURCE = R.drawable.expanded;
-    private static final int DEFAULT_INDENT = 0;
-    private static final int DEFAULT_GRAVITY = Gravity.LEFT
-            | Gravity.CENTER_VERTICAL;
-    private Drawable expandedDrawable;
-    private Drawable collapsedDrawable;
-    private Drawable rowBackgroundDrawable;
-    private Drawable indicatorBackgroundDrawable;
-    private int indentWidth = 0;
-    private int indicatorGravity = 0;
-    private AbstractTreeViewAdapter< ? > treeAdapter;
-    private boolean collapsible;
-    private boolean handleTrackballPress;
-
-    public TreeViewList(final Context context, final AttributeSet attrs) {
-        this(context, attrs, R.style.treeViewListStyle);
-    }
-
-       public TreeViewList(final Context context) {
-        this(context, null);
-    }
-
-    public TreeViewList(final Context context, final AttributeSet attrs,
-            final int defStyle) {
-        super(context, attrs, defStyle);
-        parseAttributes(context, attrs);
-    }
-
-    private void parseAttributes(final Context context, final AttributeSet attrs) {
-        final TypedArray a = context.obtainStyledAttributes(attrs,
-                R.styleable.TreeViewList);
-        expandedDrawable = a.getDrawable(R.styleable.TreeViewList_src_expanded);
-        if (expandedDrawable == null) {
-            expandedDrawable = context.getResources().getDrawable(
-                    DEFAULT_EXPANDED_RESOURCE);
-        }
-        collapsedDrawable = a
-                .getDrawable(R.styleable.TreeViewList_src_collapsed);
-        if (collapsedDrawable == null) {
-            collapsedDrawable = context.getResources().getDrawable(
-                    DEFAULT_COLLAPSED_RESOURCE);
-        }
-        indentWidth = a.getDimensionPixelSize(
-                R.styleable.TreeViewList_indent_width, DEFAULT_INDENT);
-        indicatorGravity = a.getInteger(
-                R.styleable.TreeViewList_indicator_gravity, DEFAULT_GRAVITY);
-        indicatorBackgroundDrawable = a
-                .getDrawable(R.styleable.TreeViewList_indicator_background);
-        rowBackgroundDrawable = a
-                .getDrawable(R.styleable.TreeViewList_row_background);
-        collapsible = a.getBoolean(R.styleable.TreeViewList_collapsible, true);
-        handleTrackballPress = a.getBoolean(
-                R.styleable.TreeViewList_handle_trackball_press, true);
-    }
-
-    @Override
-    public void setAdapter(final ListAdapter adapter) {
-        if (!(adapter instanceof AbstractTreeViewAdapter)) {
-            throw new TreeConfigurationException(
-                    "The adapter is not of TreeViewAdapter type");
-        }
-        treeAdapter = (AbstractTreeViewAdapter< ? >) adapter;
-        syncAdapter();
-        super.setAdapter(treeAdapter);
-    }
-
-    private void syncAdapter() {
-        treeAdapter.setCollapsedDrawable(collapsedDrawable);
-        treeAdapter.setExpandedDrawable(expandedDrawable);
-        treeAdapter.setIndicatorGravity(indicatorGravity);
-        treeAdapter.setIndentWidth(indentWidth);
-        treeAdapter.setIndicatorBackgroundDrawable(indicatorBackgroundDrawable);
-        treeAdapter.setRowBackgroundDrawable(rowBackgroundDrawable);
-        treeAdapter.setCollapsible(collapsible);
-        if (handleTrackballPress) {
-            setOnItemClickListener(new OnItemClickListener() {
-                @Override
-                public void onItemClick(final AdapterView< ? > parent,
-                        final View view, final int position, final long id) {
-                    treeAdapter.handleItemClick(view, view.getTag());
-                }
-            });
-        } else {
-            setOnClickListener(null);
-        }
-
-    }
-
-    public void setExpandedDrawable(final Drawable expandedDrawable) {
-        this.expandedDrawable = expandedDrawable;
-        syncAdapter();
-        treeAdapter.refresh();
-    }
-
-    public void setCollapsedDrawable(final Drawable collapsedDrawable) {
-        this.collapsedDrawable = collapsedDrawable;
-        syncAdapter();
-        treeAdapter.refresh();
-    }
-
-    public void setRowBackgroundDrawable(final Drawable rowBackgroundDrawable) {
-        this.rowBackgroundDrawable = rowBackgroundDrawable;
-        syncAdapter();
-        treeAdapter.refresh();
-    }
-
-    public void setIndicatorBackgroundDrawable(
-            final Drawable indicatorBackgroundDrawable) {
-        this.indicatorBackgroundDrawable = indicatorBackgroundDrawable;
-        syncAdapter();
-        treeAdapter.refresh();
-    }
-
-    public void setIndentWidth(final int indentWidth) {
-        this.indentWidth = indentWidth;
-        syncAdapter();
-        treeAdapter.refresh();
-    }
-
-    public void setIndicatorGravity(final int indicatorGravity) {
-        this.indicatorGravity = indicatorGravity;
-        syncAdapter();
-        treeAdapter.refresh();
-    }
-
-    public void setCollapsible(final boolean collapsible) {
-        this.collapsible = collapsible;
-        syncAdapter();
-        treeAdapter.refresh();
-    }
-
-    public void setHandleTrackballPress(final boolean handleTrackballPress) {
-        this.handleTrackballPress = handleTrackballPress;
-        syncAdapter();
-        treeAdapter.refresh();
-    }
-
-    public Drawable getExpandedDrawable() {
-        return expandedDrawable;
-    }
-
-    public Drawable getCollapsedDrawable() {
-        return collapsedDrawable;
-    }
-
-    public Drawable getRowBackgroundDrawable() {
-        return rowBackgroundDrawable;
-    }
-
-    public Drawable getIndicatorBackgroundDrawable() {
-        return indicatorBackgroundDrawable;
-    }
-
-    public int getIndentWidth() {
-        return indentWidth;
-    }
-
-    public int getIndicatorGravity() {
-        return indicatorGravity;
-    }
-
-    public boolean isCollapsible() {
-        return collapsible;
-    }
-
-    public boolean isHandleTrackballPress() {
-        return handleTrackballPress;
-    }
-
-}
diff --git a/android/src/pl/polidea/treeview/license.txt b/android/src/pl/polidea/treeview/license.txt
deleted file mode 100644 (file)
index 1fd37cf..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-Android tree-view-list is 2-clause BSD licensed.\r
-\r
-http://code.google.com/p/tree-view-list-android/\r
-\r
-Copyright (c) <YEAR>, <OWNER>\r
-All rights reserved.\r
-\r
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the\r
-following conditions are met:\r
-\r
-    Redistributions of source code must retain the above copyright notice, this list of conditions and\r
-    the following disclaimer.\r
-    Redistributions in binary form must reproduce the above copyright notice, this list of conditions and\r
-    the following disclaimer in the documentation and/or other materials provided with the distribution.\r
-\r
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r
-INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/android/src/pl/polidea/treeview/package-info.java b/android/src/pl/polidea/treeview/package-info.java
deleted file mode 100644 (file)
index a622e09..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-/**
- * Provides expandable Tree View implementation.
- */
-package pl.polidea.treeview;
\ No newline at end of file
index 10ef69c68136c740d1a14881d72754b76b29bd27..fb297f54eaccbf077503a4f3ff953321db661194 100644 (file)
        <classpathentry kind="lib" path="lib-test/junit-dep-4.8.2.jar"/>
        <classpathentry kind="lib" path="lib-test/uispec4j-2.3-jdk16.jar"/>
        <classpathentry kind="lib" path="resources"/>
+       <classpathentry kind="lib" path="lib/jspf.core-1.0.2.jar" sourcepath="/home/sampo/Projects/lib/jspf/documentation/api"/>
+       <classpathentry kind="lib" path="lib/opencsv-2.3.jar"/>
+       <classpathentry kind="lib" path="lib/jogl/gluegen-rt.jar"/>
+       <classpathentry kind="lib" path="lib/jogl/jogl.all.jar"/>
+       <classpathentry kind="lib" path="lib/OrangeExtensions-1.2.jar"/>
        <classpathentry kind="output" path="bin"/>
 </classpath>
index 592f898e4ae39fca9726621c6c77566d31aeb4f6..7f0fa6f74761b491245fee72af141e047ccff011 100644 (file)
@@ -1,3 +1,82 @@
+2012-08-28 Bill Kuker
+
+   * Removed late GL initialization, was causing issues with Java 7.
+   
+   * Added -Dopenrocket.3d.disable option for anyone experiencing crashes as a result of OpenGL.
+
+2012-08-01 Kevin Ruland
+
+   * Changed the loader to pull *.rkt files from zip containers.
+   
+   * Modified the BasicFrame so it doesn't automatically open the Rocket configuration dialog when opening a new rocket.
+   
+   * Unified the behavior for replacing (automatically closing) the base frame when opening a file, loading an example,
+   or picking from the Most-recently-used list.
+
+2012-06-24  Bill Kuker
+
+    * OSX UI Elements: Screen menu bar, Application name, Dock Icon, Quit, About & Preference
+    handlers. Stubs for the "Apple Java Extensions" to allow other platforms to compile provided
+    by https://github.com/ymasory/OrangeExtensions.
+
+2012-06-11  Bill Kuker
+
+    * Added a 3D view of the rocket to the figure panel.
+    
+2012-06-05  Doug Pedrick
+
+    * Most recently used design files added to File menu.
+
+2012-05-23  Doug Pedrick
+
+    * Centering ring templates can now be chosen for printing.
+    * Calibration ruler added to printed templates.
+
+2012-05-09  Kevin Ruland
+
+    * Add ComponentPreset functionality.  These are commercial components which can be used in rocket designs.
+    System currently support Body Tube, Nose Cone, Transition, Tube Coupler, Centering Ring, Engine Block, Bulk Head,
+    Launch Lug, Streamer and Parachutes.  Received permission from Always Ready Rocketry, Balsa Machining Service, Giant
+    Leap Rocketry, Public Missiles, Semroc and Fliskits to include their parts catalogs in OR.
+
+2012-05-09  Kevin Ruland
+
+    * Add fractional inch unit 'in/64' to Length unit group.
+
+2012-05-09  Jason Blood
+
+       * Add PageFitPrintStrategy and related files to print multiple fins, transitions, and nosecones onto the same page(s)
+
+2012-04-19  Sampo Niskanen
+
+       * Allow opening recovery device on stage separation
+
+2012-04-11  Doug Pedrick
+
+       * [BUG] Printed simulation did not honor launch conditions
+
+2012-04-09  Sampo Niskanen
+
+       * [BUG] Cancelling simulation causes later simulations to fail
+       * Add debugging for NPE in GeneralOptimizationDialog
+
+2012-03-27  Sampo Niskanen
+
+       * [BUG] Inputting negative rotation angle values of components
+
+2012-03-25  Sampo Niskanen
+
+       * [BUG] Removed locale-specific toLowerCase/toUpperCase
+
+2012-03-25  Doug Pedrick
+
+       * Printed rocket figure in design report now honors rotation angle of main figure; fixed bug in layout where the
+      figure was clipped in the page margin.
+
+2012-03-18  Jason Blood
+
+       * Updated importing images to freeform fin sets to work with color images with improved description
+
 2012-03-17  Sampo Niskanen
 
        * Released version 12.03
 2009-11-24  Sampo Niskanen
 
        * Close original window when opening example design
-       
+
 2009-11-10  Sampo Niskanen
 
        * [BUG] Fixed transition volume/mass computation
 2009-10-11  Sampo Niskanen
 
        * [BUG] Sorting motor selection dialog with ',' decimal separator
-       
+
 2009-10-10  Sampo Niskanen
 
        * Removed non-ASCII characters from source code files
 
        * Added icon and source info to About dialog
        * Finalized flight event plot icons
-       
+
 2009-08-27  Sampo Niskanen
 
        * Allow clicking on label to toggle checkbox in two tables
 2009-08-14  Sampo Niskanen
 
        * Plots ignore trailing NaN values
-       
+
 2009-08-13  Sampo Niskanen
 
        * [BUG] Added fin cant for elliptical fins
 2009-07-28  Sampo Niskanen
 
        * Opening of example rocket designs
-       
+
 2009-07-27  Sampo Niskanen
 
        * [BUG] Launch lug radial position not correctly loaded
        * Fixed file dialog directory browsing
        * Initial shift-click selects second component from figure
        * Allow adding body components without selecting stage
-       
+
 2009-05-24  Sampo Niskanen  <sampo.niskanen@iki.fi>
 
        * Initial release 0.9.0
index b2c66f0fe4796d0325feba5cb68571829ef04c1e..1498a596479eeaa1df81f88344e3ebf30629cc4e 100644 (file)
@@ -27,6 +27,7 @@ Contributions have been made by:
 Sampo Niskanen, main developer
 Doug Pedrick, support for RockSim designs, printing
 Kevin Ruland, Android version
+Bill Kuker, 3D visualization
 Richard Graham, geodetic computations
 Jason Blood, freeform fin set import
 Boris du Reau, internationalization
@@ -37,4 +38,6 @@ Tripoli Spain
 Stefan Lobas / ERIG
 Mauro Biasutti
 Sky Dart Team
+Vladimir Beran
+Polish Rocketry Society / Łukasz & Alex Kazanski
 
index 221a6b4a1d67b66963c98713aa66c90257af868f..2981cb092622555d3eb08dedfa04236cd51d0171 100644 (file)
@@ -1,3 +1,22 @@
+OpenRocket 12.09  (2012-09-16):
+-------------------------------
+
+Numerous new features by many contributors:
+
+- 3D rocket design view
+- Component Presets
+- Custom expressions in simulations
+- Printing for centering ring and clustered centering ring components.
+- Support simple arthmatic in dimension entry
+- Support deploying recovery device at stage separation
+- Support for fractional inches (1/64) for unit length
+- Added preference for windspeed units separately
+- Added "most recently used files" in File Menu.
+- Improved printed accurracy in fin marking guide
+- Calibration rulers added to printed templates
+- Translations in Czech and Polish, numerous updates
+
+
 OpenRocket 12.03  (2012-03-17):
 -------------------------------
 
index 0e57a6b0cdc212dd0c3a243347f5b4be40a5238c..9b178defe66a59021edbec0287b652ba09fdaa0a 100644 (file)
                <pathelement location="${src-test.dir}"/>
                <fileset dir="lib-test/" includes="*.jar"/>
        </path>
-       
+
+       <path id="run-classpath">
+               <path refid="classpath"/>
+               <pathelement location="${basedir}/resources"/>
+               <pathelement location="${classes.dir}"/>
+       </path>
+
+       <!-- Add Ant-contrib tasks so we can use for loop -->
+       <taskdef resource="net/sf/antcontrib/antlib.xml">
+               <classpath>
+                       <pathelement location="lib-extra/ant-contrib-1.0b3.jar"/>
+               </classpath>
+       </taskdef>
 
        
        <!-- CLEAN -->
-       <target name="clean">
+       <target name="clean" description="Removes all build artifacts">
                <delete dir="${build.dir}"/>
                <delete dir="tmp/"/>
        </target>
                <javac debug="true" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="classpath"/>
        </target>
        
-       
-       <!-- JAR -->
-       <target name="jar" depends="build">
-               <copy todir="${dist.dir}/">
-                       <fileset dir="." includes="LICENSE.TXT README.TXT ChangeLog ReleaseNotes fileformat.txt" />
-                       <fileset dir="resources/"/>
+       <!-- Executible Eclipse-Jar-In-Jar style JAR -->
+       <target name="jar" depends="core-jar" description="Create the OpenRocket jar-in-jar Executable">
+               <mkdir dir="${jar.dir}" />
+               <jar destfile="${jar.file}">
+                       <manifest>
+                               <attribute name="Main-Class" value="org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader" />
+                               <attribute name="Rsrc-Main-Class" value="${main-class}" />
+                               <attribute name="SplashScreen-Image" value="pix/splashscreen.png" />
+                               <attribute name="Class-Path" value="." />
+                               <attribute name="Rsrc-Class-Path" value="./ main/${ant.project.name}-Core.jar lib/jfreechart-1.0.13.jar lib/jcommon-1.0.16.jar lib/gluegen-rt.jar lib/miglayout15-swing.jar lib/iText-5.0.2.jar lib/jogl.all.jar lib/opencsv-2.3.jar lib/OrangeExtensions-1.2.jar" />
+                       </manifest>
+
+                       <!-- Unzip the Eclipse JIJ Loader -->
+                       <zipfileset src="lib/jar-in-jar-loader.jar" />
+                       
+                       <!-- Include, in the root of the JAR, the resources needed by OR -->
                        <fileset dir="src/" includes="META-INF/" />
-               </copy>
-               <mkdir dir="${jar.dir}"/>
-               <jar destfile="${jar.file}" basedir="${dist.dir}">
+                       <fileset dir="resources/" />
+                       
+                       <!-- Include the core OpenRocket JAR -->
+                       <zipfileset dir="${build.dir}/" prefix="main">
+                               <include name="${ant.project.name}-Core.jar"/>
+                       </zipfileset>
+                       
+                       <!-- Include libraries needed by OR -->
+                       <zipfileset dir="${lib.dir}" prefix="lib">
+                               <include name="*.jar"/>
+                       </zipfileset>
+                       <zipfileset dir="${lib.dir}/jogl" prefix="lib">
+                               <include name="*.jar"/>
+                       </zipfileset>
+                       
+                       <!-- Include metafiles about OR -->
+                       <fileset dir="." includes="LICENSE.TXT README.TXT ChangeLog ReleaseNotes fileformat.txt" />
+               </jar>
+       </target>
+       
+       
+       <!-- Core OpenRocket JAR -->
+       <target name="core-jar" depends="build" description="Create the OpenRocket code-only jar file">
+               <jar destfile="${build.dir}/${ant.project.name}-Core.jar" basedir="${dist.dir}">
                        <manifest>
                                <attribute name="Main-Class" value="${main-class}"/>
                                <attribute name="SplashScreen-Image" value="pix/splashscreen.png"/>
                        </manifest>
-                       <zipfileset src="lib/miglayout15-swing.jar" />
-                       <zipfileset src="lib/jcommon-1.0.16.jar" />
-                       <zipfileset src="lib/jfreechart-1.0.13.jar" />
-                       <zipfileset src="lib/iText-5.0.2.jar" />
                </jar>
        </target>
-       
+
+       <!-- CONVERT vendor csv to ORC files -->
+       <macrodef name="build-orc-file">
+               <attribute name="dir"/>
+               <attribute name="vendor"/>
+               <sequential>
+                       <echo>Generating ORC file for vendor @{vendor}</echo>
+                       <java classname="net.sf.openrocket.preset.loader.RocksimComponentFileTranslator"
+                               fork="true"
+                               classpathref="run-classpath"
+                               failonerror="true">
+                               <arg value="@{dir}"/>
+                               <arg value="resources/datafiles/presets/@{vendor}.orc"/>
+                       </java>
+               </sequential>
+       </macrodef>
+
+       <target name="generate-orc-files"
+               description="Generate ORC file from vendor csv"
+               depends="build">
+
+               <for param="vendor-dir">
+                       <dirset dir="resources-src/datafiles/rocksim_components"
+                               includes="*"/>
+                       <sequential>
+                               <propertyregex property="vendor"
+                                       override="true"
+                                       input="@{vendor-dir}"
+                                       select="\1"
+                                       regexp=".*[/\\]([^/\\]*)$"/>
+                               <build-orc-file dir="@{vendor-dir}" vendor="${vendor}"/>
+                       </sequential>
+               </for>
+       </target>
        
        <!-- DIST-SRC -->
        <target name="dist-src">
@@ -212,4 +284,4 @@ ${nonascii}</fail>
                </echo>
        </target>
     
-</project>
\ No newline at end of file
+</project>
index db4a52faff9e158040f0dea8bd0fddf010f9056a..c9a44cb404fd1c4456ab8b3c54173e3650cc61b0 100644 (file)
@@ -9,7 +9,8 @@ openrocket.locale
        Select the default locale to be used, for example "en_US".
        If set to "xx", the logical keys will be displayed instead of the translated strings.
 
-
+openrocket.3d.disable
+       Disables all OpenGL calls if set.
 
 Logging options
 ---------------
diff --git a/core/doc/techdoc/figures/motors/staged b/core/doc/techdoc/figures/motors/staged
new file mode 100644 (file)
index 0000000..b9b5e5c
--- /dev/null
@@ -0,0 +1,44 @@
+#FIG 3.2  Produced by xfig version 3.2.5
+Landscape
+Center
+Metric
+A4      
+100.00
+Single
+-2
+1200 2
+0 32 #696d69
+6 4275 -3915 5625 225
+1 2 0 1 0 0 48 -1 20 0.000 1 0.0000 4960 -224 170 87 4790 -224 5130 -224
+1 2 0 1 0 32 49 -1 20 0.000 1 0.0000 4951 -109 540 270 4411 -109 5491 -109
+1 2 0 1 0 7 50 -1 20 0.000 1 0.0000 4950 -112 675 337 4275 -112 5625 -112
+1 2 0 1 0 7 55 -1 -1 0.000 1 0.0000 4950 -292 675 337 4275 -292 5625 -292
+1 2 1 1 0 7 60 -1 -1 4.000 1 0.0000 4950 -3547 675 337 4275 -3547 5625 -3547
+2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
+        4275 -89 4275 -314
+2 2 0 0 -1 7 53 -1 20 0.000 0 0 -1 0 0 5
+        4275 -314 5625 -314 5625 -89 4275 -89 4275 -314
+2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
+        5625 -134 5625 -314
+2 1 1 1 0 32 60 -1 -1 4.000 0 0 -1 0 0 2
+        4275 -269 4275 -3554
+2 1 1 1 0 32 60 -1 -1 4.000 0 0 -1 0 0 2
+        5625 -269 5625 -3554
+2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
+        4590 -990 4590 -1170
+-6
+1 2 0 1 0 0 48 -1 20 0.000 1 0.0000 4960 4185 170 87 4790 4185 5130 4185
+1 2 0 1 0 32 49 -1 20 0.000 1 0.0000 4951 4300 540 270 4411 4300 5491 4300
+1 2 0 1 0 7 50 -1 20 0.000 1 0.0000 4950 4297 675 337 4275 4297 5625 4297
+1 2 0 1 0 7 55 -1 -1 0.000 1 0.0000 4950 4117 675 337 4275 4117 5625 4117
+1 2 1 1 0 7 55 -1 -1 4.000 1 0.0000 4950 862 675 337 4275 862 5625 862
+2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
+        4275 4320 4275 4095
+2 2 0 0 -1 7 53 -1 20 0.000 0 0 -1 0 0 5
+        4275 4095 5625 4095 5625 4320 4275 4320 4275 4095
+2 1 1 1 0 32 55 -1 -1 4.000 0 0 -1 0 0 2
+        4275 4140 4275 855
+2 1 1 1 0 32 55 -1 -1 4.000 0 0 -1 0 0 2
+        5625 4140 5625 855
+2 2 1 0 0 7 57 -1 20 2.000 0 0 -1 0 0 5
+        4275 1125 5625 1125 5625 4275 4275 4275 4275 1125
diff --git a/core/doc/techdoc/figures/motors/staged. b/core/doc/techdoc/figures/motors/staged.
deleted file mode 100644 (file)
index b9b5e5c..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-#FIG 3.2  Produced by xfig version 3.2.5
-Landscape
-Center
-Metric
-A4      
-100.00
-Single
--2
-1200 2
-0 32 #696d69
-6 4275 -3915 5625 225
-1 2 0 1 0 0 48 -1 20 0.000 1 0.0000 4960 -224 170 87 4790 -224 5130 -224
-1 2 0 1 0 32 49 -1 20 0.000 1 0.0000 4951 -109 540 270 4411 -109 5491 -109
-1 2 0 1 0 7 50 -1 20 0.000 1 0.0000 4950 -112 675 337 4275 -112 5625 -112
-1 2 0 1 0 7 55 -1 -1 0.000 1 0.0000 4950 -292 675 337 4275 -292 5625 -292
-1 2 1 1 0 7 60 -1 -1 4.000 1 0.0000 4950 -3547 675 337 4275 -3547 5625 -3547
-2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
-        4275 -89 4275 -314
-2 2 0 0 -1 7 53 -1 20 0.000 0 0 -1 0 0 5
-        4275 -314 5625 -314 5625 -89 4275 -89 4275 -314
-2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
-        5625 -134 5625 -314
-2 1 1 1 0 32 60 -1 -1 4.000 0 0 -1 0 0 2
-        4275 -269 4275 -3554
-2 1 1 1 0 32 60 -1 -1 4.000 0 0 -1 0 0 2
-        5625 -269 5625 -3554
-2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
-        4590 -990 4590 -1170
--6
-1 2 0 1 0 0 48 -1 20 0.000 1 0.0000 4960 4185 170 87 4790 4185 5130 4185
-1 2 0 1 0 32 49 -1 20 0.000 1 0.0000 4951 4300 540 270 4411 4300 5491 4300
-1 2 0 1 0 7 50 -1 20 0.000 1 0.0000 4950 4297 675 337 4275 4297 5625 4297
-1 2 0 1 0 7 55 -1 -1 0.000 1 0.0000 4950 4117 675 337 4275 4117 5625 4117
-1 2 1 1 0 7 55 -1 -1 4.000 1 0.0000 4950 862 675 337 4275 862 5625 862
-2 1 0 1 0 7 51 -1 -1 0.000 0 0 -1 0 0 2
-        4275 4320 4275 4095
-2 2 0 0 -1 7 53 -1 20 0.000 0 0 -1 0 0 5
-        4275 4095 5625 4095 5625 4320 4275 4320 4275 4095
-2 1 1 1 0 32 55 -1 -1 4.000 0 0 -1 0 0 2
-        4275 4140 4275 855
-2 1 1 1 0 32 55 -1 -1 4.000 0 0 -1 0 0 2
-        5625 4140 5625 855
-2 2 1 0 0 7 57 -1 20 2.000 0 0 -1 0 0 5
-        4275 1125 5625 1125 5625 4275 4275 4275 4275 1125
index 0a3dbf03b88f1bf724fd9d826850cb6492e729a0..b5ffe06d22846076465ca026efc49b71b0465824 100644 (file)
@@ -38,3 +38,8 @@ The following file format versions exist:
       deploymentvelocity attributes to <flightdata> element.  The motor
       digesting algorithm was changed.  Adds <separationevent> and
       <separationdelay> elements to stage components (except sustainer).
+
+1.5:  Introduced with OpenRocket 12.xx.  Added ComponentPresets.
+      Added lowerstageseparation as recovery device deployment event.
+      Added <datatypes> section for supporting datatypes other than
+      internal ones. Currently only supports datatypes from custom expressions.
diff --git a/core/lib-extra/ant-contrib-1.0b3.jar b/core/lib-extra/ant-contrib-1.0b3.jar
new file mode 100644 (file)
index 0000000..0625376
Binary files /dev/null and b/core/lib-extra/ant-contrib-1.0b3.jar differ
diff --git a/core/lib/OrangeExtensions-1.2.jar b/core/lib/OrangeExtensions-1.2.jar
new file mode 100644 (file)
index 0000000..637d396
Binary files /dev/null and b/core/lib/OrangeExtensions-1.2.jar differ
diff --git a/core/lib/jar-in-jar-loader.jar b/core/lib/jar-in-jar-loader.jar
new file mode 100644 (file)
index 0000000..ebb1287
Binary files /dev/null and b/core/lib/jar-in-jar-loader.jar differ
diff --git a/core/lib/jogl/gluegen-rt-natives-linux-amd64.jar b/core/lib/jogl/gluegen-rt-natives-linux-amd64.jar
new file mode 100644 (file)
index 0000000..ee7cf4b
Binary files /dev/null and b/core/lib/jogl/gluegen-rt-natives-linux-amd64.jar differ
diff --git a/core/lib/jogl/gluegen-rt-natives-linux-i586.jar b/core/lib/jogl/gluegen-rt-natives-linux-i586.jar
new file mode 100644 (file)
index 0000000..a7a7007
Binary files /dev/null and b/core/lib/jogl/gluegen-rt-natives-linux-i586.jar differ
diff --git a/core/lib/jogl/gluegen-rt-natives-macosx-universal.jar b/core/lib/jogl/gluegen-rt-natives-macosx-universal.jar
new file mode 100644 (file)
index 0000000..72d86d3
Binary files /dev/null and b/core/lib/jogl/gluegen-rt-natives-macosx-universal.jar differ
diff --git a/core/lib/jogl/gluegen-rt-natives-windows-amd64.jar b/core/lib/jogl/gluegen-rt-natives-windows-amd64.jar
new file mode 100644 (file)
index 0000000..19f62cb
Binary files /dev/null and b/core/lib/jogl/gluegen-rt-natives-windows-amd64.jar differ
diff --git a/core/lib/jogl/gluegen-rt-natives-windows-i586.jar b/core/lib/jogl/gluegen-rt-natives-windows-i586.jar
new file mode 100644 (file)
index 0000000..713ce14
Binary files /dev/null and b/core/lib/jogl/gluegen-rt-natives-windows-i586.jar differ
diff --git a/core/lib/jogl/gluegen-rt.jar b/core/lib/jogl/gluegen-rt.jar
new file mode 100644 (file)
index 0000000..07bcb06
Binary files /dev/null and b/core/lib/jogl/gluegen-rt.jar differ
diff --git a/core/lib/jogl/jogl-all-natives-linux-amd64.jar b/core/lib/jogl/jogl-all-natives-linux-amd64.jar
new file mode 100644 (file)
index 0000000..544b7d7
Binary files /dev/null and b/core/lib/jogl/jogl-all-natives-linux-amd64.jar differ
diff --git a/core/lib/jogl/jogl-all-natives-linux-i586.jar b/core/lib/jogl/jogl-all-natives-linux-i586.jar
new file mode 100644 (file)
index 0000000..75165df
Binary files /dev/null and b/core/lib/jogl/jogl-all-natives-linux-i586.jar differ
diff --git a/core/lib/jogl/jogl-all-natives-macosx-universal.jar b/core/lib/jogl/jogl-all-natives-macosx-universal.jar
new file mode 100644 (file)
index 0000000..3475838
Binary files /dev/null and b/core/lib/jogl/jogl-all-natives-macosx-universal.jar differ
diff --git a/core/lib/jogl/jogl-all-natives-windows-amd64.jar b/core/lib/jogl/jogl-all-natives-windows-amd64.jar
new file mode 100644 (file)
index 0000000..9dbe67c
Binary files /dev/null and b/core/lib/jogl/jogl-all-natives-windows-amd64.jar differ
diff --git a/core/lib/jogl/jogl-all-natives-windows-i586.jar b/core/lib/jogl/jogl-all-natives-windows-i586.jar
new file mode 100644 (file)
index 0000000..0b03ce7
Binary files /dev/null and b/core/lib/jogl/jogl-all-natives-windows-i586.jar differ
diff --git a/core/lib/jogl/jogl.all.jar b/core/lib/jogl/jogl.all.jar
new file mode 100644 (file)
index 0000000..34e9aa7
Binary files /dev/null and b/core/lib/jogl/jogl.all.jar differ
diff --git a/core/lib/jspf.core-1.0.2.jar b/core/lib/jspf.core-1.0.2.jar
new file mode 100644 (file)
index 0000000..02dec5b
Binary files /dev/null and b/core/lib/jspf.core-1.0.2.jar differ
diff --git a/core/lib/opencsv-2.3.jar b/core/lib/opencsv-2.3.jar
new file mode 100644 (file)
index 0000000..32b00f9
Binary files /dev/null and b/core/lib/opencsv-2.3.jar differ
diff --git a/core/resources-src/datafiles/rocksim_components/bluetube/BTDATA.CSV b/core/resources-src/datafiles/rocksim_components/bluetube/BTDATA.CSV
new file mode 100644 (file)
index 0000000..a58fe49
--- /dev/null
@@ -0,0 +1,10 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,,\r
+Always Ready Rocketry,BT20-29A,29mm Blue Tube 2.0 Airframe,in.,1.141,1.265,48,Vulcanized Fiber,29,2,0\r
+Always Ready Rocketry,BT20-38A,38mm Blue Tube 2.0 Airframe,in.,1.525,1.649,48,Vulcanized Fiber,38,2,0\r
+Always Ready Rocketry,BT20-54A,54mm Blue Tube 2.0 Airframe,in.,2.14,2.264,48,Vulcanized Fiber,54,2,0\r
+Always Ready Rocketry,BT20-63A,2.56 in Blue Tube 2.0 Airframe,in.,2.55,2.674,48,Vulcanized Fiber,,2,0\r
+Always Ready Rocketry,BT20-75A,3 in Blue Tube 2.0 Airframe,in.,3,3.124,48,Vulcanized Fiber,75,2,0\r
+Always Ready Rocketry,BT20-98A,4 in Blue Tube 2.0 Airframe,in.,3.91,4.024,48,Vulcanized Fiber,98,2,0\r
+Always Ready Rocketry,BT20-139A,5.5 in Blue Tube 2.0 Airframe,in.,5.345,5.503,48,Vulcanized Fiber,,2,0\r
+Always Ready Rocketry,BT20-152A,6 in Blue Tube 2.0 Airframe,in.,6,6.16,48,Vulcanized Fiber,,2,0\r
+Always Ready Rocketry,BT20-191A,7.5 in Blue Tube 2.0 Airframe,in.,7.51,7.67,48,Vulcanized Fiber,,2,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/bluetube/MATERIAL.CSV b/core/resources-src/datafiles/rocksim_components/bluetube/MATERIAL.CSV
new file mode 100644 (file)
index 0000000..ecf840c
--- /dev/null
@@ -0,0 +1,2 @@
+Material Name,Units,Density,Low,High,Class,Rocketry Use,Body Tubes,Fin Sets,Launch Lugs,Cords,Nose,Chute,Stream,Trans,Ring,Bulkhead,Engine Block,Sleeve,Tube Coupler,spare,spare,spare,spare,spare,spare,spare,Known Dim type,Known Dim Units,Known Dim Value\r
+Vulcanized Fiber,g/cm3,1.25,,,,1,1,0,1,0,0,0,0,0,0,0,0,1,1,,,,,,,,None,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/bluetube/TCDATA.CSV b/core/resources-src/datafiles/rocksim_components/bluetube/TCDATA.CSV
new file mode 100644 (file)
index 0000000..07d2070
--- /dev/null
@@ -0,0 +1,13 @@
+Mfg.,Part No.,COUPLERS,Units,ID,OD,Length,Material,Mass Units,CG,Mass,AutoSize\r
+Always Ready Rocketry,BT20-29C,29mm Blue Tube 2.0 Coupler,in.,1.017,1.141,8,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-38C,38mm Blue Tube 2.0 Coupler,in.,1.394,1.515,8,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-54C,54mm Blue Tube 2.0 Coupler,in.,2,2.124,8,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-63C,2.56 in Blue Tube 2.0 Coupler,in.,2.418,2.542,8,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-75C,3 in Blue Tube Coupler,in.,2.873,2.997,8,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-98C,4 in Blue Tube Coupler,in.,3.764,3.888,8,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-139C,5.5 in Blue Tube Coupler,in.,5.19,5.338,12,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-152C,6 in Blue Tube Coupler,in.,5.835,5.976,12,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-191C,7.5 in Blue Tube 2.0 Coupler,in.,7.35,7.483,12,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-139C,5.5 in Blue Tube Coupler - Long,in.,5.19,5.338,16,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-152CL,6 in Blue Tube Coupler - Long,in.,5.835,5.976,16,Vulcanized Fiber,oz.,0,0,1\r
+Always Ready Rocketry,BT20-191CL,7.5 in Blue Tube 2.0 Coupler - Long,in.,7.35,7.483,16,Vulcanized Fiber,oz.,0,0,1\r
diff --git a/core/resources-src/datafiles/rocksim_components/bluetube/readme.txt b/core/resources-src/datafiles/rocksim_components/bluetube/readme.txt
new file mode 100644 (file)
index 0000000..358bce5
--- /dev/null
@@ -0,0 +1,46 @@
+Blue Tube 2.0 Rocksim Installation Instructions\r
+3/6/10\r
+\r
+Installation Instructions:\r
+\r
+Extract this zip file to a temporary location you should have three files and this "readme"\r
+\r
+BTDATA.CSV\r
+MATERIAL.CSV\r
+TCDATA.CSV\r
+\r
+Copy these three files to the "DATAIMPORT" folder of your Rocksim Installation.\r
+\r
+(This would USUALLY be C:\Program Files\Rocksim(X)\Dataimport) where X is your version.\r
+\r
+if you can't find this folder, contact Apogee Components.\r
+\r
+Once those files are copied there, launch Rocksim.  Rocksim will import this new data into the parts database.\r
+\r
+\r
+NOTE FOR ROCKSIM 7 and below:\r
+\r
+Open the files in excel and copy the contents (not including the headers) of the download files and paste them into the corresponding files in the RockSim DATA folder. Make a backup copy first in case there is a problem.\r
+Or, try this:\r
+\r
+For RockSim 7, it works the same way as v9, except that the folder was different.  Instead of the "DATAIMPORT" folder, you must create a folder called "New" under the "DATA" folder.  Then extract the .csv files into that "DATA\New" folder.\r
+\r
+\r
+\r
+That's it!\r
+\r
+Add a body tube and scroll all the way to the bottom and see ARR's airframe selections.\r
+\r
+Have fun!\r
+\r
+Sincerely,\r
+\r
+Always Ready Rocketry\r
+\r
+www.alwaysreadyrocketry.com\r
+\r
+ARRSALES@COX.NET\r
+\r
+\r
+\r
+\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/BHdata.csv b/core/resources-src/datafiles/rocksim_components/bms/BHdata.csv
new file mode 100644 (file)
index 0000000..718297e
--- /dev/null
@@ -0,0 +1,9 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+BalsaMachining.com,BHT70-F,2.175x.05thk fiber bulkhead,in.,0,2.175,.05,Fiber,0,g,0,1\r
+BalsaMachining.com,BHT70-W,2.175x.125thk lite-ply bulkhead,in.,0,2.175,.125,lite ply,0,g,0,1\r
+BalsaMachining.com,BHC70-F,2.104x.05thk fiber bulkhead,in.,0,2.178,.05,Fiber,0,g,0,1\r
+BalsaMachining.com,BHC70-W,2.104x.125thk lite-ply bulkhead,in.,0,2.178,.125,lite ply,0,g,0,1\r
+BalsaMachining.com,BHT80-F,2.558x.05thk fiber bulkhead,in.,0,2.558,.05,Fiber,0,g,0,1\r
+BalsaMachining.com,BHT80-W,2.558x.125 lite-ply bulkhead,in.,0,2.558,.125,lite ply,0,g,0,\r
+BalsaMachining.com,BHC80-F,2.474x.05thk fiber bulkhead,in.,0,2.556,.05,Fiber,0,g,0,1\r
+BalsaMachining.com,BHC80-W,2.474x.125thk lite-ply bulkhead,in.,0,2.556,.125,lite ply,0,g,0,1\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/BTdata.csv b/core/resources-src/datafiles/rocksim_components/bms/BTdata.csv
new file mode 100644 (file)
index 0000000..e4c5bc4
--- /dev/null
@@ -0,0 +1,31 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Mass units,Mass\r
+BalsaMachining.com,T2-34,0.246x0.220x.013x34,in.,0.220,0.246,34,Paper,1,oz,0\r
+BalsaMachining.com,T2PLUS-34,0.281x0.255x.013x34 (fits over T2),in.,0.255,0.281,34,Paper,1,oz,0\r
+BalsaMachining.com,T14LL-34,0.316x0.280x.018x34  1/4 inch Launch lug stock,in.,0.280,0.316,34,Paper,1,oz,0\r
+BalsaMachining.com,T4-34,.448x.432x.013x34 Apogee micro,in.,.432,.448,34,Paper,,g,0\r
+BalsaMachining.com,T4+34,.478x.452x.013x34 slips over T4,in.,.452,.478,34,Paper,,g,0\r
+BalsaMachining.com,T5-34,.544x.518x.013x34 Estes mini A,in.,.518,.544,34,Paper,,g,0\r
+BalsaMachining.com,T5-9,.544x.518 x.013 x9  Plain Kraft,in.,.518,.544,9,Paper,,g,0\r
+BalsaMachining.com,T20Q-34,.787x.748x.039x34 MPC/Quest T20,in.,.748,.787,34,Paper,,g,0\r
+BalsaMachining.com,T20-34,.736x.710x.013x34 Estes 18mm,in.,.710,.736,34,Paper,18,g,0\r
+BalsaMachining.com,T908-34,.908x.865x.022x34 Centuri ST-8,in.,.865,.908,34,Paper,,g,0\r
+BalsaMachining.com,T50-34,.976x.950x.013x34  24mm,in.,.95,.976,34,Paper,24,g,0\r
+BalsaMachining.com,T50H-34,. 990 x.950 x.020 x34  Heavy Wall,in.,.95,.990,34,Paper,1,oz,0\r
+BalsaMachining.com,T50MF-34,1.000x0.950x.025x34 metal foil lined,in.,.95,1.0,34,Paper,1,oz,0\r
+BalsaMachining.com,T104-34,1.040x1.00x.020 x 34 Centuri ST-10,in.,1,1.04,34,Paper,1,oz,0\r
+BalsaMachining.com,T52H-34,1.210x1.140x.035x34  29mm Motor Mount size,in.,1.14,1.210,34,Paper,29,g,0\r
+BalsaMachining.com,T55-34,1.325x1.283x.021,in.,1.283,1.325,34,Paper,,g,0\r
+BalsaMachining.com,T38-34,1.635x1.525x.055x34 38mm Motor Mount size,in.,1.525,1.635,34,Paper,38,g,0\r
+BalsaMachining.com,T60-34,1.637x1.595x.021,in.,1.595,1.637,34,Paper,,g,0\r
+BalsaMachining.com,T188-34,1.880x1.800x.040x34inch long  (Aerotech size),in.,1.8,1.88,34,Paper,,g,0\r
+BalsaMachining.com,T204-34,2.024x2.0x.021x34 Centuri ST-20,in.,2.0,2.024,34,Paper,,g,0\r
+BalsaMachining.com,T70-34,2.217x2.175x.021x34,in.,2.175,2.217,34,Paper,,g,0\r
+BalsaMachining.com,T70H-34,2.245x2.175x.035x34in long (white Heavy wall),in.,2.175,2.245,34,Paper,,g,0\r
+BalsaMachining.com,T80-34,2.600x2.558x.021x34in long,in.,2.558,2.6,34,Paper,,g,0\r
+BalsaMachining.com,T80H-34,2.640x2.558x.041x34in long (white Heavy wall),in.,2.558,2.64,34,Paper,,g,0\r
+BalsaMachining.com,T20-EMT,.736x.710x.013x2.75 Motor Tube,in.,.71,.736,2.75,Paper,18,g,0\r
+BalsaMachining.com,T50-EMT,.976x.950x.013x2.75 Motor Tube,in.,.95,.976,2.75,Paper,24,g,0\r
+BalsaMachining.com,T50H-EMT,.990x.950x.020x2.75 Motor Tube,in.,.95,.99,2.75,Paper,24,g,0\r
+BalsaMachining.com,T50HE-MT,.990x.950x.020x3.75 Motor Tube (E motors),in.,.95,.99,3.75,Paper,24,g,0\r
+BalsaMachining.com,T50F-MT,1.000x.950x.025x2.75  Foil Motor Tube,in.,.95,1.00,2.75,Paper,24,g,0\r
+BalsaMachining.com,T50FE-MT,1.000x.950x.025x3.75 Foil  Tube (E motors),in.,.95,1.00,3.75,Paper,24,g,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/CRdata.csv b/core/resources-src/datafiles/rocksim_components/bms/CRdata.csv
new file mode 100644 (file)
index 0000000..93ea99b
--- /dev/null
@@ -0,0 +1,61 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass units,Mass,AutoSize\r
+BalsaMachining.com,CR23-F,.348x.250x.05thk fiber,in.,.25,.348,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR24-F,.420x.250x.05thk fiber,in.,.25,.420,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR25-F,.516x.250x.05thk fiber,in.,.25,.516,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR220-F,.708x.250x.05thk fiber,in.,.25,.708,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR2+3-F,.348x.281x.05thk fiber,in.,.281,.348,.05,lite ply,0,g,0,0\r
+BalsaMachining.com,CR2+4-F,.420x.281x.05thk fiber,in.,.281,.420,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR2+5-F,.518x.281x.05thk fiber,in.,.281,.518,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR34-F,.420x.376x.05thk fiber,in.,.376,.420,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR35-P,.516x.376x.25thk paper (mini eng thrust ring),in.,.376,.516,.25,Paper,0,g,0,0\r
+BalsaMachining.com,CR35-F,.516x.376x.05thk fiber,in.,.376,.516,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR320-F,.708x.376x.05thk fiber,in.,.376,.708,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR45-F,.516x.450x.05thk fiber,in.,.450,.516,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR420-F,.708x.450x.05thk fiber,in.,.450,.708,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR450-F,.95x.450x.05thk fiber,in.,.450,.95,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR520-P,.708x.542x.25thk paper,in.,.546,.708,.25,Paper,0,g,0,0\r
+BalsaMachining.com,CR520-F,.703x.546x.05thk fiber,in.,.546,.703,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR520-W,.703x.546x.125thk lite-ply,in.,.546,.703,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR0550-F,.946x.546x.05thk fiber,in.,.546,.946,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR0550-W,.946x.546x.125thk lite ply,in.,.546,.946,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR0555-F,1.283x.546x.05thk fiber,in.,.546,1.283,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR0560-F,1.595x.546x.05thk fiber,in.,.546,1.595,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR2050-P,.946x.736x.25thk paper,in.,.736,.946,.25,Paper,0,g,0,0\r
+BalsaMachining.com,CR2050-F,.946x.736x.05thk fiber,in.,.736,.946,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR2050-W,.946x.736x.125thk lite ply,in.,.736,.946,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR2050-TW,.946x.736x.250thk lite ply,in.,.736,.946,.250,lite ply,0,g,0,0\r
+BalsaMachining.com,CR2055-F,1.283x.736x.05thk fiber,in.,.736,1.283,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR2055-W,1.283x.736x.125thk lite-ply,in.,.736,1.283,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR2060-F,1.593x.736x.05thk fiber,in.,.736,1.593,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR2060-W,1.593x.736x.125thk lite ply,in.,.736,1.593,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR2070-F,2.178x.736x.05thk fiber,in.,.736,2.178,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR2080-F,2.558x.736x.05thk fiber,in.,.736,2.558,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR20204-F,2.042x.736x.05thk fiber,in.,.736,2.024,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR20101-F,3.896x.736x.05thk fiber,in.,.736,3.896,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5052H-P,1.137x.977x.25thk paper,in.,.977,1.137,.25,Paper,0,g,0,0\r
+BalsaMachining.com,CR5052H-P1,1.137x.977x.50thk paper,in.,.977,1.137,.5,Paper,0,g,0,0\r
+BalsaMachining.com,CR5052H-F,1.14x.980x.05thk fiber,in.,.98,1.14,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5055-F,1.283x.978x.05thk fiber,in.,.978,1.283,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5055-W,1.283x.978x.125thk lite-ply,in.,.978,1.283,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR50H55-W,1.283x.990x.125thk lite-ply,in.,.990,1.283,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR5060-F,1.593x.978x.05thk fiber,in.,.978,1.593,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5060-W,1.593x.978x.125thk lite-ply,in.,.978,1.593,.05,lite ply,0,g,0,0\r
+BalsaMachining.com,CR50H60-F,1.593x.990x.05thk fiber,in.,.990,1.593,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5070-F,2.178x.978x.05thk fiber,in.,.978,2.178,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5070-W,2.178x.978x.125thk lite-ply,in.,.978,2.178,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR50H70-W,2.178x.990x.125thk lite-ply,in.,.990,2.178,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR5080-F,2.556x.978x.05thk fiber,in.,.978,2.556,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR50101-F,3.896x.978x.05thk fiber,in.,.978,3.896,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5080-W,2.556x.978x.125thk lite-ply,in.,.978,2.556,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR52H55-F,1.283x1.215x.05thk fiber,in.,1.215,1.283,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR52H60-F,1.592x1.215x.05thk fiber,in.,1.215,1.592,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR52H80-W,2.558x1.215x.125thk lite-ply,in.,1.215,2.558,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR5560-F,1.592x1.283x.05thk fiber,in.,1.283,1.592,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5570-F,2.217x1.283x.05thk fiber,in.,1.283,2.217,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR5570-W,2.178x1.325x.125thk lite-ply,in.,1.325,2.178,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR5580-F,2.558x1.283x.05thk fiber,in.,1.283,2.558,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR55101-F,3.896x1.283x.05thk fiber,in.,1.283,3.896,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR6070-F,2.217x1.595x.05thk fiber,in.,1.595,2.217,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR6070-W,2.175x1.637x.125thk lite-ply,in.,1.635,2.178,.125,lite ply,0,g,0,0\r
+BalsaMachining.com,CR6080-F,2.558x1.595x.05thk fiber,in.,1.595,2.558,.05,Fiber,0,g,0,0\r
+BalsaMachining.com,CR60101-F,3.896x1.595x.05thk fiber,in.,1.595,3.896,.05,Fiber,0,g,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/LLdata.csv b/core/resources-src/datafiles/rocksim_components/bms/LLdata.csv
new file mode 100644 (file)
index 0000000..54a6fe0
--- /dev/null
@@ -0,0 +1,6 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,3.126,0,0,0,0.205,1,Urethane,0.658,oz.,3.4,0,0,0,0,0,0,0,0,0,0,0,0\r
+BalsaMachining.com,LL18-125,1/8  x 1.25 inch LL,in.,.160,.169,1.25,Paper\r
+BalsaMachining.com,LL316-200,3/16 x 2 inch LL,in.,.219,.240,2,Paper\r
+BalsaMachining.com,LL316-1200,3/16 x 12 inch LL,in.,.214,.240,2,Paper\r
+BalsaMachining.com,LL14-300,0.316x0.280x.018x34  1/4 inch Launch lug,in.,0.280,0.316,3,Paper\r
+BalsaMachining.com,LL14-3400,0.316x0.280x.018x34  1/4 inch Launch lug,in.,0.280,0.316,34,Paper\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/MATERIAL.CSV b/core/resources-src/datafiles/rocksim_components/bms/MATERIAL.CSV
new file mode 100644 (file)
index 0000000..f062f55
--- /dev/null
@@ -0,0 +1,5 @@
+Material Name,Units,Density,Low,High,Class,Rocketry Use,Body Tubes,Fin Sets,Launch Lugs,Cords,Nose,Chute,Streamer,Trans,Ring,Bulkhead,Engine Block,Sleeve,Tube Coupler,spare,spare,spare,spare,spare,spare,spare,Fixed dim type,Fixed dim units,Fixed dim value,\r
+Fiber,lb/ft3,41,,,,1,0,0,0,0,0,0,0,0,1,1,0,0,0,,,,,,,,None,In.,0\r
+lite ply,lb/ft3,22,,,,1,0,1,0,0,0,0,0,0,1,1,1,0,0,,,,,,,,None,In.,0\r
+Balsa,lb/ft3,8,,,Wood,1,1,1,0,0,1,0,0,1,1,1,1,0,0,,,,,,,,None,0,0\r
+Paper,lb/ft3,70,,,,1,1,1,1,0,1,0,1,1,1,1,1,1,1,,,,,,,,None,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/NCdata.csv b/core/resources-src/datafiles/rocksim_components/bms/NCdata.csv
new file mode 100644 (file)
index 0000000..69a1f8c
--- /dev/null
@@ -0,0 +1,22 @@
+Mfg.,Part No.,Desc.,Units,Length,Outer Dia,L/D Ratio,Insert Length,Insert OD,Thickness,Shape,Config,Material,CG Loc,Mass Units,Mass,Base Ext. Len\r
+BalsaMachining.com,BMS20V2C,V2 Nose Cone w/bored hole,In.,2.25,0.73,0,0.50,0.71,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BMS60V2C,V2 cone with 4 inch deep bored hole,In.,5.25,1.63,0,0.75,1.59,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC20L,Estes CYL-Ogive,In.,1.40,0.73,0,0.50,0.71,0.00,Ogive,Solid,Balsa,0,oz,0,0.50\r
+BalsaMachining.com,BNC20N,Estes Classic,In.,2.70,0.73,0,0.50,0.71,0.00,Ogive,Solid,Balsa,0,oz,0,1.00\r
+BalsaMachining.com,BNC20R,Estes Classic,In.,2.75,0.73,0,0.50,0.71,0.00,Conical,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC20Y,Estes Classic,In.,1.05,0.73,0,0.50,0.71,0.00,Conical,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC30E,Estes-CYL-Ogive,In.,2.19,0.76,0,0.50,0.72,0.00,Ogive,Solid,Balsa,0,oz,0,0.30\r
+BalsaMachining.com,BNC30N,BT30 Ogive,In.,2.75,0.76,0,0.50,0.72,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC55F,V2 nose cone,In.,4.20,1.32,0,0.70,1.28,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC55O61,BT55 6:1 Ogive,In.,6.00,1.32,0,0.75,1.28,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC5AW,Estes Classic,In.,2.25,0.54,0,0.50,0.51,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC5AX,Estes-Ogive,In.,2.17,0.54,0,0.50,0.51,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC5E,Estes Classic,In.,1.38,0.54,0,0.50,0.51,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC5O51,BT5 5:1 Ogive,In.,2.72,0.54,0,0.40,0.51,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC5S,Estes Classic,In.,1.50,0.54,0,0.50,0.51,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BNC5W,Estes Classic,In.,2.80,0.54,0,0.50,0.51,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,BOMARC,Estes Citation BOMARC (bored hole),In.,4.15,1.32,0,0.90,1.28,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,CENBC107,Centuri Ogive,In.,5.25,1.04,0,0.50,1.00,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,CENBC79,Centuri Conical,In.,2.60,0.79,0,0.50,0.72,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,CENBC89,Centuri Ogive,In.,5.50,0.90,0,0.75,0.85,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
+BalsaMachining.com,CENV2NC,Centuri V2 nose cone w/ bored hole,In.,5.50,1.67,0,0.75,1.59,0.00,Ogive,Solid,Balsa,0,oz,0,0.00\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/TCdata.csv b/core/resources-src/datafiles/rocksim_components/bms/TCdata.csv
new file mode 100644 (file)
index 0000000..d6e3d55
--- /dev/null
@@ -0,0 +1,23 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+BalsaMachining.com,C5-2,.516x.474x2inch long T5 coupler,in.,.474,.516,2,Paper,0,oz.,0,1\r
+BalsaMachining.com,C20-3,.708x.666x3 inch long T20 coupler,in.,.666,.708,3,Paper,0,oz.,0,1\r
+BalsaMachining.com,C50-1,.948x.88x.034x1in long T50 coupler.,in.,.88,.948,1,Paper,0,oz.,0,1\r
+BalsaMachining.com,C50-4,.948x.88x.034x4in long T50 coupler.,in.,.88,.948,4,Paper,0,oz.,0,1\r
+BalsaMachining.com,C52H-4,1.137x.977x4 inch T52H coupler  .080thk,in.,.977,1.137,4,Paper,0,oz.,0,1\r
+BalsaMachining.com,C55-4,1.280x1.212x4 inch long T55 coupler,in.,1.212,1.28,4,Paper,0,oz.,0,1\r
+BalsaMachining.com,C60-4,1.592x1.524x4 inch long T60 coupler,in.,1.524,1.592,4,Paper,0,oz.,0,1\r
+BalsaMachining.com,C188-4,1.796x1.728x4 inch long T188 coupler,in.,1.728,1.796,4,Paper,0,oz.,0,1\r
+BalsaMachining.com,C204-4,1.997x1.929x4 inch long T204 coupler,in.,1.929,1.997,4,Paper,0,oz.,0,1\r
+BalsaMachining.com,C70-4,2.172x2.104x4 in long T70 or T70H coupler,in.,2.104,2.172,4,Paper,0,oz.,0,1\r
+BalsaMachining.com,C80-4,2.554x2.474x4in long T80 or T80H coupler,in.,2.474,2.554,4,Paper,0,oz.,0,1\r
+BalsaMachining.com,C80-6,2.554x2.474x6in T80 or T80H coupler stock,in.,2.474,2.554,6,Paper,0,oz.,0,1\r
+BalsaMachining.com,C5-34,.516x.474x34inch long T5 coupler stock,in.,.474,.516,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C20-34,.708x.666x34 inch long T20 coupler stock,in.,.666,.708,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C50-34,.948x.88x.034x34 T50 coupler stk.,in.,.88,.948,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C52H-34,1.137x.977x34inch T52H coupler stock .080thk,in.,.977,1.137,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C55-34,1.280x1.212x34 inch long T55 coupler stock,in.,1.212,1.28,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C60-34,1.592x1.524x34 inch long T60 coupler stock,in.,1.524,1.592,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C188-34,1.796x1.728x34 inch long T188 coupler stock,in.,1.728,1.796,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C204-34,1.997x1.929x34 inch long T204 coupler stock,in.,1.929,1.997,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C70-34,2.172x2.104x34in T70 or T70H coupler stock,in.,2.104,2.172,34,Paper,0,oz.,0,1\r
+BalsaMachining.com,C80-34,2.554x2.474x34in T80 or T80H coupler stock,in.,2.474,2.554,34,Paper,0,oz.,0,1\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/TRdata.csv b/core/resources-src/datafiles/rocksim_components/bms/TRdata.csv
new file mode 100644 (file)
index 0000000..8b22bf5
--- /dev/null
@@ -0,0 +1,21 @@
+Mfg.,Part No.,Desc.,Units,Front Insert Len,Front Insert OD,Front OD,Length,Rear OD,Core Dia.,Rear Insert Len,Rear Insert OD,Thickness,Config,Material,CG Loc,Mass Units,Mass,Shape,Shape Param,0,0,0,0,0,0,0,0,0,0\r
+BalsaMachining.com,BMS20V2B,V2 Boat-tail with 10mm bored hole,in.,0.50,0.71,0.73,1.62,0.52,0.40,0.00,0.00,,solid,Balsa,0,oz.,0,Ogive,0\r
+BalsaMachining.com,BMS50V2B,V2 Boat-tail with bored BT5 hole,in.,0.50,0.95,0.97,2.00,0.68,0.54,0.00,0.00,,solid,Balsa,0,,0,Ogive,0\r
+BalsaMachining.com,BMS60V2B,V2 Boat-tail with bored BT20 hole,in.,0.50,1.59,1.63,3.70,1.05,0.73,0.00,0.00,,solid,Balsa,0,,0,Ogive,0\r
+BalsaMachining.com,BMSV2BT1,V2 Boat-tail with bored BT50 hole,in.,0.50,1.59,1.63,3.70,1.11,0.97,0.00,0.00,,solid,Balsa,0,,0,Ogive,0\r
+BalsaMachining.com,BTC55Z,V2 Boat-tail with bored BT20 hole,in.,0.50,1.28,1.32,3.00,0.97,0.73,0.00,0.00,,solid,Balsa,0,,0,Ogive,0\r
+BalsaMachining.com,TA2050,Transition   T20 to T50  2 in long,in.,0.50,0.71,0.73,2.00,0.97,0,0.50,0.71,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA2050A,Transition   T20 to T50  1 in long,in.,0.50,0.71,0.73,1.00,0.97,0,0.75,0.95,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA2055,Transition   T20 to T55  1.5 in long,in.,0.50,0.71,0.73,1.50,1.63,0,0.75,1.28,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA2060,Transition   T20 to T80  0.84 in long,in.,0.75,0.71,0.73,0.84,2.60,0,0.75,2.55,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA5055,Transition   T50 to T55  1 in long,in.,0.75,0.95,0.97,1.00,1.63,0,0.75,1.28,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA5055L,Transiition  T50 to T55   1.5 in long,in.,0.75,0.95,0.97,1.50,1.63,0,0.75,1.28,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA5060,Transition   T50 to T60  2 in long,in.,0.75,0.95,0.97,2.00,1.63,0,0.75,1.59,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA520,Transition   T5 to T20  0.78 in long,in.,0.50,0.51,0.54,0.78,0.73,0,0.50,0.71,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA550,Transition   T5 to T50  1 in long,in.,0.50,0.51,0.54,1.00,0.97,0,0.50,0.95,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA555,Transiition   T5 to T55  2.75 in long,in.,0.75,0.51,0.54,2.75,1.63,0,0.75,1.28,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA5560,Transition   T55 to T60  1 long,in.,1.00,1.28,1.63,1.00,1.63,0,1.00,1.59,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA5560A,Transition    T55 to T60  1.3 in long,in.,0.75,1.28,1.63,1.30,1.63,0,0.75,1.59,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA6070,Transition   T60 to T70  1.75 in long,in.,0.60,1.59,1.63,1.50,2.21,0,0.60,2.17,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA6080,Transition   T60 to T80   2.25 in long,in.,1.25,1.59,1.63,2.25,2.60,0,1.50,2.55,,solid,Balsa,0,oz.,0,Conical,0\r
+BalsaMachining.com,TA7080,Transition T70 to T80 2 in long,in.,1.40,2.17,2.21,2.00,2.60,0,1.40,2.55,,solid,Balsa,0,oz.,0,Conical,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/bms/ebdata.csv b/core/resources-src/datafiles/rocksim_components/bms/ebdata.csv
new file mode 100644 (file)
index 0000000..0bd44da
--- /dev/null
@@ -0,0 +1,5 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+BalsaMachining.com,EB13-P,.516x.376x.25thk paper (mini eng thrust ring),in.,.376,.516,.25,Paper,,oz.,0,1\r
+BalsaMachining.com,EB18-P,.708x.542x.25thk paper (fits T20 tube),in.,.546,.708,.25,Paper,,oz.,0,1\r
+BalsaMachining.com,EB24-P,.946x.736x.25thk paper (fits T50 tube),in.,.736,.946,.25,Paper,,oz.,0,1\r
+BalsaMachining.com,EB29-P,1.137x.977x.50thk paper (fits T52H),in.,.977,1.137,.5,Paper,0,g,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/estes/BTDATA.CSV b/core/resources-src/datafiles/rocksim_components/estes/BTDATA.CSV
new file mode 100644 (file)
index 0000000..540f201
--- /dev/null
@@ -0,0 +1,18 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Mass Units,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass\r
+Estes,EST 3084,BT-5 Body Tube/18in,in,0.515,0.541,18,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 3085,BT-20 Body Tube/18in,in,0.71,0.736,18,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30338,BT-30 Body Tube/9in,in,0.725,0.765,9,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30351,BT-48BE Body Tube/2.5in,in,0.902,0.928,2.5,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 3086,BT-50 Body Tube/18in,in,0.95,0.976,18,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30376,BT-51N Body Tube/12.42in,in,0.984,1.011,12.42,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30380,BT-52S Body Tube/3.938in,in,0.988,1.114,3.938,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 3087,BT-55 Body Tube/18in,in,1.283,1.325,18,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 3088,BT-56 Body Tube/18in,in,1.304,1.346,18,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30394,BT-58 Body Tube/12.75in,in,1.498,1.54,12.75,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 3089,BT-60 Body Tube/18in,in,1.595,1.637,18,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30420,BT-63CJ Body Tube/3in,in,1.639,1.681,3,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30424,BT-70 Body Tube/17.5in,in,2.18,2.217,17.5,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 3090,BT-80 Body Tube/14.25in,in,2.588,2.6,14.25,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30174,RT-99D Body Tube/.391in,in,3.668,3.79,0.391,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30436,BT-100Z Body Tube/10.89in,in,3.702,3.744,10.89,Paper,,g,0,,,,,,,,,,,,,,,,,,,
+Estes,EST 30449,BT-101SV Body Tube/24.7in,in,3.896,3.938,24.7,Paper,,g,0,,,,,,,,,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/estes/EBDATA.CSV b/core/resources-src/datafiles/rocksim_components/estes/EBDATA.CSV
new file mode 100644 (file)
index 0000000..3ecc045
--- /dev/null
@@ -0,0 +1,2 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+Estes,30162-2,Eng. Block BT-20 / .2in,mm,16.5,18,5,Paper,2.5,g,0,0
diff --git a/core/resources-src/datafiles/rocksim_components/estes/LLDATA.CSV b/core/resources-src/datafiles/rocksim_components/estes/LLDATA.CSV
new file mode 100644 (file)
index 0000000..b0af60e
--- /dev/null
@@ -0,0 +1,4 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Estes,ESTES 1/8,1/8 in x 1.25in Launch lug,in,0.14,0.16,1.25,Paper,,,,,,,,,,,,,,,,,,,,,,
+Estes,ESTES 3/16,3/16 in x 2in Launch lug,in,0.219,0.24,2,Paper,,,,,,,,,,,,,,,,,,,,,,
+Estes,ESTES 1/4,1/4 in x 2in Launch lug,in,0.25,0.28,2,Paper,,,,,,,,,,,,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/estes/MATERIAL.CSV b/core/resources-src/datafiles/rocksim_components/estes/MATERIAL.CSV
new file mode 100644 (file)
index 0000000..5c9db02
--- /dev/null
@@ -0,0 +1,162 @@
+Material Name,Units,Density,Low,High,Class,Rocketry Use,Body Tubes,Fin Sets,Launch Lugs,Cords,Nose,Chute,Stream,Trans,Ring,Bulkhead,Engine Block,Sleeve,Tube Coupler,spare,spare,spare,spare,spare,spare,spare,Known Dim type,Known Dim Units,Known Dim Value\r
+,kg/m3,0,0,0,unknown,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+"G10 (PML 0.062"")",kg/m3,1309.,1309.,1309.,unknown,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+.060 Carbon Fiber,kg/m3,1400,1400,1400,Carbon Fiber,1,1,0,0,0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+.125 in Fiberglass/Honeycomb,lb/ft3,28.8,28.8,28.8,unknown,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+.25 in Fiberglass/Honeycomb,lb/ft3,14.7,14.7,14.7,unknown,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1 in. Flat Elastic,oz/in,0.0139,0.0139,0.0139,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1 in. Tubular Nylon,oz/in,0.04,0.04,0.04,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.1 Ounce Rip Stop Nylon,lb/ft3,0.0037351,0.0037351,0.0037351,Nylon,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.1 oz. Rip Stop Nylon,oz/in2,0.00085,0.00085,0.00085,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.3 oz. Ripstop Nylon (SkyAngle),oz/in2,0.001003,0.001003,0.001003,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.7 oz. Ripstop Nylon ,oz/in2,0.0013117,0.0013117,0.0013117,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.9 oz. Ripstop Nylon (SkyAngle),oz/in2,0.001466,0.001466,0.001466,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.9 oz. Ripstop Nylon (PML),oz/in2,0.002,0.002,0.002,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.9 oz. Ripstop Nylon ,oz/in2,0.001466,0.001466,0.001466,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/16 in. Aircraft Plywood,kg/m3,361.3765253,361.3765253,361.3765253,Wood,1,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/16 in. Braided Nylon,g/cm,0.0102,0.0102,0.0102,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/16 in. Round Elastic,g/cm,0.0183,0.0183,0.0183,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/2 in. Flat Elastic,oz/in,0.0028,0.0028,0.0028,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/2 in. Tubular Kevlar,oz/in,0.04,0.04,0.04,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/2 in. Tubular Nylon,lb/ft3,0.0038,0.0038,0.0038,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/32 in. Kevlar,g/cm,0.00659,0.00659,0.00659,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 Aircraft Plywood,kg/m3,344.269,344.269,344.269,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 in. Braided Nylon,lb/ft3,0.00408,0.00408,0.00408,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 in. Aircraft Plywood,kg/m3,344.2688068,344.2688068,344.2688068,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 In. Flat Elastic,g/cm,0.0402,0.0402,0.0402,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 in. Tubular Kevlar,oz/in,0.02,0.02,0.02,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 Aircraft Plywood,kg/m3,337.541,337.541,337.541,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in Birch Plywood (Revell),lb/ft3,40,40,40,unknown,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Aircraft Plywood,lb/ft3,42,42,42,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Braided Nylon,lb/ft3,0.00204,0.00204,0.00204,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Flat Elastic,g/cm,0.0205,0.0205,0.0205,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Flat Rubber,g/cm,0.0231,0.0231,0.0231,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Tubular Kevlar,oz/in,0.01,0.01,0.01,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+100 lb Kevlar (Apogee 29505),lb/ft3,0.000397,0.000397,0.000397,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+100 lb. Kevlar,lb/ft3,0.00205,0.00205,0.00205,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+100lb Kevlar (Apogee 29505),lb/ft3,0.000397,0.000397,0.000397,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1500 lb. Kevlar,lb/ft3,0.0059875,0.0059875,0.0059875,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1500lb Kevlar (Apogee 29507),lb/ft3,0.0059875,0.0059875,0.0059875,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+260 lb. Elastic,kg/m3,0,0,0,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/16 Aircraft Plywood,kg/m3,344.2688068,344.2688068,344.2688068,unknown,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/16 in. Aircraft Plywood,kg/m3,344.2688068,344.2688068,344.2688068,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/4 in. Flat Elastic,oz/in,0.011,0.011,0.011,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 in. Flat Elastic,lb/ft3,0.0038,0.0038,0.0038,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 in. Tubular Nylon ,oz/in,0.0166667,0.0166667,0.0166667,Nylon,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 in. Tubular Nylon (SkyAngle),oz/in,0.0166667,0.0166667,0.0166667,Nylon,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 inch Flat Elastic,lb/ft3,0.0038,0.0038,0.0038,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+"3/8"" tubular nylon (SkyAngle)",lb/ft3,0.186021,0.186021,0.186021,unknown,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+"3/8"" tubular nylon (SkyAngle)",lb/ft3,0.186021,0.186021,0.186021,unknown,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+30 Lb. Kevlar,g/cm,0.00178,0.00178,0.00178,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+300 lb. Kevlar (Apogee 29506),lb/ft3,0.0011286,0.0011286,0.0011286,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+300 lb. Kevlar,lb/ft3,0.0011286,0.0011286,0.0011286,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+300lb Kevlar (Apogee 29506),lb/ft3,0.0011286,0.0011286,0.0011286,unknown,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+4000 lb. nylon,kg/m3,0,0,0,Nylon,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+5/64 in. Round Elastic,g/cm,0.0242,0.0242,0.0242,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+5/8 in. Tubular Nylon,oz/in,0.02,0.02,0.02,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+5/8 in. Tubular Nylon (SkyAngle),oz/in,0.02,0.02,0.02,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+6000 lb. nylon,kg/m3,0,0,0,Nylon,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+6oz & 2oz FG & Poster board,kg/m3,798.85,798.85,798.85,Paper,1,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+7/16 in. Flat Braided Kevlar,oz/in,0.045,0.045,0.045,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+70 Lb. Kevlar,g/cm,0.0033,0.0033,0.0033,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+750 Lb. Kevlar,oz/in,0.0027,0.0027,0.0027,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+9/16 in. Tubular Nylon,oz/in,0.015,0.015,0.015,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Acrylic (Cast),lb/ft3,74,74,74,Acrylic,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Aircraft plywood (Birch),lb/ft3,45.26,43.56,46.96,Wood,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Aircraft plywood (LOC),lb/ft3,45.26,43.56,46.96,Wood,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Aluminum,kg/m3,2698.9,2698.9,2698.9,Metal,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Aluminum (Al),kg/m3,2698.9,2698.9,2698.9,Metal,1,0,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Aluminum 2024,kg/m3,2780,2780,2780,Metal,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Aluminum 7075,kg/m3,2810,2810,2810,Metal,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Ash,lb/ft3,42.5,40,45,Wood,1,0,1,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Balsa,lb/ft3,8,8,8,Wood,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+Basswood,lb/ft3,26.5,25,28,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Beech,lb/ft3,45,45,45,Wood,0,0,1,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Birch,lb/ft3,42.5,42.5,42.5,Wood,1,1,1,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Birch Plywood (Revell),lb/ft3,41,41,41,unknown,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Blue Tube,g/cm3,1.237,1.237,1.237,Paper,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Blue Tube 2,g/cm3,1.25,1.25,1.25,Paper,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Brass,lb/ft3,534,534,534,Metal,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Carbon Fiber,kg/m3,1400,1400,1400,Carbon Fiber,1,1,1,0,0,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Cardboard,lb/ft3,43,43,43,Cardboard,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Carpet String,g/cm,0.0032972,0.0032972,0.0032972,String,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Carpet String (Apogee 29500),g/cm,0.0032972,0.0032972,0.0032972,String,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Cellulose Acetate Propionate,lb/ft3,74.9,74.9,74.9,Plastic,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Chalk (Fine),lb/ft3,70,70,70,Chalk,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Copper (cast),lb/ft3,542,542,542,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Copper (rolled),lb/ft3,556,556,556,Metal,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Cork (Solid),lb/ft3,15,15,15,Cork,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Cottonwood,lb/ft3,25,25,25,Wood,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Composite Fin Material,lb/ft3,39.6,39.6,39.6,Cardboard,1,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Custom,kg/m3,0.,0.,0.,unknown,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Fiber,lb/ft3,41,41,41,Fiber ,1,1,0,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Fiberglass,lb/ft3,118.94,118.94,118.94,Fiberglass,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Fir (Douglas),lb/ft3,35,35,35,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Fir (White),lb/ft3,25,25,25,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 (PML 0.062"),lb/ft3,0.0044074,0.0044074,0.0044074,unknown,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 (PML 0.062),oz/in2,0.0714,0.0714,0.0714,Fiberglass,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 (PML 0.093),oz/in2,0.1143,0.1143,0.1143,Fiberglass,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 (PML 0.125),oz/in2,0.1404,0.1404,0.1404,Fiberglass,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 Fiberglass Filament Wound,kg/m3,1934,1934,1934,Fiberglass,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+G10 Fiberglass Filament Wound Tube,kg/m3,1820,1820,1820,Fiberglass,1,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+G10 Fiberglass,lb/ft3,135.8,135.8,135.8,Fiberglass,1,1,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+G10 Fiberglass (LOC),lb/ft3,118.94,118.94,118.94,Fiberglass,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 Phenolic,lb/ft3,118.94,118.94,118.94,Fiberglass,1,1,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+G12 Fiberglass,kg/m3,0.,0.,0.,unknown,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Glassed Phenolic,kg/m3,1900,1900,1900,unknown,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Gold (24 kt.),lb/ft3,1204,1204,1204,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Kevlar Thread (Apogee 29502),g/cm,0.0008858,0.0008858,0.0008858,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Kraft phenolic,lb/ft3,58.9,58.9,58.9,unknown,1,1,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Kraft phenolic (Glassed),kg/m3,1153.329336,1153.329336,1153.329336,Paper,1,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Lead (cast),lb/ft3,708,708,708,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Lead (rolled),lb/ft3,711,711,711,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Lead Shot,kg/m3,6727.75,6727.75,6727.75,Metal,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Leather,lb/ft3,59,59,59,Leather,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Lexan,g/cm3,1.218,1.218,1.218,Lexan,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Mat Board 4-Ply,kg/m3,710.579,710.579,710.579,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Spiral/Glassine-Thick,kg/m3,768.886,768.886,768.886,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Vulcanized Fiber,kg/m3,1250,1250,1250,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Lite Plywood,lb/ft3,22,22,22,Wood,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Mail Tube Paper,kg/m3,800,800,800,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Magna Phenolic,g/cm3,1.1,1.1,1.1,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Dyna-Wind Tubing,g/cm3,1.21,1.21,1.21,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Maple (Hard),lb/ft3,39.5,35,44,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Mylar,g/cm3,1.309,1.309,1.309,unknown,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Nickel 200,kg/m3,8890,8890,8890,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel 400,kg/m3,8800,8800,8800,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel 600,kg/m3,8410,8410,8410,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel 625,kg/m3,8440,8440,8440,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel 718,kg/m3,8230,8230,8230,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel C276,kg/m3,8890,8890,8890,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nylon,g/cm3,1.14,1.141.14,0,Nylon,1,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Oak (Brown),lb/ft3,45,45,45,Wood,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Oak (Red),lb/ft3,45,45,45,Wood,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Oak (White),lb/ft3,47,47,47,Wood,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Paper,lb/ft3,38,38,38,Paper,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Paper/2layers 8 oz.  glass,kg/m3,1681.94,1681.94,1681.94,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Pine (White Northern),lb/ft3,25,25,25,Wood,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+Pine (White Western),lb/ft3,27,27,27,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+Plastic,kg/m3,920,920,920,Plastic,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Polycarbonate,lb/ft3,74.9,74.9,74.9,Plastic,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Polyethylene,kg/m3,920,920,920,Plastic,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Polyethylene LDPE,lb/ft3,57.7,57.7,57.7,Plastic,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Polystyrene PS,lb/ft3,65.5,65.5,65.5,Plastic,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Poplar (Yellow),lb/ft3,30,30,30,Wood,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+PVC,lb/ft3,81.2,81.2,81.2,Plastic,1,1,1,0,0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Quantum Tubing,g/cm3,1.1,1.1,1.1,Paper,1,1,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Rip stop nylon,g/cm2,0.006685,0.006685,0.006685,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Rocketwood,lb/ft3,33.03,33.03,33.03,Wood,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Russian 1/8 in. Plywood,kg/m3,685.1,685.1,685.1,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Silver,lb/ft3,653,653,653,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Spiral/Glassine,lb/ft3,53,53,53,Paper,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Spruce,lb/ft3,28,28,28,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Stainless steel 17-4PH,kg/m3,7600,7600,7600,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Stainless steel 17-5PH,kg/m3,7800,7800,7800,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Stainless steel 17-7PH,kg/m3,7800,7800,7800,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Steel,kg/m3,7850,7850,7850,Metal,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Steel 4130,kg/m3,7850,7850,7850,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Steel 4340,kg/m3,7850,7850,7850,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Sycamore,lb/ft3,35,35,35,Wood,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Titanium,kg/m3,4500,4500,4500,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Urethane,lb/ft3,52.88,52.88,52.88,unknown,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+lite ply,kg/m3,352.406186,352.406186,352.406186,Wood,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/estes/MODATA.CSV b/core/resources-src/datafiles/rocksim_components/estes/MODATA.CSV
new file mode 100644 (file)
index 0000000..cd05f1d
--- /dev/null
@@ -0,0 +1,3 @@
+Mfg.,Part no,Desc,Units,Name,Type,Length,Material,Mass units,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass\r
+Estes,Engine Hook Mini,Mini size,in,Engine hook,general,0,Steel,g,1.01,,,,,,,,,
+Estes,Engine Hook Standard,Engine Hook-Standard size,in,Engine hook,general,0,Steel,g,1.4,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/estes/NCDATA.CSV b/core/resources-src/datafiles/rocksim_components/estes/NCDATA.CSV
new file mode 100644 (file)
index 0000000..7b62048
--- /dev/null
@@ -0,0 +1,32 @@
+Mfg.,Part No.,Desc.,Units,Length,Outer Dia,L/D Ratio,Insert Length,Insert OD,Thickness,Shape,Config,Material,CG Loc,Mass Units,Mass,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len\r
+Estes,BNC-5E ,Balsa Nose cone,in,1.38,0.544,0,0.25,0.519,0,parabolic,solid,Balsa,0.812,oz,0.02,0,,,,,,,,,,,,,
+Estes,PNC-5A,Plastic Nose cone,in,2.125,0.544,0,0.5,0.519,0.0625,parabolic,hollow,Polystyrene PS,0,oz,0.1,0,,,,,,,,,,,,,
+Estes,BNC-5S ,Balsa Nose cone,in,1.5,0.544,0,0.25,0.519,0,cone,solid,Balsa,0.875,oz,0.016,0,,,,,,,,,,,,,
+Estes,BNC-5V ,Balsa Nose cone,in,0.75,0.544,0,0.25,0.519,0,parabolic,solid,Balsa,0.5,oz,0.013,0,,,,,,,,,,,,,
+Estes,BNC-5W ,Balsa Nose cone,in,2.8,0.544,0,0.25,0.519,0,ogive,solid,Balsa,1.525,oz,0.039,0,,,,,,,,,,,,,
+Estes,BNC-20AM ,Balsa Nose cone,in,2,0.736,0,0.5,0.71,0,parabolic,solid,Balsa,1.25,oz,0.06,0,,,,,,,,,,,,,
+Estes,BNC-20B ,Balsa Nose cone,in,1.7,0.736,0,0.5,0.71,0,parabolic,solid,Balsa,1.1,oz,0.05,0,,,,,,,,,,,,,
+Estes,BNC-20R ,Balsa Nose cone,in,2.75,0.736,0,0.5,0.71,0,cone,solid,Balsa,1.625,oz,0.07,0,,,,,,,,,,,,,
+Estes,PNC-20Y,Plastic Nose cone,in,0.95,0.736,0,0.5,0.71,0,cone,hollow,Polystyrene PS,0,oz,0.1,0,,,,,,,,,,,,,
+Estes,BNC-20Y ,Balsa Nose cone,in,0.95,0.736,0,0.5,0.71,0,cone,solid,Balsa,0.725,oz,0.02,0,,,,,,,,,,,,,
+Estes,DART ,Plastic Nose cone,in,2.88,0.736,0,0.5,0.71,0.0625,ogive,hollow,Polystyrene PS,0,g,0,0,,,,,,,,,,,,,
+Estes,PNC-20,Plastic Nose cone,in,2.65,0.736,0,0.5,0.71,0.0625,ogive,hollow,Polystyrene PS,1.77,g,3.35,0,,,,,,,,,,,,,
+Estes,PNC-50YR,Plastic Nose cone,in,4.125,0.976,0,0.75,0.95,0.125,parabolic,hollow,Polystyrene PS,0,oz,0.3,0,,,,,,,,,,,,,
+Estes,BNC-50J ,Balsa Nose cone,in,1.37,0.976,0,0.5,0.95,0,parabolic,solid,Balsa,0.935,oz,0.08,0,,,,,,,,,,,,,
+Estes,BNC-50K ,Balsa Nose cone,in,2.75,0.976,0,0.5,0.95,0,ogive,solid,Balsa,1.625,oz,0.13,0,,,,,,,,,,,,,
+Estes,BNC-50KA,Balsa Nose cone,in,2.735,0.976,0,0.75,0.95,0,ogive,solid,Balsa,1.7425,oz,0.13,0,,,,,,,,,,,,,
+Estes,BNC-50Y ,Balsa Nose cone,in,4.35,0.976,0,0.5,0.95,0,ogive,solid,Balsa,2.425,oz,0.16,0,,,,,,,,,,,,,
+Estes,PNC-55BB,Plastic Nose cone,in,6.5,1.325,0,1.25,1.283,0.125,cone,hollow,Polystyrene PS,0,oz,0.5,0,,,,,,,,,,,,,
+Estes,PNC-55AC ,Plastic Nose cone,in,5.403,1.325,0,0.75,1.283,0.125,ogive,hollow,Polystyrene PS,2.9515,oz,0.4,0,,,,,,,,,,,,,
+Estes,PNC-55 ,Plastic Sentinal Nose cone,in,8.375,1.325,0,1,1.283,0.125,ogive,hollow,Polystyrene PS,2.95,g,24.8058,0,,,,,,,,,,,,,
+Estes,PNC-56,Plastic Nose cone,in,6.375,1.346,0,0.75,1.3,0.125,parabolic,hollow,Polystyrene PS,0,oz,0.6,0,,,,,,,,,,,,,
+Estes,PNC-60A,Plastic Nose cone,mm,120.65000000000001,41.580000000000005,0.,19.050000000000001,40.513000000000005,2.3876,ogive,hollow,Polystyrene PS,76.200000000000003,g,24.380600000000001,0.
+Estes,PNC-60AH ,Plastic Nose cone,in,6.75,1.637,0,0.8,1.595,0.125,parabolic,hollow,Polystyrene PS,3.775,oz,1,0,,,,,,,,,,,,,
+Estes,PNC-60L ,Plastic Nose cone,in,2.5,1.637,0,0.75,1.595,0.125,elliptical,hollow,Polystyrene PS,1.625,g,11.056,0,,,,,,,,,,,,,
+Estes,PNC-60MS ,Plastic Nose cone,in,2.5,1.637,0,0.75,1.595,0.125,parabolic,hollow,Polystyrene PS,1.625,oz,0.5,0,,,,,,,,,,,,,
+Estes,PNC-60NA,Plastic Nose cone,in,4.75,1.637,0,0.75,1.595,0.125,ogive,hollow,Polystyrene PS,0,oz,0.6,0,,,,,,,,,,,,,
+Estes,BNC-70AJ ,Balsa Nose cone,in,4.4,2.217,0,0.75,2.18,0,parabolic,solid,Balsa,2.575,oz,0.85,0,,,,,,,,,,,,,
+Estes,PNC-80BB ,Plastic Nose cone,in,4,2.6,0,1.75,2.558,0.125,parabolic,hollow,Polystyrene PS,2.875,oz,1.3,0,,,,,,,,,,,,,
+Estes,PNC-80FB,Estes PNC-80 Fat Boy profile cone,mm,101.6,66.04,0,38.1,64.922,3.175,elliptical,hollow,Polystyrene PS,0,g,35.892,0,,,,,,,,,,,,,
+Estes,PNC-80K ,Plastic Nose cone,in,8.15,2.6,0,1,2.558,0.125,ogive,hollow,Polystyrene PS,4.575,oz,1.68,0,,,,,,,,,,,,,
+Estes,PNC-55AO,Elliptical,mm,127,33.655,0,15.24,32.588,2.3876,elliptical,hollow,Polystyrene PS,100.99,g,12.19,0,,,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/estes/PCDATA.CSV b/core/resources-src/datafiles/rocksim_components/estes/PCDATA.CSV
new file mode 100644 (file)
index 0000000..6a9b4d7
--- /dev/null
@@ -0,0 +1,8 @@
+Mfg.,Part No.,Desc.,Units,n sides,OD,ID,Shroud Count,Shroud Len,Shroud Material,Chute Thickness,Chute Material,Mass Units,Mass,CG,Cd,AutoSize,AutoSize,AutoSize,AutoSize,0,0,0,0,0,0,0,0,0,0\r
+Estes,302260,18 in. nylon,mm,8,457.2,0,8,609.6,1/16 in. Braided Nylon,1.016,Rip stop nylon,g,10.48,0,0.75,,,,,,,,,,,,,,
+Estes,302262,6 in. Plastic Chute,mm,6,152.4,0,6,152.4,Carpet String,0.051,Polyethylene LDPE,g,0,0,0.75,,,,,,,,,,,,,,
+Estes,302264,12 in. Plastic Chute,in,6,12,0,6,12,Carpet String,0.002,Polyethylene LDPE,oz,0.072,0,0.75,,,,,,,,,,,,,,
+Estes,302260,18 in. Nylon Chute,in,8,18,0,8,24,Carpet String,0.002,Rip stop nylon,g,10.48,0,0.75,,,,,,,,,,,,,,
+Estes,302267,18 in. Plastic Chute,in,6,18,0,6,18,Carpet String,0.002,Polyethylene LDPE,oz,0.208,0,0.75,,,,,,,,,,,,,,
+Estes,82426-30,24 in. Nylon Chute,in,8,24,0,8,29.5,Carpet String,0.002,Rip stop nylon,g,23.1,0,0.75,,,,,,,,,,,,,,
+Estes,302271,24 in. Plastic Chute,in,8,24,0,8,24,Carpet String,0.002,Polyethylene LDPE,oz,0.274,0,0.75,,,,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/estes/TCDATA.CSV b/core/resources-src/datafiles/rocksim_components/estes/TCDATA.CSV
new file mode 100644 (file)
index 0000000..4b1ef47
--- /dev/null
@@ -0,0 +1,11 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize\r
+Estes,JT-5C,Tube Coupler/.51 x .75in,in,0.45,0.51,0.75,Paper,0.375,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,JT-20C,Tube Coupler/.71 x .75in,in,0.645,0.705,0.75,Paper,0.375,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,JT-50C,Tube Coupler/.95 x 1in,in,0.885,0.945,1,Paper,0.5,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,JT-55C,Tube Coupler/1.28 x 1.25in,in,1.216,1.276,1.25,Paper,0.638,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,JT-60C,Tube Coupler/1.59 x 1.5in,in,1.53,1.59,1.5,Paper,0.75,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,JT-70A,Tube Coupler/2.17 x 2in,in,2.09,2.17,2,Paper,1,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,JT-80C,Tube Coupler/2.55 x 3in,in,2.47,2.55,3,Paper,1.5,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,JT-101SV,Tube Coupler/3.9 x 1.375in,in,3.81,3.89,1.375,Paper,0.6875,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,NB-20,Balsa Tube Coupler/.71 x .75in,in,0,0.705,0.75,Balsa,0.375,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Estes,NB-50,Balsa Tube Coupler/.95 x 1in,in,0,0.945,1,Balsa,0.5,oz,0,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/estes/TRDATA.CSV b/core/resources-src/datafiles/rocksim_components/estes/TRDATA.CSV
new file mode 100644 (file)
index 0000000..994a113
--- /dev/null
@@ -0,0 +1,3 @@
+Mfg.,Part No.,Desc.,Units,Front Insert Len,Front Insert OD,Front OD,Length,Rear OD,Core Dia.,Rear Insert Len,Rear Insert OD,Thickness,Config,Material,CG Loc,Mass Units,Mass,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape\r
+Estes,30101,BULL PUB BT-55 Tail cone,mm,22,32.1,33.7,29,25,0,0,0,2.2,hollow,Polystyrene PS,28,g,4,cone,,,,,,,,,,,
+Estes,BNC-80K [R],Custom Tail Cone,mm,25.4,64.973,67.056,152.4,31.75,0,0,0,3.175,solid,Balsa,0,g,0,1,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/BHDATA.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/BHDATA.CSV
new file mode 100644 (file)
index 0000000..be24b0b
--- /dev/null
@@ -0,0 +1,7 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine\r
+Giant Leap,BH-2.15,2.15 in. Bulkhead,mm,0.,54.609999999999999,5.08,Birch,0.,g,0.,0,,,,,,,\r
+Giant Leap,BH-2.56,2.56 in. Bulkhead,mm,0.,65.024000000000001,5.08,Birch,0.,g,0.,0,,,,,,,\r
+Giant Leap,BH-3.00,3.00 in. Bulkhead,mm,0.,76.200000000000003,5.08,Birch,0.,g,0.,0,,,,,,,\r
+Giant Leap,BH-3.90,3.90 in. Bulkhead,mm,0.,99.060000000000002,5.08,Birch,0.,g,0.,0,,,,,,,\r
+Giant Leap,BH-6.00,6.00 in. Bulkhead,mm,0.,152.40000000000001,12.699999999999999,Birch,0.,g,0.,0,,,,,,,\r
+Giant Leap,BH-7.51,7.51 in. Bulkhead,mm,0.,190.8048,12.699999999999999,Birch,0.,g,0.,0,,,,,,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/BTDATA.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/BTDATA.CSV
new file mode 100644 (file)
index 0000000..7570988
--- /dev/null
@@ -0,0 +1,27 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,,,,,,,\r
+Giant Leap,B-1.145,29mm BT,mm,29.083,32.131,914.4,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-1.525,38mm BT,mm,38.735,41.7068,914.4,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-1.525-L,38mm BT,mm,38.735,41.91,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-2.152,54mm BT,mm,54.661,57.6834,914.4,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-2.152-L,54mm BT,mm,54.661,57.658,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-2.56,2.56 BT,mm,65.024,68.072,914.4,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-3.00,3.00 BT,mm,76.2,77.851,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-3.00-L,3.00 BT,mm,76.2508,79.375,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-3.90,3.90 BT,mm,99.06,101.854,914.4,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-3.90-L,3.90 BT,mm,99.06,102.108,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-6.00,6.00 BT,mm,152.4,155.575,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,B-7.50,7.50 BT,mm,190.8,195.07,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,MAG 1.5 x 48,38mm Magnaframe Tube,mm,38.735,42.164,1219.2,Kraft phenolic,,,,,,,2.3,58.42\r
+Giant Leap,MAG 2.1 x 48,54mm Magnaframe Tube,mm,54.661,58.42,1219.2,Kraft phenolic,,,,,,,2.71,68.834\r
+Giant Leap,MAG 2.5 x 48,2.56  Magnaframe Tube,mm,65.024,68.834,1219.2,Kraft phenolic,,,,,,,3.15,80.01\r
+Giant Leap,MAG 3.0 x 48,75mm  Magnaframe Tube,mm,76.2,80.01,1219.2,Kraft phenolic,,,,,,,4.05,102.87\r
+Giant Leap,MAG 3.9 x 48,98mm  Magnaframe Tube,mm,99.06,102.87,1219.2,Kraft phenolic,,,,,,,6.15,156.21\r
+Giant Leap,MAG 6.0 x48,6.0  Magnaframe Tube,mm,152.4,156.21,1219.2,Kraft phenolic,,,,,,,7.67,194.818\r
+.Giant Leap,PH 7.5 x 48,7.5  Magnaframe Tube,mm,190.8,194.818,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,DY/MAG 1.5 x 48,38mm Dynawind + Magnaframe Airframe,mm,38.735,42.418,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,DY/MAG 2.1 x 48,54mm Dynawind + Magnaframe Airframe,mm,54.661,58.674,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,DY/MAG 2.5 x 48,2.56 Dynawind + Magnaframe Airframe,mm,65.024,69.088,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,DY/MAG 3.0 x 48,75mm Dynawind + Magnaframe Airframe,mm,76.2,80.772,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,DY/MAG 3.9 x 48,98mm Dynawind + Magnaframe Airframe,mm,99.06,103.632,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,DY/MAG 6.0 x 48,6.0 Dynawind + Magnaframe Airframe,mm,152.4,157.48,1219.2,Kraft phenolic,,,,,,,,\r
+Giant Leap,DY/PH 7.5 x 48,7.5 Dynawind + Magnaframe Airframe,mm,190.8,196.596,1219.2,Kraft phenolic,,,,,    (don't have this in Magnaframe yet),,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/CRDATA.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/CRDATA.CSV
new file mode 100644 (file)
index 0000000..eb655f6
--- /dev/null
@@ -0,0 +1,21 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine\r
+Giant Leap,CR-2.56/29,CR 2.56/29mm,mm,29.,65.024000000000001,3.81,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-2.56/38,CR 2.56/38mm,mm,38.,65.024000000000001,3.81,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-2.56/54,CR 2.56/54mm,mm,54.,65.024000000000001,3.81,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-3.00/29,CR 3.00/29mm,mm,29.,76.250999999999991,5.08,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-3.00/38,CR 3.00/38mm,mm,38.,76.250799999999998,5.08,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-3.00/54,CR 3.00/54mm,mm,54.,76.250999999999991,5.08,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-3.90/29,CR 3.90/29mm,mm,29.,99.060000000000002,5.08,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-3.90/38,CR 3.90/38mm,mm,38.,99.060000000000002,5.08,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-3.90/54,CR 3.90/54mm,mm,54.,99.060000000000002,5.08,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-3.90/76,CR 3.90/76mm,mm,76.,99.060000000000002,5.08,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-38/29,CR 38/29mm,mm,29.,38.,12.699999999999999,Cardboard,0.,,,,,,,,,,\r
+Giant Leap,CR-54/38,CR 54/38mm,mm,38.,54.,17.779999999999998,Cardboard,0.,,,,,,,,,,\r
+Giant Leap,CR-6.00/38,CR 6.00/38mm,mm,38.,152.40000000000001,12.699999999999999,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-6.00/54,CR 6.00/54mm,mm,54.,152.40000000000001,12.699999999999999,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-6.00/76,CR 6.00/76mm,mm,76.,152.40000000000001,12.699999999999999,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-6.00/98,CR 6.00/98mm,mm,98.,152.40000000000001,12.699999999999999,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-7.50/54,CR 7.50/54mm,mm,54.,190.5,12.699999999999999,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-7.50/76,CR 7.50/76mm,mm,76.,190.5,12.699999999999999,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-7.50/98,CR 7.50/98mm,mm,98.,190.5,12.699999999999999,Birch,0.,,,,,,,,,,\r
+Giant Leap,CR-2.56-54,CR 2.56-54mm,mm,54.,59.689999999999998,6.35,Birch,0.,,,,,,,,,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/LLDATA.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/LLDATA.CSV
new file mode 100644 (file)
index 0000000..090ac8d
--- /dev/null
@@ -0,0 +1,3 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material\r
+Giant Leap,LL,ACME Launch Lug,mm,10.16,12.700000000000001,25.400000000000002,\r
+Giant Leap,RG,ACME Rail Guide,mm,10.16,12.700000000000001,25.400000000000002,\r
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/MATERIAL.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/MATERIAL.CSV
new file mode 100644 (file)
index 0000000..462e87d
--- /dev/null
@@ -0,0 +1,6 @@
+Material Name,Units,Density,Low,High,Class,Rocketry Use,Body Tubes,Fin Sets,Launch Lugs,Cords,Nose,Chute,Stream,Trans,Ring,Bulkhead,Engine Block,Sleeve,Tube Coupler,spare,spare,spare,spare,spare,spare,spare,Known Dim type,Known Dim Units,Known Dim Value
+Cardboard,lb/ft3,43,,,,1,1,1,1,0,1,0,0,1,1,1,1,1,1,,,,,,,,None,0,0
+Birch,lb/ft3,42.5,,,Wood,1,0,1,0,0,1,0,1,1,1,1,1,0,0,,,,,,,,None,0,0
+Kraft phenolic,lb/ft3,59.85,,,,1,1,0,0,0,0,0,0,0,1,0,0,1,1,,,,,,,,None,0,0
+Polycarbonate,lb/ft3,74.9,,,,1,1,1,1,0,1,0,0,1,1,1,1,1,1,,,,,,,,None,0,0
+Rip stop nylon,g/cm2,0.006685,,,,1,0,0,0,0,0,1,1,0,0,0,0,0,0,,,,,,,,None,0,0
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/MODATA.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/MODATA.CSV
new file mode 100644 (file)
index 0000000..c5dda06
--- /dev/null
@@ -0,0 +1,29 @@
+Mfg.,Part no,Desc,Units,Name,Type,Length,Material,Mass units,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass\r
+Giant Leap,LG-Fireball,Large Fireball,mm,Mass object,general,7620.,1 in. tubular nylon,g,130.40780000000001,,,,,,,,,\r
+Giant Leap,Shockloop,9-16in 12ft Nylon Loop,mm,Mass object,shockcord,3657.6000000000004,9/16 In. tubular nylon,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-1-15,1in 15ft Nylon Loop,mm,Mass object,shockcord,4572.,1 in. tubular nylon,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-1-20,1in 20ft Nylon Loop,mm,Mass object,shockcord,6096.,1 in. tubular nylon,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-1-25,1in 25ft Nylon Loop,mm,Mass object,shockcord,7620.,1 in. tubular nylon,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-1/2-15,1/2in 15ft Kevlar Loop,mm,Mass object,shockcord,4572.,1/2 in. tubular kevlar,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-1/2-20,1/2in 20ft Kevlar Loop,mm,Mass object,shockcord,6096.,1/2 in. tubular kevlar,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-1/2-25,1/2in 25ft Kevlar Loop,mm,Mass object,shockcord,7620.,1/2 in. tubular kevlar,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-1/4-15,1/4in 15ft Kevlar Loop,mm,Mass object,shockcord,4572.,1/4 in. tubular kevlar,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-1/4-20,1/4in 20ft Kevlar Loop,mm,Mass object,shockcord,6096.,1/4 in. tubular kevlar,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-916-12,9-16in 12ft Nylon Loop,mm,Mass object,shockcord,3657.6000000000004,9/16 In. tubular nylon,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-916-15,9-16in 15ft Nylon Loop,mm,Mass object,shockcord,4572.,9/16 In. tubular nylon,g,0.,,,,,,,,,\r
+Giant Leap,Shockloop-916-25,9-16in 25ft Nylon Loop,mm,Mass object,shockcord,7620.,9/16 In. tubular nylon,g,0.,,,,,,,,,\r
+Giant Leap,SLIM38,Slimline 38mm Retainer,mm,Mass object,general,0.,,g,31.1845,,,,,,,,,\r
+Giant Leap,SLIM38-29,Slimline 38-29mm Adapter,mm,Mass object,general,0.,,g,73.708799999999997,,,,,,,,,\r
+Giant Leap,SLIM54,Slimline 54mm Retainer,mm,Mass object,general,0.,,g,42.524300000000004,,,,,,,,,\r
+Giant Leap,SLIM54-38,Slimline 54-38mm Adapter,mm,Mass object,general,0.,,g,119.06800000000001,,,,,,,,,\r
+Giant Leap,SLIM76,Slimline 76mm Retainer,mm,Mass object,general,0.,,g,99.223300000000009,,,,,,,,,\r
+Giant Leap,SLIM76-54,Slimline 76-54mm Adapter,mm,Mass object,general,0.,,g,238.13600000000002,,,,,,,,,\r
+Giant Leap,SLIM98,Slimline 98mm Retainer,mm,Mass object,general,0.,,g,107.7282,,,,,,,,,\r
+Giant Leap,SLIM98-76,Slimline 98-76mm Adapter,mm,Mass object,general,0.,,g,518.79629999999997,,,,,,,,,\r
+Giant Leap,SM-Fireball,Small Fireball,mm,Mass object,general,7620.,1 in. tubular nylon,g,56.699100000000001,,,,,,,,,\r
+Giant Leap,TC54-38,Slimline 54-38mm Tailcone,mm,Mass object,general,7620.,1 in. tubular nylon,g,127.5729,,,,,,,,,\r
+Giant Leap,TC76-38,Slimline 76-38mm Tailcone,mm,Mass object,general,7620.,1 in. tubular nylon,g,93.553400000000011,,,,,,,,,\r
+Giant Leap,TC76-54,Slimline 76-54mm Tailcone,mm,Mass object,general,7620.,1 in. tubular nylon,g,127.5729,,,,,,,,,\r
+Giant Leap,TC98-54,Slimline 98-54mm Tailcone,mm,Mass object,general,7620.,1 in. tubular nylon,g,144.58260000000001,,,,,,,,,\r
+Giant Leap,TC98-76,Slimline 98-76mm Tailcone,mm,Mass object,general,7620.,1 in. tubular nylon,g,155.92240000000001,,,,,,,,,\r
+Giant Leap,SLIM29,Slimline 29mm Retainer,mm,Mass object,general,0.,,g,14.174800000000001,,,,,,,,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/NCDATA.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/NCDATA.CSV
new file mode 100644 (file)
index 0000000..1959244
--- /dev/null
@@ -0,0 +1,6 @@
+Mfg.,Part No.,Desc.,Units,Length,Outer Dia,L/D Ratio,Insert Length,Insert OD,Thickness,Shape,Config,Material,CG Loc,Mass Units,Mass,Mass\r
+Giant Leap,NC-2.56,2.56 in. Nosecone,mm,228.60000000000002,65.024000000000001,0.,0.,0.,1.778,ogive,hollow,Polycarbonate,0.,g,0.,55.880000000000003\r
+Giant Leap,NC-3.00,3.00 in. Nosecone,mm,285.75,76.200000000000003,0.,0.,0.,1.778,ogive,hollow,Polycarbonate,0.,g,0.,76.200000000000003\r
+Giant Leap,NC-38,38mm Nosecone,mm,203.20000000000002,38.,0.,0.,0.,4.318000000000001,ogive,hollow,Polycarbonate,0.,g,0.,44.450000000000003\r
+Giant Leap,NC-54,54mm Nosecone,mm,279.40000000000003,54.,0.,0.,0.,2.286,ogive,hollow,Polycarbonate,0.,g,0.,76.200000000000003\r
+Giant Leap,NC-3.90,3.90 in. Nosecone,mm,419.10000000000002,99.060000000000002,0.,0.,0.,2.032,ogive,hollow,Polycarbonate,0.,g,0.,83.820000000000007\r
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/PCDATA.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/PCDATA.CSV
new file mode 100644 (file)
index 0000000..e7290bc
--- /dev/null
@@ -0,0 +1,6 @@
+Mfg.,Part No.,Desc.,Units,n sides,OD,ID,Shroud Count,Shroud Len,Shroud Material,Chute Thickness,Chute Material,Mass Units,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass\r
+Giant Leap,TAC-24,TAC-1 24 in. Parachute,mm,6,609.60000000000002,0.,6,0.,,0.076,Rip stop nylon,g,153.08699999999999,0.,0.75\r
+Giant Leap,TAC-36,TAC-1 36 in. Parachute,mm,6,914.39999999999998,0.,6,0.,,0.076,Rip stop nylon,g,229.631,0.,0.75\r
+Giant Leap,TAC-48,TAC-1 48 in. Parachute,mm,6,1219.2,0.,6,0.,,0.076,Rip stop nylon,g,306.17500000000001,0.,0.75\r
+Giant Leap,TAC-60,TAC-1 60 in. Parachute,mm,6,1524.,0.,6,0.,,0.076,Rip stop nylon,g,405.39800000000002,0.,0.75\r
+Giant Leap,TAC-72,TAC-1 72 in. Parachute,mm,6,1828.8,0.,6,0.,,0.076,Rip stop nylon,g,510.291,0.,0.75\r
diff --git a/core/resources-src/datafiles/rocksim_components/giantleaprocketry/TCDATA.CSV b/core/resources-src/datafiles/rocksim_components/giantleaprocketry/TCDATA.CSV
new file mode 100644 (file)
index 0000000..3ce0999
--- /dev/null
@@ -0,0 +1,11 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Mass Units,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass\r
+Giant Leap,C-2.15,2.15 CT,mm,51.308,54.61,101.6,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-2.15-L,2.15 CT,mm,51.562,54.61,927.1,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-2.56,2.56 CT,mm,62.738,65.024,127,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-2.56-L,2.56 CT,mm,62.738,65.024,927.1,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-3.00,3.0 CT,mm,73.66,76.2,127,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-3.00-L,3.0 CT,mm,73.66,76.2,927.1,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-3.90,3.9 CT,mm,96.266,99.06,177.8,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-3.90-L,3.9 CT,mm,96.266,99.06,927.1,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-6.007-L,6.0 CT,mm,148.59,152.5778,1219.2,Kraft phenolic,0,0,0,,,,,,,\r
+Giant Leap,C-7.512-L,7.5 CT,mm,186.182,190.8048,1219.2,Kraft phenolic,0,0,0,,,,,,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/BHDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/BHDATA.CSV
new file mode 100644 (file)
index 0000000..c34ac32
--- /dev/null
@@ -0,0 +1,18 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine\r
+Public Missiles,PML BP-01,Fits PT-1.145,in.,0,1.145,0.1875,Birch\r
+Public Missiles,PML BP-02,Fits PT-1.525,in.,0,1.525,0.1875,Birch\r
+Public Missiles,PML BP-03,Fits PT-2.152,in.,0,2.152,0.1875,Birch\r
+Public Missiles,PML BP-04,Fits PT-2.560,in.,0,2.56,0.1875,Birch\r
+Public Missiles,PML BP-05,Fits PT-3.002,in.,0,3.002,0.1875,Birch\r
+Public Missiles,PML BP-06,Fits PT-3.900,in.,0,3.9,0.1875,Birch\r
+Public Missiles,PML BP-15,Fits PT-6.007,in.,0,6.007,0.5,Birch\r
+Public Missiles,PML BP-20,Fits PT-7.512,in.,0,7.512,0.5,Birch\r
+Public Missiles,PML BP-90,Fits PT-11.41,in.,0,11.41,0.5,Birch\r
+Public Missiles,PML CBP-02,Fits CT-1.52,in.,0,1.45,0.1875,Birch\r
+Public Missiles,PML CBP-03,Fits CT-2.15,in.,0,2.088,0.1875,Birch\r
+Public Missiles,PML CBP-04,Fits CT-2.56,in.,0,2.498,0.1875,Birch\r
+Public Missiles,PML CBP-05,Fits CT-3.00,in.,0,2.938,0.1875,Birch\r
+Public Missiles,PML CBP-06,Fits CT-3.90,in.,0,3.83,0.1875,Birch\r
+Public Missiles,PML CBP-15,Fits CT-6.00,in.,0,5.926,0.5,Birch\r
+Public Missiles,PML CBP-20,Fits CT-7.51,in.,0,7.43,0.5,Birch\r
+Public Missiles,PML CBP-90,Fits CT-11.4,in.,0,11.28,0.5,Birch\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/BTDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/BTDATA.CSV
new file mode 100644 (file)
index 0000000..195ce78
--- /dev/null
@@ -0,0 +1,23 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine\r
+Public Missiles Ltd.,PML PT-1.145,Airframe tube,in.,1.145,1.269,36,Kraft phenolic,29\r
+Public Missiles Ltd.,PML PT-1.525,Airframe tube,in.,1.525,1.649,36,Kraft phenolic,38\r
+Public Missiles Ltd.,PML PT-2.152,Airframe tube,in.,2.152,2.276,36,Kraft phenolic,54\r
+Public Missiles Ltd.,PML PT-2.560,Airframe tube,in.,2.56,2.684,36,Kraft phenolic,\r
+Public Missiles Ltd.,PML PT-3.002,Airframe tube,in.,3.002,3.126,36,Kraft phenolic,75\r
+Public Missiles Ltd.,PML PT-3.900,Airframe tube,in.,3.9,4.024,36,Kraft phenolic,98\r
+Public Missiles Ltd.,PML PT-6.007,Airframe tube,in.,6.007,6.155,48,Kraft phenolic,\r
+Public Missiles Ltd.,PML PT-7.512,Airframe tube,in.,7.512,7.672,48,Kraft phenolic,\r
+Public Missiles Ltd.,PML PT-11.41,Airframe tube,in.,11.41,11.66,48,Kraft phenolic,\r
+Public Missiles Ltd.,PML PIS 1.5,Piston,in,1.401,1.525,1.5,Kraft phenolic,0\r
+Public Missiles Ltd.,PML PIS 2.1,Piston,in,2.028,2.152,2,Kraft phenolic,54\r
+Public Missiles Ltd.,PML PIS 2.5,Piston,in,2.436,2.56,2,Kraft phenolic,0\r
+Public Missiles Ltd.,PML PIS 3.0,Piston,in,2.878,3.002,2,Kraft phenolic,0\r
+Public Missiles Ltd.,PML PIS 3.9,Piston,in,3.776,3.9,2.5,Kraft phenolic,0\r
+Public Missiles Ltd.,PML PIS 6.0,Piston,in,5.859,6.007,4,Kraft phenolic,0\r
+Public Missiles Ltd.,PML PIS 7.5,Piston,in,7.352,7.512,4,Kraft phenolic,0\r
+Public Missiles Ltd.,PML KS-2.152,KS2000 54mm,in.,2.152,2.276,14.5,Kraft phenolic,29\r
+Public Missiles Ltd.,PML KS-1.525,KS2000 38mm,in.,1.525,1.649,14.5,Kraft phenolic,38\r
+Public Missiles Ltd.,PML KS-1.145,KS2000 29mm,in.,1.145,1.269,14.5,Kraft phenolic,54\r
+Public Missiles Ltd.,PML 29/38ADPTR,29>38mm Adapter,in,1.145,1.52,8,Kraft phenolic,29\r
+Public Missiles,PML 54/38 ADPTR,54>38mm Adapter,in.,1.525,2.15,9,Kraft phenolic,38\r
+Public Missiles,PML 54/29 ADPTR,54>29mm Adapter,in.,1.145,2.15,9,Kraft phenolic,29\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/CFDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/CFDATA.CSV
new file mode 100644 (file)
index 0000000..3e2b9b3
--- /dev/null
@@ -0,0 +1,32 @@
+Mfg.,Part no,Desc,Units,Root chord,Tip chord,Span,Sweep,Thickness,Shape,Tip shape,Material,Npoints,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128\r
+PML,CirrusDart,Cirrus Fins,in,3.5,1.5,2,2.531,0.0625,,square,G10 fiberglass,5,3.49555969382414|             0.,3.747386993524089|             0.881228265061307,3.752451030001824|             1.994997991119145,2.356802576737988|             2.002666389214002,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML Matrix,Upper payload fins,in,4.75,3.15,0.62,0.8,0.0938,,square,G10 fiberglass,4,4.75|             0.,4.|             0.62,0.75|             0.62,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML Matrix,Lower main fin set,in,4,1.824,5.75,3.306,0.0938,,square,G10 fiberglass,5,4.|             0.,5.38|             4.,5.38|             5.75,0.|             2.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML Mini BBX,Lower fins,in,5.75,3.338,2.75,4.932,0.063,,square,G10 fiberglass,5,5.75|             0.,6.5|             0.375,7.875|             2.749623570271068,4.75|             2.741438242031717,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML Ptero Jr,Fins,in,17.759,12.447,4.25,13.054,0.063,,square,G10 fiberglass,5,17.759|             0.,16.263999999999999|             4.25,12.739000000000001|             4.25,11.893000000000001|             1.514,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML Pterodactyl,Fins,in,34,26.079,8.5,24.793,0.094,,square,G10 fiberglass,5,34.|             0.,31.25|             8.5,24.75|             8.5,23.|             2.75,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML A-02 & Io & Callisto,Fins,in,4,1.772,4,1.114,0.0625,,square,G10 fiberglass,4,4.|             0.,3.|             4.,1.|             4.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML A-03 & Explorer,Fins,in,5.5,0.248,4,4.563,0.0625,,square,G10 fiberglass,4,5.5|             0.,5.5|             3.,4.|             4.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML A-04 & Phobos,Fins,in,6.5,3.152,4,4.924,0.0625,,square,G10 fiberglass,3,6.5|             0.,6.5|             4.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML A-07,Fins,in,6.5,2.348,4,4.855,0.0625,,square,G10 fiberglass,4,6.5|             0.,6.5|             2.,5.75|             4.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML A-09,Fins,in,6.5,0.681,3,4.785,0.0625,,square,G10 fiberglass,4,6.5|             0.,6.|             3.,4.25|             3.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML B-02 & Ariel,Fins,in,5,2.187,5,1.406,0.0625,,square,G10 fiberglass,4,5.|             0.,3.75|             5.,1.25|             5.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML B-03 & Qleap Upper,Fins,in,7,8.274,5,2.053,0.063,,square,G10 fiberglass,4,7.|             0.,7.|             3.75,5.5|             5.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML B-04,Fins,in,8,4,5,6,0.0625,,square,G10 fiberglass,3,8.|             0.,8.|             5.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML B-07,Fins,in,8,2.685,5,5.871,0.0625,,square,G10 fiberglass,4,8.|             0.,8.|             2.5,6.75|             5.,0.|             0.,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,\r
+PML,PML B-09,Fins,in,8,0.131,4,6.56,0.063,,square,G10 fiberglass,4,8.|             0.,7.5|             4.,5.75|             4.,0.|             0.\r
+PML,PML C-02,Fins,in,6,2.625,6,1.687,0.0938,,square,G10 fiberglass,4,6.|             0.,4.5|             6.,1.5|             6.,0.|             0.\r
+PML,PML C-03,Fins,in,9,0.035,6,7.318,0.0938,,square,G10 fiberglass,4,9.|             0.,9.|             4.25,6.|             6.,0.|             0.\r
+PML,PML C-05,Fins,in,6,2.254,5,2.748,0.0938,,square,G10 fiberglass,4,6.|             0.,5.25|             5.,2.5|             5.,0.|             0.\r
+PML,PML C-07,Fins,in,10,3.262,6,7.425,0.0938,,square,G10 fiberglass,4,10.|             0.,10.|             3.,8.5|             6.,0.|             0.\r
+PML,PML C-09,Fins,in,10,0.277,5,8.237,0.0938,,square,G10 fiberglass,4,10.|             0.,9.5|             5.,7.25|             5.,0.|             0.\r
+PML,PML D-02,Fins,in,8,2.877,8,2.312,0.094,,square,G10 fiberglass,4,8.|             0.,5.5|             8.,2.|             8.,0.|             0.\r
+PML,PML D-03,Fins,in,12,13.745,8,3.662,0.0938,,square,G10 fiberglass,4,12.|             0.,12.|             6.25,9.25|             8.,0.|             0.\r
+PML,PML D-05,Fins,in,8,2.877,6.5,3.812,0.0938,,square,G10 fiberglass,4,8.|             0.,7.|             6.5,3.5|             6.5,0.|             0.\r
+PML,PML D-07,Fins,in,13.5,4.429,8,10.028,0.0938,,square,G10 fiberglass,4,13.5|             0.,13.5|             4.,11.5|             8.,0.|             0.\r
+PML,PML D-09,Fins,in,13.5,0.306,6.5,11.347,0.0938,,square,G10 fiberglass,4,13.5|             0.,13.|             6.5,10.|             6.5,0.|             0.\r
+PML,PML Aurora,Fins,in,9.25,0.913,5.5,8.16,0.0625,,square,G10 fiberglass,4,9.250000122100001|             0.,9.5000001254|             4.7500000627,7.750000102300001|             5.500000072599999,0.|             0.\r
+PML,PML Hydra,Simulated 4 for 2 fins,in,3.875,0.297,2.625,2.227,0.0938,,square,G10 fiberglass,4,3.875|             0.,2.875|             2.625,1.875|             2.625,0.|             0.\r
+PML,PML Hydra,4 swept-back fins,in,4.625,1.631,6.25,7.185,0.0938,,square,G10 fiberglass,4,4.625|             0.,9.|             6.25,7.|             6.25,0.|             0.\r
+PML,PML Intruder,Simulated 4 for 2 Fins,in,3.125,1.623,2.125,0.689,0.063,,square,G10 fiberglass,4,3.125|             0.,2.375|             2.125,0.625|             2.125,0.|             0.\r
+PML,PML Ptero Jr,NO STRAKE Fins,in,6.25,3.238,4.25,1.384,0.063,,square,G10 fiberglass,4,6.25|             0.,4.75|             4.25,1.256111741726874|             4.25000002805,0.|             0.\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/CRDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/CRDATA.CSV
new file mode 100644 (file)
index 0000000..57b6715
--- /dev/null
@@ -0,0 +1,22 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine\r
+Public Missiles,PML CR-00,1.5>29mm,in.,1.269,1.525,0.1875,Aircraft plywood (Birch),29mm,,,,,,,,,,\r
+Public Missiles,PML CR-01,2.1>29mm,in.,1.269,2.152,0.1875,Aircraft plywood (Birch),29mm,,,,,,,,,,\r
+Public Missiles,PML CR-02,2.1>38mm,in.,1.649,2.152,0.1875,Aircraft plywood (Birch),38mm,,,,,,,,,,\r
+Public Missiles,PML CR-06,2.5>29mm,in.,1.269,2.56,0.1875,Aircraft plywood (Birch),29mm,,,,,,,,,,\r
+Public Missiles,PML CR-07,2.5>38mm,in.,1.649,2.56,0.1875,Aircraft plywood (Birch),38mm,,,,,,,,,,\r
+Public Missiles,PML CR-08,2.5>54mm,in.,2.276,2.56,0.1875,Aircraft plywood (Birch),KS2000,,,,,,,,,,\r
+Public Missiles,PML CR-09,3.0>29mm,in.,1.269,3.002,0.1875,Aircraft plywood (Birch),29mm,,,,,,,,,,\r
+Public Missiles,PML CR-10,3.0>38mm,in.,1.649,3.002,0.1875,Aircraft plywood (Birch),38mm,,,,,,,,,,\r
+Public Missiles,PML CR-11,3.0>54mm,in.,2.276,3.002,0.1875,Aircraft plywood (Birch),KS2000,,,,,,,,,,\r
+Public Missiles,PML CR-12,3.9>29mm,in.,1.269,3.9,0.1875,Aircraft plywood (Birch),29mm,,,,,,,,,,\r
+Public Missiles,PML CR-13,3.9>38mm,in.,1.649,3.9,0.1875,Aircraft plywood (Birch),38mm,,,,,,,,,,\r
+Public Missiles,PML CR-14,3.9>54mm,in.,2.276,3.9,0.1875,Aircraft plywood (Birch),KS2000,,,,,,,,,,\r
+Public Missiles,PML CR-16,6.0>38mm,in.,1.649,6.007,0.5,Aircraft plywood (Birch),38mm,,,,,,,,,,\r
+Public Missiles,PML CR-17,6.0>54mm,in.,2.276,6.007,0.5,Aircraft plywood (Birch),KS2000,,,,,,,,,,\r
+Public Missiles,PML CR-18,6.0>98mm,in.,4.024,6.007,0.5,Aircraft plywood (Birch),GiantKS,,,,,,,,,,\r
+Public Missiles,PML CR-20,7.5>54mm,in.,2.276,7.512,0.5,Aircraft plywood (Birch),KS2000\r
+Public Missiles,PML CR-21,7.5>98mm,in.,4.024,7.512,0.5,Aircraft plywood (Birch),GiantKS\r
+Public Missiles,PML CR-90,11.4>54mm,in.,2.276,11.41,0.5,Aircraft plywood (Birch),KS2000\r
+Public Missiles,PML CR-91,11.4>98mm,in.,4.024,11.41,0.5,Aircraft plywood (Birch),GiantKS\r
+Public Missiles,Eclipse B,Custom 38mm MMT rings,in,1.649,3.88,0.1875,Aircraft plywood (Birch),\r
+Public Missiles,PML CR-92,11.4>76mm,in,3.126,11.390000000000001,0.5,Aircraft plywood (Birch)\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/EBDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/EBDATA.CSV
new file mode 100644 (file)
index 0000000..9db65b8
--- /dev/null
@@ -0,0 +1,3 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine\r
+Apogee,EB-50,Eng. block BT-50,in.,0.74,0.95,0.25,Paper\r
+Estes,30162-2,Eng. block BT-20,mm,16.530000000000001,18.033999999999999,5.,Paper\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/FSDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/FSDATA.CSV
new file mode 100644 (file)
index 0000000..272583d
--- /dev/null
@@ -0,0 +1,61 @@
+Mfg.,Part no,Desc,Units,Root chord,Tip chord,Span,Sweep Dist.,Thickness,Shape,Tip shape,Material,Sweep Mode,Sweep Mode,Sweep Mode,Sweep Mode,Sweep Mode,Sweep Mode,Sweep Mode\r
+PML,1-2Pat1,1/2 Patriot fins,in,12.5,4.5,6.625,7.9997,0.0938,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,1-4Pat1,1/4 Patriot fins,in,6.75,2.125,3.5,4.5008,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,AM21,AMRAAM-2 Upper fins,in,3,0.001,1.5,3.0007,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,AM22,AMRAAM-2 Lower fins,in,3.5,1.125,2.75,2.2501,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,AM31,AMRAAM-3 Upper fins,in,3.375,0.001,2,3.3751,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,AM32,AMRAAM-3 Lower fins,in,5.25,1.5,3.875,3.7499,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,AM41,AMRAAM-4 Upper fins,in,6,0.001,3,6.0013,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,AM42,AMRAAM-4 Lower fins,in,7,2,5.5,4.7508,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,Arie1,Ariel fins,in,5,2.25,5,1.5001,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,Auro1,Aurora fins,in,9.5,0.001,5.5,9.4995,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,BBV1,Black Brant VB fins,in,6.25,3.75,3.125,6.2514,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,BBX1,Black Brant X Upper fins,in,3,0.001,1.75,2.9996,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,BBX2,Black Brant X Lower fins,in,10,6,4.75,7.9493,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,Buld1,Bulldog Upper fins,in,3.125,0.001,2,3.1249,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,Buld2,Bulldog lower fins,in,9,2.5,9,6.5006,0.0625,trapezoid,square,G10 fiberglass,1,,,,,,\r
+PML,Bulp1,Bullpup Upper fins,in,2.125,0.001,1,2.1251,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Bulp2,Bullpup Lower fins,in,4.5,1.5,4.5,3,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Call1,Callisto fins,in,4,1.75,4,1.0003,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Eclp1,Eclipse fins,in,11,2.625,4,8.0018,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,End1,Endeavour Upper fins,in,7.75,2.125,3.5,7.4989,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,End2,Endeavour Lower fins,in,5,3,3.5,2.0004,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,IO,IO fins,in,4,1.75,4,1.0003,0.1875,trapezoid,square,G10 fiberglass,1\r
+PML,LER,LunarExp Rudders,in,9.375,6,3.75,4.4993,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,LEW,LunarExp Wings,in,12.5,7,7.75,8.0002,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,LLER,LilLunarExp Rudders,in,6.125,4,2.5,2.8756,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,LLEW,LilLunarExp Wings,in,7.75,4.75,4.75,4.4997,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,LLnExp Averaged,Fins,in,6.938,4.275,3.625,4.1248,0.063,trapezoid,square,G10 fiberglass,1\r
+PML,LunExp Averaged,Fins,in,10.938,6.5,5.75,7.999,0.063,trapezoid,square,G10 phenolic,0\r
+PML,Matrix,Upper Main Fins,in,14,0,2,14.0002,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Nimb1,Nimbus fins,in,9,1.5,3.625,5.2508,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Phan1,Phantom Longer fins,in,7.75,0.001,3,6.2503,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Phan2,Phantom Shorter fins,in,4.25,0.001,2.25,2.7499,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Phob1,Phobos fins,in,6.5,0.001,3.75,6.5004,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Quas1,Quasar fins,in,8.25,0.001,3.375,6.2498,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,SmEnd1,Small Endeavour Upper fins,in,4.5,1,2.5,4.75,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,SmEnd2,Small Endeavour Lower fins,in,3,1.75,2.5,1.2503,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Stra1,Stratus fins,in,6,0.001,2.5,4.7497,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Sudd1,Sudden Rush fins,in,8.5,0.001,4.25,7.2498,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,T&L1,Thund/Light upper fins,in,11.5,0.001,4,8.6252,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Temp1,Tempest fins,in,11.25,0.001,4.25,9.7511,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,Tethys or T&L lwr or C-05,Fins,in,6,1.75,5,2.8751,0.0938,trapezoid,square,G10 fiberglass,1\r
+PML,Tomy1,D-Region Tomahawk fins,in,6.5,3,4.875,4.7507,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,UEnd1,Ultimate Endeavour Upper fins,in,11.5,3,5.5,11.0024,0.0938,trapezoid,square,G10 fiberglass,1\r
+PML,UEnd2,Ultimate Endeavour Lower fins,in,7.25,4.75,5.5,2.4995,0.0938,trapezoid,square,G10 fiberglass,1\r
+PML,PML A-01,Fins,in,4,2,4,2.0004,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,PML A-05 & Miranda,Fins,in,4,1.5,3,1.7503,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,PML A-06,Fins,in,5.5,1.5,4,4,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,PML A-08,Fins,in,4,1.875,4,3.3564,0.0625,trapezoid,square,G10 fiberglass,0\r
+PML,PML B-01,Fins,in,5,2.5,5,2.5005,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,PML B-05,Fins,in,5,1.625,4,2.2502,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,PML Qleap lwr & B-06,Fins,in,7,2,5,5,0.0625,trapezoid,square,G10 fiberglass,1\r
+PML,PML B-08,Fins,in,5,2.5,5,4.1955,0.0625,trapezoid,square,G10 fiberglass,0\r
+PML,PML C-01,Fins,in,6,3,6,3.0007,0.0938,trapezoid,square,G10 fiberglass,1\r
+PML,PML C-04,Fins,in,10,0.001,6,10.186,0.0938,trapezoid,square,G10 fiberglass,0\r
+PML,PML C-06,Fins,in,9,3.125,6,6,0.0938,trapezoid,square,G10 fiberglass,0\r
+PML,PML C-08,Fins,in,6,2.875,6,5.0346,0.0938,trapezoid,square,G10 fiberglass,0\r
+PML,PML D-01,Fins,in,8,3.875,8,4.0009,0.0938,trapezoid,square,G10 fiberglass,0\r
+PML,PML D-04,Fins,in,13.5,0.001,8,13.5813,0.0938,trapezoid,square,G10 fiberglass,0\r
+PML,PML D-06,Fins,in,12,4,8,8,0.094,trapezoid,square,G10 fiberglass,0\r
+PML,PML D-08,Fins,in,8,3.5,8,6.8327,0.094,trapezoid,square,G10 fiberglass,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/GRAPHS.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/GRAPHS.CSV
new file mode 100644 (file)
index 0000000..ea69da5
--- /dev/null
@@ -0,0 +1,6 @@
+name,x,rgbx, y1,rgb1,style1, y2,rgb2,style2, y3,rgb3,style3, y4,rgb4,style4, y5,rgb5,style5, StartCode,StartValue,EndCode,EndValue\r
+Flight Angle & AOA,0,255|0|0,16,255|128|64,0,17,255|0|128,0,34,0|128|0,0,-1,0|0|0,0,-1,0|0|0,0,0,0.25,6,0.\r
+Cross wind forces vs. time,0,255|0|0,36,255|0|128,0,37,255|128|64,0,-1,0|0|0,0,-1,0|0|0,0,-1,0|0|0,0,2,0.25,3,0.\r
+Cd Vs. Mach number,35,255|0|0,18,255|128|0,0,-1,0|0|0,0,-1,0|0|0,0,-1,0|0|0,0,-1,0|0|0,0,0,0.25,3,0.\r
+Acceleration / Velocity / Altitude Vs. Time,0,255|0|0,4,255|128|0,0,7,0|255|0,0,10,0|0|160,7,-1,0|0|0,0,-1,0|0|0,0,0,0.25,0,0.\r
+Cd Vs. Velocity,7,255|0|0,18,255|128|0,0,-1,0|0|0,0,-1,0|0|0,0,-1,0|0|0,0,-1,0|0|0,0,0,0.25,3,0.\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/LLDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/LLDATA.CSV
new file mode 100644 (file)
index 0000000..49d1acf
--- /dev/null
@@ -0,0 +1,5 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material\r
+Public Missiles,PML LL-25,"1/4"" brass launch lug",in.,0.225,0.25,12,Brass,0.7,0.058,,,,,,,,,\r
+Public Missiles,PML LL-38,"3/8"" brass launch lug",in.,0.3375,0.375,12,Brass,1.1,0.092,,,,,,,,,\r
+Public Missiles,PML LL-50,"1/2"" brass launch lug",in.,0.45,0.5,12,Brass,1.3,0.108,,,,,,,,,\r
+Public Missiles,PML LL-75,"3/4"" copper launch lug",in.,0.675,0.75,12,Copper (rolled),4.7,0.392,,,,,,,,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/MATERIAL.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/MATERIAL.CSV
new file mode 100644 (file)
index 0000000..26894c9
--- /dev/null
@@ -0,0 +1,62 @@
+Material Name,Units,Density,Low,High,Class,Rocketry Use,Body Tubes,Fin Sets,Launch Lugs,Cords,Nose,Chute,Stream,Trans,Ring,Bulkhead,Engine Block,Sleeve,Tube Coupler,spare,spare,spare,spare,spare,spare,spare,spare,spare,spare\r
+Acrylic (Cast),lb/ft3,74,74,74,Plastic,y,n,y,n,n,y,n,n,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+Aircraft plywood (Birch),lb/ft3,45.259999999999998,43.560000000000002,46.960000000000001,unknown,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Ash,lb/ft3,42.5,40,45,unknown,0,0,1,0,0,1,0,0,1,1,1,0,0,0,n,n,n,n,n,n,n,n,n,n\r
+Balsa,lb/ft3,8,8,8,unknown,1,1,1,1,0,1,0,0,1,1,1,1,1,1,n,n,n,n,n,n,n,n,n,n\r
+Basswood,lb/ft3,26.5,25,28,unknown,1,1,1,1,0,1,0,0,1,1,1,1,1,1,n,n,n,n,n,n,n,n,n,n\r
+Beech,lb/ft3,45,45,45,Wood,n,y,y,y,n,y,y,y,y,y,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Birch,lb/ft3,42.5,40,45,Wood,n,y,y,y,n,y,y,y,y,y,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Brass,lb/ft3,534,534,534,Metal,y,y,y,y,n,y,n,n,y,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+Cardboard,lb/ft3,43,43,43,unknown,1,1,1,1,0,1,0,0,1,1,1,1,1,1,n,n,n,n,n,n,n,n,n,n\r
+Chalk (Fine),lb/ft3,70,70,70,Mineral,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Copper (cast),lb/ft3,542,542,542,unknown,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Copper (rolled),lb/ft3,556.,556.,556.,unknown,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Cork (Solid),lb/ft3,15,15,15,Wood,y,n,n,n,n,y,n,n,n,n,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+Cottonwood,lb/ft3,25,25,25,Wood,n,y,y,y,n,y,y,y,y,y,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Epoxy,lb/ft3,78.3,78.3,78.3,Plastic,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Fiberglass,kg/m3,128.147704,n,n,n,1,1,1,0,0,1,0,0,1,1,1,1,1,1,n,n,n,n,n,n,n,None,0,0\r
+Fir (Douglas),lb/ft3,35,35,35,Wood,y,n,y,n,n,y,n,n,y,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+Fir (White),lb/ft3,25,25,25,Wood,y,n,y,n,n,y,n,n,y,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+G10 fiberglass,lb/ft3,118.94,118.27,118.61,Plastic,y,n,y,n,n,n,n,n,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+G10 phenolic,lb/ft3,118.94,118.27,118.61,Plastic,y,n,y,n,n,n,n,n,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+Gold (24 kt.),lb/ft3,1204,1204,1204,Metal,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Iron (cast,lb/ft3,450,450,450,Metal,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Iron (wrought),lb/ft3,485,485,485,Metal,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Kraft phenolic,lb/ft3,59.85,59.85,59.85,Plastic,y,y,n,n,n,n,n,n,n,n,n,n,y,y,n,n,n,n,n,n,n,n,n,n\r
+Lead (cast),lb/ft3,708,708,708,Metal,n,n,n,n,n,n,n,n,n,n,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Lead (rolled),lb/ft3,711,711,711,Metal,n,n,n,n,n,n,n,n,n,n,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Leather,lb/ft3,59,59,59,Animal,n,n,n,n,n,n,n,n,n,n,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Lexan,g/cm3,1.218,1.218,1.218,Plastic,y,n,y,n,n,n,n,n,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+Maple (Hard),lb/ft3,39.5,35.,44.,unknown,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Mylar,g/cm3,1.309,1.309,1.309,Plastic,y,n,n,n,n,n,y,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Nylon,g/cm3,1.14,1.14,1.14,Plastic,y,n,y,n,n,n,n,n,n,y,y,y,n,y,n,n,n,n,n,n,n,n,n,n\r
+Oak (Brown),lb/ft3,45,45,45,Wood,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Oak (Red),lb/ft3,45,45,45,Wood,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Oak (White),lb/ft3,47,47,47,Wood,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Paper,lb/ft3,70.,70.,70.,unknown,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Pine (White Northern),lb/ft3,25,25,25,Wood,y,n,y,n,n,y,n,n,y,y,y,y,n,y,n,n,n,n,n,n,n,n,n,n\r
+Pine (White Western),lb/ft3,27,27,27,Wood,y,n,y,n,n,y,n,n,y,y,y,y,n,y,n,n,n,n,n,n,n,n,n,n\r
+Polycarbonate,lb/ft3,74.9,74.9,74.9,Plastic,y,y,y,y,n,y,n,n,y,y,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Polyethylene LDPE,lb/ft3,57.7,57.7,57.7,Plastic,y,n,n,n,n,n,y,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Polystyrene PS,lb/ft3,65.5,65.5,65.5,Plastic,y,y,y,y,n,y,n,n,y,y,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Poplar (Yellow),lb/ft3,30,30,30,Wood,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+PVC,lb/ft3,81.2,81.2,81.2,Plastic,y,y,y,n,n,y,n,n,y,y,y,y,y,y,n,n,n,n,n,n,n,n,n,n\r
+Rip stop nylon,g/cm2,0.006685,0.006685,0.006685,unknown,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Silver,lb/ft3,653,653,653,Metal,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+Spruce,lb/ft3,28,28,28,Wood,y,n,y,n,n,y,n,n,y,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+Sycamore,lb/ft3,35,35,35,Wood,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+1/8 In. flat rubber,g/cm,0.0231,0.0231,0.0231,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+1/8 In. flat elastic,g/cm,0.0205,0.0205,0.0205,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+1/4 In. flat elastic,g/cm,0.0402,0.0402,0.0402,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+1/16 In. braided nylon,g/cm,0.0102,0.0102,0.0102,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+1/16 In. round elastic,g/cm,0.0183,0.0183,0.0183,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+5/64 In. round elastic,g/cm,0.0242,0.0242,0.0242,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+1/32 In. kevlar,g/cm,0.00659,0.00659,0.00659,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+70 Lb. kevlar,g/cm,0.0033,0.0033,0.0033,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+30 Lb. kevlar,g/cm,0.00178,0.00178,0.00178,Shock,y,n,n,n,y,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n,n\r
+"G10 (PML 0.062"")",oz/in2,0.0714,0.0714,0.0714,Plastic,y,n,y,n,n,n,n,n,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+G10 (PML 0.093),oz/in2,0.1143,0.1143,0.1143,Plastic,y,n,y,n,n,n,n,n,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+G10 (PML 0.125),oz/in2,0.1404,0.1404,0.1404,Plastic,y,n,y,n,n,n,n,n,n,y,y,y,n,n,n,n,n,n,n,n,n,n,n,n\r
+Urethane,lb/ft3,52.880000000000003,52.880000000000003,52.880000000000003,unknown,1,0,0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 inch Flat Elastic,g/cm,0.038,0.038,0.038,unknown,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Rocketwood,lb/ft3,33.030000000000001,33.030000000000001,33.030000000000001,unknown,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/MODATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/MODATA.CSV
new file mode 100644 (file)
index 0000000..87b9903
--- /dev/null
@@ -0,0 +1,122 @@
+Mfg.,Part no,Desc,Units,Name,Type,Length,Material,Mass units,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass\r
+Public Missiles,PML UBLT,Ubolt for FNCs,in,6/7.5/11in. FNC Ubolt,general,0,,oz.,2.7,,,,,,,,,\r
+Public Missiles,LilLunar nose,Bplate w/hdwe,in,Bulkplate with hardware  Little Lunar,general,0,,oz.,0.88,,,,,,,,,\r
+Public Missiles,PML 24in.,chute-T&L booster,in,Mass object,general,0,,oz.,1.6,,,,,,,,,\r
+Public Missiles,PML CPR 2.1 system,CPR2000,in,PML 2.1 CPR2k system,general,0,,oz.,8.2,,,,,,,,,\r
+Public Missiles,PML CPR 2.5 system,CPR2000,in,PML 2.5 CPR2k system,general,0,,oz.,8.4,,,,,,,,,\r
+Public Missiles,PML CPR 3.0 system,CPR2000,in,PML 3.0 CPR2k system,general,0,,oz.,8.6,,,,,,,,,\r
+Public Missiles,PML CPR 3.9 system,CPR2000,in,PML 3.9 CPR2k system,general,0,,oz.,9.3,,,,,,,,,\r
+Public Missiles,STRACPR,Stratus CPR parts,in,Mass object,general,0,,oz.,6.1,,,,,,,,,\r
+Public Missiles,PML PS-1.52,Piston assy,in.,Piston assy,general,,,oz.,1.9,,,,,,,,,\r
+Public Missiles,PML PS-2.15,Piston assy,in.,Piston assy,general,,,oz.,2.9,,,,,,,,,\r
+Public Missiles,PML PS-2.56,Piston assy,in.,Piston assy,general,,,oz.,3,,,,,,,,,\r
+Public Missiles,PML PS-3.00,Piston assy,in.,Piston assy,general,,,oz.,3.3,,,,,,,,,\r
+Public Missiles,PML PS-3.90,Piston assy,in.,Piston assy,general,,,oz.,4.1,,,,,,,,,\r
+Public Missiles,PML PS-6.00,Piston assy,in.,Piston assy,general,,,oz.,8.1,,,,,,,,,\r
+Public Missiles,PML PS-7.51,Piston assy,in.,Piston assy,general,,,oz.,12,,,,,,,,,\r
+Public Missiles,PML KL-01,Small KwikLink,,KwikLink small,general,,Steel,oz.,0.2\r
+Public Missiles,PML KL-02,Large KwikLink,,KwikLink large,general,,Steel,oz.,0.8\r
+Public Missiles,PML EB-01,1/8x24 eyebolt,,Eye Bolt,general,,Steel,oz.,0.2\r
+Public Missiles,PML NT-01,1/8x24 nut,,Nut,general,,Steel,oz.,0.1\r
+Public Missiles,PML,Eyblt/wshr/2nuts,in,PML eyebolt  washer  2 nuts,general,0,Steel,oz.,0.5\r
+Public Missiles,PML WA-01,eyebolt washer,,Washer,general,,Steel,oz.,0.2\r
+Public Missiles,PML DR-10,D ring,,D-ring,general,,Nylon,oz.,0.1\r
+Public Missiles,PML 98/54 KS-KIT,98 to 54mm MMT adapter,in.,98/54 KwikSwitch,,36,Kraft phenolic,oz.,26.7\r
+Public Missiles,PML P5,Altimeter,in.,Altimeter,general,3,Kraft phenolic,oz.,4\r
+Public Missiles,PML EC-LES,Ejection canister,,Ejection canister,,2,Aluminum,oz.,\r
+Public Missiles,PML ECH-01,Ejection canister holder,,Ejection canister holder,,,Urethane,oz.,\r
+Public Missiles,PML AG1-B,Single flashbulb,,Single flashbulb,,,Glass,oz.,0.1\r
+Public Missiles,PML CBA-1.52,Coupler/bulkhead assy.,in.,Coupler/bulkhead assy.,general,3,,oz.,0.75\r
+Public Missiles,PML CBA-2.15,Coupler/bulkhead assy.,in.,Coupler/bulkhead assy.,general,4,,oz.,1.5\r
+Public Missiles,PML CBA-2.56,Coupler/bulkhead assy.,in.,Coupler/bulkhead assy.,general,5,,oz.,2\r
+Public Missiles,PML CBA-3.00,Coupler/bulkhead assy.,in.,Coupler/bulkhead assy.,general,5,,oz.,2.4\r
+Public Missiles,PML CBA-3.90,Coupler/bulkhead assy.,in.,Coupler/bulkhead assy.,general,7,,oz.,4\r
+Public Missiles,PML CBA-6.00,Coupler/bulkhead assy.,in.,Coupler/bulkhead assy.,general,12,,oz.,9.4\r
+Public Missiles,PML CBA-7.51,Coupler/bulkhead assy.,in.,Coupler/bulkhead assy.,general,12,,oz.,20.8\r
+Public Missiles,PML CBA-11.4,Coupler/bulkhead assy.,in.,Coupler/bulkhead assy.,general,16,,oz.,43.7\r
+Public Missiles,PML PSK-01,Payload section kit,in.,Payload section kit,general,9,,oz.,2.4\r
+Public Missiles,PML PSK-02,Payload section kit,in.,Payload section kit,general,12,,oz.,2.9\r
+Public Missiles,PML PSK-03,Payload section kit,in.,Payload section kit,general,18,,oz.,3.9\r
+Public Missiles,PML PSK-05,Payload section kit,in.,Payload section kit,general,9,,oz.,3.6\r
+Public Missiles,PML PSK-06,Payload section kit,in.,Payload section kit,general,12,,oz.,4.3\r
+Public Missiles,PML PSK-07,Payload section kit,in.,Payload section kit,general,18,,oz.,5.8\r
+Public Missiles,PML PSK-10,Payload section kit,in.,Payload section kit,general,9,,oz.,4.6\r
+Public Missiles,PML PSK-11,Payload section kit,in.,Payload section kit,general,12,,oz.,5.4\r
+Public Missiles,PML PSK-12,Payload section kit,in.,Payload section kit,general,18,,oz.,7.1\r
+Public Missiles,PML PSK-20,Payload section kit,in.,Payload section kit,general,9,,oz.,5.3\r
+Public Missiles,PML PSK-21,Payload section kit,in.,Payload section kit,general,12,,oz.,6.3\r
+Public Missiles,PML PSK-22,Payload section kit,in.,Payload section kit,general,18,,oz.,8.4\r
+Public Missiles,PML PSK-30,Payload section kit,in.,Payload section kit,general,9,,oz.,7.8\r
+Public Missiles,PML PSK-31,Payload section kit,in.,Payload section kit,general,12,,oz.,9.1\r
+Public Missiles,PML PSK-32,Payload section kit,in.,Payload section kit,general,18,,oz.,11.7\r
+Public Missiles,PML PSK-40,Payload section kit,in.,Payload section kit,general,12,,oz.,33.3\r
+Public Missiles,PML PSK-41,Payload section kit,in.,Payload section kit,general,16,,oz.,37.4\r
+Public Missiles,PML PSK-42,Payload section kit,in.,Payload section kit,general,24,,oz.,45.8\r
+Public Missiles,PML PSK-60,Payload section kit,in.,Payload section kit,general,12,,oz.,17.4\r
+Public Missiles,PML PSK-61,Payload section kit,in.,Payload section kit,general,16,,oz.,20.1\r
+Public Missiles,PML PSK-62,Payload section kit,in.,Payload section kit,general,24,,oz.,25.4\r
+Public Missiles,PML PSK-90,Payload section kit,in.,Payload section kit,general,12,,oz.,71.7\r
+Public Missiles,PML PSK-91,Payload section kit,in.,Payload section kit,general,16,,oz.,80.9\r
+Public Missiles,PML PSK-92,Payload section kit,in.,Payload section kit,general,24,,oz.,100\r
+Public Missiles,PML SC-.75,"3/4"" shock cord",in.,Elastic shock cord,Black,72,200 lb. elastic,oz.,1.2\r
+Public Missiles,PML SC-1.0,"1"" shock cord",in.,Elastic shock cord,White,72,260 lb. elastic,oz.,1.4\r
+Public Missiles,PML SC-1.5,"1.5"" shock cord",in.,Elastic shock cord,Black,72,400 lb. elastic,oz.,2.3\r
+Public Missiles,PML ST-1.0,"1"" nylon strap",in.,Nylon strap,Red,60,4000 lb. nylon,oz.,2\r
+Public Missiles,PML ST-1.0,"2"" nylon strap",in.,Nylon strap,Black,72,6000 lb. nylon,oz.,4.4\r
+Public Missiles,PML 38/29 ADPTR,Friction fit adapter,in.,Friction fit MMT adapter,,8,Kraft phenolic,oz.,2.3\r
+Public Missiles,PML 54/38 ADPTR,Friction fit adapter,in.,Friction fit MMT adapter,,9,Kraft phenolic,oz.,4.8\r
+Public Missiles,PML 54/29 ADPTR,Friction fit adapter,in.,Friction fit MMT adapter,,9,Kraft phenolic,oz.,4.5\r
+Public Missiles,PML FAM-CPR,CPR2000 fore altimeter mount,in.,CPR2000 component,,,Urethane,oz.,0.5\r
+Public Missiles,PML AAM-CPR,CPR2000 aft altimeter mount,in.,CPR2000 component,,,Urethane,oz.,0.3\r
+Public Missiles,PML LES-CPR,CPR2000 ejection canister mount,in.,CPR2000 component,,,Urethane,oz.,0.2\r
+Public Missiles,PML CPR-TS,CPR2000 threaded sleeve for coupler,in.,CPR2000 component,,,Urethane,oz.,0.2\r
+Public Missiles,PML 2.15-CPR-TAC,CPR2000 threaded airframe coupler,in.,CPR2000 component,,,Urethane,oz.,0.6\r
+Public Missiles,PML 2.56-CPR-TAC,CPR2000 threaded airframe coupler,in.,CPR2000 component,,,Urethane,oz.,0.8\r
+Public Missiles,PML 3.00-CPR-TAC,CPR2000 threaded airframe coupler,in.,CPR2000 component,,,Urethane,oz.,1\r
+Public Missiles,PML 3.90-CPR-TAC,CPR2000 threaded airframe coupler,in.,CPR2000 component,,,Urethane,oz.,1.7\r
+Public Missiles,PML PS-1.52,Fits PT-1.525,in.,Piston assy,,,,oz.,1.9\r
+Public Missiles,PML PS-2.15,Fits PT-2.152,in.,Piston assy,,,,oz.,2.9\r
+Public Missiles,PML PS-2.56,Fits PT-2.560,in.,Piston assy,,,,oz.,3\r
+Public Missiles,PML PS-3.00,Fits PT-3.002,in.,Piston assy,,,,oz.,3.3\r
+Public Missiles,PML PS-3.90,Fits PT-3.900,in.,Piston assy,,,,oz.,4.1\r
+Public Missiles,PML PS-6.00,Fits PT-6.007,in.,Piston assy,,,,oz.,8.1\r
+Public Missiles,PML PS-7.51,Fits PT-7.512,in.,Piston assy,,,,oz.,12\r
+Public Missiles,PML KL-01,small,,KwikLink,,,Steel,oz.,0.2\r
+Public Missiles,PML KL-02,large,,KwikLink,,,Steel,oz.,0.8\r
+Public Missiles,PML EB-01,1/8x24,,Eye Bolt,,,Steel,oz.,0.2\r
+Public Missiles,PML NT-01,1/8x24,,Nut,,,Steel,oz.,0.1\r
+Public Missiles,PML WA-01,For EB-01,,Washer,,,Steel,oz.,0.2\r
+Public Missiles,PML DR-10,1 inch,,D-ring,,,Nylon,oz.,0.1\r
+Public Missiles,PML ALTS-25,Altimeter,,Altimeter,,,,oz.,\r
+Public Missiles,PML CBA-1.52,Fits PT-1.525,in.,Coupler/bulkhead assy.,,3,,oz.,0.75\r
+Public Missiles,PML CBA-2.15,Fits PT-2.152,in.,Coupler/bulkhead assy.,,4,,oz.,1.5\r
+Public Missiles,PML CBA-2.56,Fits PT-2.560,in.,Coupler/bulkhead assy.,,5,,oz.,2\r
+Public Missiles,PML CBA-3.00,Fits PT-3.002,in.,Coupler/bulkhead assy.,,5,,oz.,2.4\r
+Public Missiles,PML CBA-3.90,Fits PT-3.900,in.,Coupler/bulkhead assy.,,7,,oz.,4\r
+Public Missiles,PML CBA-6.00,Fits PT-6.007,in.,Coupler/bulkhead assy.,,12,,oz.,9.4\r
+Public Missiles,PML CBA-7.51,Fits PT-7.512,in.,Coupler/bulkhead assy.,,12,,oz.,20.8\r
+Public Missiles,PML CBA-11.4,Fits PT-11.41,in.,Coupler/bulkhead assy.,,16,,oz.,43.7\r
+Public Missiles,PML PSK-01,Fits PT-1.525,in.,Payload section kit,,9,,oz.,2.4\r
+Public Missiles,PML PSK-02,Fits PT-1.525,in.,Payload section kit,,12,,oz.,2.9\r
+Public Missiles,PML PSK-03,Fits PT-1.525,in.,Payload section kit,,18,,oz.,3.9\r
+Public Missiles,PML PSK-05,Fits PT-2.152,in.,Payload section kit,,9,,oz.,3.6\r
+Public Missiles,PML PSK-06,Fits PT-2.152,in.,Payload section kit,,12,,oz.,4.3\r
+Public Missiles,PML PSK-07,Fits PT-2.152,in.,Payload section kit,,18,,oz.,5.8\r
+Public Missiles,PML PSK-10,Fits PT-2.560,in.,Payload section kit,,9,,oz.,4.6\r
+Public Missiles,PML PSK-11,Fits PT-2.560,in.,Payload section kit,,12,,oz.,5.4\r
+Public Missiles,PML PSK-12,Fits PT-2.560,in.,Payload section kit,,18,,oz.,7.1\r
+Public Missiles,PML PSK-20,Fits PT-3.002,in.,Payload section kit,,9,,oz.,5.3\r
+Public Missiles,PML PSK-21,Fits PT-3.002,in.,Payload section kit,,12,,oz.,6.3\r
+Public Missiles,PML PSK-22,Fits PT-3.002,in.,Payload section kit,,18,,oz.,8.4\r
+Public Missiles,PML PSK-30,Fits PT-3.900,in.,Payload section kit,,9,,oz.,7.8\r
+Public Missiles,PML PSK-31,Fits PT-3.900,in.,Payload section kit,,12,,oz.,9.1\r
+Public Missiles,PML PSK-32,Fits PT-3.900,in.,Payload section kit,,18,,oz.,11.7\r
+Public Missiles,PML PSK-40,Fits PT-7.512,in.,Payload section kit,,12,,oz.,33.3\r
+Public Missiles,PML PSK-41,Fits PT-7.512,in.,Payload section kit,,16,,oz.,37.4\r
+Public Missiles,PML PSK-42,Fits PT-7.512,in.,Payload section kit,,24,,oz.,45.8\r
+Public Missiles,PML PSK-60,Fits PT-6.007,in.,Payload section kit,,12,,oz.,17.4\r
+Public Missiles,PML PSK-61,Fits PT-6.007,in.,Payload section kit,,16,,oz.,20.1\r
+Public Missiles,PML PSK-62,Fits PT-6.007,in.,Payload section kit,,24,,oz.,25.4\r
+Public Missiles,PML PSK-90,Fits PT-11.41,in.,Payload section kit,,12,,oz.,71.7\r
+Public Missiles,PML PSK-91,Fits PT-11.41,in.,Payload section kit,,16,,oz.,80.9\r
+Public Missiles,PML PSK-92,Fits PT-11.41,in.,Payload section kit,,24,,oz.,100\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/NCDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/NCDATA.CSV
new file mode 100644 (file)
index 0000000..10815ea
--- /dev/null
@@ -0,0 +1,16 @@
+Mfg.,Part No.,Desc.,Units,Length,Outer Dia,L/D Ratio,Insert Length,Insert OD,Thickness,Shape,Config,Material,CG Loc,Mass Units,Mass\r
+Public Missiles,PML UNC-1.145,Urethane nose cone,in.,6,1.27,4.7,1.5,1.145,0,cone,solid,Urethane,6.5,oz.,2\r
+Public Missiles,PML UNC-1.525,Urethane nose cone,in.,8,1.6,5,1.5,1.475,0,cone,solid,Urethane,6.5,oz.,4\r
+Public Missiles,PML UNC-OG-1.5,Stratus nose cone,in,4.375,1.649,0,0.875,1.505,0,ogive,solid,Urethane,0,oz.,0\r
+Public Missiles,PML PNC-2.15,Plastic nose cone,in.,9.5,2.3,4.2,1.75,2.175,0.125,ogive,hollow,Polystyrene PS,7.5,oz.,3.5\r
+Public Missiles,PML PNC-2.56,Plastic nose cone,in.,11.25,2.7,4.2,2,2.575,0.125,ogive,hollow,Polystyrene PS,9,oz.,5.4\r
+Public Missiles,PML PNC-3.00,Plastic nose cone,in.,13.25,3.1,4.2,2.5,2.975,0.125,ogive,hollow,Polystyrene PS,9,oz.,5.6\r
+Public Missiles,PML PNC-3.90,Plastic nose cone,in.,16.75,4,4.2,3,3.875,0.125,ogive,hollow,Polystyrene PS,9,oz.,10\r
+Public Missiles,PML FNC-6.00,Fiberglass nose cone,in.,24,6.1,4.2,5.5,5.975,0.125,ogive,hollow,Fiberglass,14.5,oz.,28\r
+Public Missiles,PML FNC-7.51,Fiberglass nose cone,in.,29,7.7,4.2,6,7.575,0.125,ogive,hollow,Fiberglass,18,oz.,44\r
+Public Missiles,PML FNC-11.41,Fiberglass nose cone,in.,42,11.7,4.2,6,11.575,0.125,ogive,hollow,Fiberglass,24,oz.,80\r
+Public Missiles,PML FNC-11.4HRPN,Fiberglass nose cone,in,21.94,11.66,0,6,11.39,0.0875,cone,hollow,Fiberglass,0,oz.,0\r
+Public Missiles,PML IC-2.1-1.1,Intellicone,in.,9.5,2.3,4.2,3,2.175,0.125,ogive,hollow,Polystyrene PS,,oz.,4.7\r
+Public Missiles,PML IC-2.6-1.5,Intellicone,in.,11.25,2.7,4.2,2,2.575,0.125,ogive,hollow,Polystyrene PS,,oz.,7.2\r
+Public Missiles,PML IC-3.0-2.1,Intellicone,in.,13.25,3.1,4.2,2.5,2.975,0.125,ogive,hollow,Polystyrene PS,,oz.,8.7\r
+Public Missiles,PML IC-3.9-2.1,Intellicone,in.,16.75,4,4.2,3,3.875,0.125,ogive,hollow,Polystyrene PS,,oz.,14.4\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/PCDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/PCDATA.CSV
new file mode 100644 (file)
index 0000000..fc34d73
--- /dev/null
@@ -0,0 +1,16 @@
+Mfg.,Part No.,Desc.,Units,n sides,OD,ID,Shroud Count,Shroud Len,Shroud Material,Chute Thickness,Chute Material,Mass Units,Mass,Mass,Mass,Mass,Mass,Mass\r
+Public Missiles,PML Xform,12 in. nylon,in.,4,12,0,4,12,Thin poly,,Rip stop nylon,oz.,0.3,,,,,\r
+Public Missiles,PML PAR-18-F111,18 in. nylon,in.,8,18,3.5,8,13,Thin poly,0,Rip stop nylon,oz.,0.6,,,,,\r
+Public Missiles,PML PAR-24R,24 in. nylon,in.,8,24,6,8,20,Thin poly,0,Rip stop nylon,oz.,1.6,,,,,\r
+Public Missiles,PML PAR-30R,30 in. nylon,in.,8,30,6,8,24,Thin poly,0,Rip stop nylon,oz.,2.4,,,,,\r
+Public Missiles,PML PAR-34R,34 in. nylon,in.,8,34,7,8,25,Thin poly,0,Rip stop nylon,oz.,2.9,,,,,\r
+Public Missiles,PML PAR-36R,36 in. nylon,in.,8,36,7,8,27,Thin poly,0,Rip stop nylon,oz.,3.1,,,,,\r
+Public Missiles,PML PAR-44R,44 in. nylon,in.,8,44,7,8,32,Thin poly,0,Rip stop nylon,oz.,4.1,,,,,\r
+Public Missiles,PML PAR-48R,48 in. nylon,in.,8,48,7,8,36,Thin poly,0,Rip stop nylon,oz.,4.4,,,,,\r
+Public Missiles,PML PAR-54R,54 in. nylon,in.,8,54,8,8,41,Medium poly,0,Rip stop nylon,oz.,4.8,,,,,\r
+Public Missiles,PML PAR-60R,60 in. nylon,in.,8,60,9.5,10,42,Heavy poly,0,Rip stop nylon,oz.,7.9,,,,,\r
+Public Missiles,PML PAR-62R,62 in. nylon,in.,8,62,9.5,10,44,Heavy poly,0,Rip stop nylon,oz.,8.3,,,,,\r
+Public Missiles,PML PAR-72R,72 in. nylon,in.,8,72,10,10,45,Heavy poly,0,Rip stop nylon,oz.,9,,,,,\r
+Public Missiles,PML PAR-74R,74 in. nylon,in.,8,74,10,10,47,Heavy poly,0,Rip stop nylon,oz.,9.5,,,,,\r
+Public Missiles,PML PAR-84R,84 in. nylon,in.,8,84,12,10,60,Heavy poly,0,Rip stop nylon,oz.,11.9,,,,,\r
+Public Missiles,PML PAR-96R,96 in. nylon,in.,8,96,12,10,72,Heavy poly,0,Rip stop nylon,oz.,25.5,,,,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/SLDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/SLDATA.CSV
new file mode 100644 (file)
index 0000000..fa49974
--- /dev/null
@@ -0,0 +1,2 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine,Engine\r
+Estes,Eng. Hook Sleeve,BT-20 Sleeve,mm,18.693999999999999,18.948,8.,Paper,0.\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/STDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/STDATA.CSV
new file mode 100644 (file)
index 0000000..52c2bb1
--- /dev/null
@@ -0,0 +1,3 @@
+Mfg.,Part No.,Desc.,Units,Length,Width,Thickness,Count,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material,Material\r
+Public Missiles,PML TBD123,Streamer,in,120,3,0.002,1,Polyethylene LDPE,,,,,,,,,,\r
+Public Missiles,STREAMER,F111 streamer,in,144,4,0.0005,1,Rip stop nylon,,,,,,,,,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/TCDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/TCDATA.CSV
new file mode 100644 (file)
index 0000000..b10fdc7
--- /dev/null
@@ -0,0 +1,9 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Mass Units,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass\r
+Public Missiles Ltd.,PML CT-1.52,Coupler tube,in.,1.401,1.525,3,Kraft phenolic,oz.,0.3,,,,,,,,,\r
+Public Missiles Ltd.,PML CT-2.15,Coupler tube,in.,2.028,2.152,4,Kraft phenolic,oz.,0.7,,,,,,,,,\r
+Public Missiles Ltd.,PML CT-2.56,Coupler tube,in.,2.436,2.56,5,Kraft phenolic,oz.,1.1,,,,,,,,,\r
+Public Missiles Ltd.,PML CT-3.00,Coupler tube,in.,2.878,3.002,5,Kraft phenolic,oz.,1.3,,,,,,,,,\r
+Public Missiles Ltd.,PML CT-3.90,Coupler tube,in.,3.776,3.9,7,Kraft phenolic,oz.,2.6,,,,,,,,,\r
+Public Missiles Ltd.,PML CT-6.00,Coupler tube,in.,5.859,6.007,12,Kraft phenolic,oz.,5.4,,,,,,,,,\r
+Public Missiles Ltd.,PML CT-7.51,Coupler tube,in.,7.352,7.512,12,Kraft phenolic,oz.,15.4,,,,,,,,,\r
+Public Missiles Ltd.,PML CT-11.4,Coupler tube,in.,11.16,11.41,16,Kraft phenolic,oz.,30.3,,,,,,,,,\r
diff --git a/core/resources-src/datafiles/rocksim_components/publicmissiles/TRDATA.CSV b/core/resources-src/datafiles/rocksim_components/publicmissiles/TRDATA.CSV
new file mode 100644 (file)
index 0000000..e2eef59
--- /dev/null
@@ -0,0 +1,10 @@
+Mfg.,Part No.,Desc.,Units,Front Insert Len,Front Insert OD,Front OD,Length,Rear OD,Core Dia.,Rear Insert Len,Rear Insert OD,Thickness,Config,Material,CG Loc,Mass Units,Mass,Shape\r
+Public Missiles,PML TC-2.1-1.1,Transition (or tailcone) from 2.152 to 1.145,in,0.25,2.152,2.276,1.75,1.269,0,0,0,0.2189,1,Urethane,0.692,oz.,1.5,0\r
+Public Missiles,PML TC-2.5-1.1,Transition (or tailcone) from 2.560 to 1.145,in,0.25,2.56,2.684,1.75,1.269,0,0,0,0.334,1,Urethane,0.645,oz.,2.7,0\r
+Public Missiles,PML TC-2.5-1.5,Transition (or tailcone) from 2.560 to 1.525,in,0.188,2.56,2.684,1.75,1.649,0,0,0,0.17,1,Urethane,0.658,oz.,1.5,0\r
+Public Missiles,PML TC-3.0-1.5,Transition (or tailcone) from 3.002 to 1.525,in,0.25,3.002,3.126,1.75,1.649,0,0,0,0.263,1,Urethane,0.644,oz.,2.8,0\r
+Public Missiles,PML TC-3.0-2.1,Transition (or tailcone) from 3.002 to 2.152,in,0.25,3.002,3.126,1.75,2.276,0,0,0,0.155,1,Urethane,0.688,oz.,1.8,0\r
+Public Missiles,PML TC-3.9-2.1,Transition (or tailcone) from 3.900 to 2.152,in,0.25,3.9,4.024,1.75,2.276,0,0,0,0.225,1,Urethane,0.618,oz.,3.6,0\r
+Public Missiles,PML TC-3.9-3.0,Transition (or tailcone) from 3.900 to 3.002,in,0.25,3.9,4.024,1.75,3.126,0,0,0,0.205,1,Urethane,0.658,oz.,3.4,0\r
+Public Missiles,Large Lunar,Boattail,in,6.155,5.987,6.155,20,2.276,0,0.001,2.132,0.0875,1,Polystyrene PS,0,oz.,20,1\r
+Public Missiles,Little Lunar,Boatail,in,4.024,3.88,4.024,12,1.649,0,0.001,1.505,0.063,1,Polystyrene PS,0,oz.,0,1\r
diff --git a/core/resources-src/datafiles/rocksim_components/quest/BTDATA.CSV b/core/resources-src/datafiles/rocksim_components/quest/BTDATA.CSV
new file mode 100644 (file)
index 0000000..0b0fd7c
--- /dev/null
@@ -0,0 +1,13 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Mass Units,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass,Mass\r
+Quest,10311,MMX Engine Tube/1in,in,0.252,0.276,1,Paper,,oz,0.05,,,,,,,,,,,,,,,,,,,
+Quest,9527,MMX Body Tube/6in,in,0.257,0.277,6,Paper,,oz,0.05,,,,,,,,,,,,,,,,,,,
+Quest,9528,MMX Body Tube/6in,in,0.372,0.392,6,Paper,,oz,0.05,,,,,,,,,,,,,,,,,,,
+Quest,Red tint payload tube,Clear Red Body Tube/4in,in,0.944,0.984,4,Plastic,,oz,0.3,,,,,,,,,,,,,,,,,,,
+Quest,T153000,Body Tube/30in,in,0.55,0.59,30,Paper,,oz,0.6,,,,,,,,,,,,,,,,,,,
+Quest,T203000,Body Tube/30in,in,0.752,0.788,30,Paper,,oz,0.7,,,,,,,,,,,,,,,,,,,
+Quest,10315,D5 Motor Mount Tube/3.65in,in,0.795,0.835,3.65,Paper,,oz,0.01,,,,,,,,,,,,,,,,,,,
+Quest,T253000,Body Tube/30in,in,0.944,0.984,30,Paper,,oz,0.95,,,,,,,,,,,,,,,,,,,
+Quest,T303000,Body Tube/30in,in,1.141,1.181,30,Paper,,oz,1.2,,,,,,,,,,,,,,,,,,,
+Quest,T353000,Body Tube/30in,in,1.34,1.38,30,Paper,,oz,1.25,,,,,,,,,,,,,,,,,,,
+Quest,T403000,Body Tube/30in,in,1.53,1.57,30,Paper,,oz,1.35,,,,,,,,,,,,,,,,,,,
+Quest,T502400,Body Tube/24in,in,1.92,1.97,24,Paper,,oz,2,,,,,,,,,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/quest/CRDATA.CSV b/core/resources-src/datafiles/rocksim_components/quest/CRDATA.CSV
new file mode 100644 (file)
index 0000000..a86ce77
--- /dev/null
@@ -0,0 +1,15 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,AutoSize,,,\r
+Quest,CR2125,Paper Center Ring D5(20mm) to T25 x.045,in,0.835,0.944,0.045,Paper,0,g,0.01,0
+Quest,CR2130,Paper Center Ring D5(20mm) to T30 x.045,in,0.835,1.141,0.045,Paper,0,g,0.01,0
+Quest,CR2135,Paper Center Ring D5(20mm) to T35 x.045,in,0.835,1.34,0.045,Paper,0,g,0.01,0
+Quest,CR2140,Paper Center Ring D5(20mm) to T40 x.045,in,0.835,1.53,0.045,Paper,0,g,0.01,0
+Quest,CR2150,Paper Center Ring D5(20mm) to T50 x.07,in,0.835,1.92,0.07,Paper,0,g,0.01,0
+Quest,14007,MMX Centering Ring .278 x .37 x .5in,in,0.278,0.37,0.5,Paper,0,oz,0.01,0
+Quest,CR24,Paper Center Ring .75 x .942 x .25,in,0.75,0.942,0.25,Paper,0,g,0,0
+Quest,CR2924,Paper Center Ring .994(25mm)x 1.134(29mm) x .5,in,0.994,1.134,0.5,Paper,0,g,0,0
+Quest,CR29,Paper Center Ring 10303(18mm) to T30 x .045,in,0.738,1.141,0.045,Paper,0,g,0,0
+Quest,CR2534,Paper Center Ring T25(24mm) to T35 x .05,in,0.984,1.34,0.05,Paper,0,g,0,0
+Quest,CR34,Paper Center Ring 10303(18mm) to T35 x .045,in,0.738,1.34,0.045,Paper,0,g,0,0
+Quest,CR39,Paper Center Ring 10303(18mm) to T40 x .045,in,0.738,1.53,0.045,Paper,0,g,0,0
+Quest,CR4924,Paper Center Ring T25(24mm) to T50 x .07,in,0.984,1.92,0.07,Paper,0,g,0,0
+Quest,CR4929,Paper Center Ring T29(29mm) to T50 x .07,in,1.215,1.92,0.07,Paper,0,g,0,0
diff --git a/core/resources-src/datafiles/rocksim_components/quest/EBDATA.CSV b/core/resources-src/datafiles/rocksim_components/quest/EBDATA.CSV
new file mode 100644 (file)
index 0000000..59531fa
--- /dev/null
@@ -0,0 +1,5 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+Quest Aerospace,14005,MMX Thrust Ring/.25 x .25in,in,0.148,0.248,0.25,Paper,0.125,oz,0.01,0
+Quest Aerospace,14000,Thrust Ring for 10303 Eng. Tube/ .25in,in,0.51,0.708,0.25,Paper,0.125,g,0,0
+Quest Aerospace,14101,D5 Thrust Ring/ .25in,in,0.545,0.795,0.25,Paper,0.125,g,0.01,0
+Quest Aerospace,14103,Engine Block 29mm/ .25in,in,0.9,1.136,0.25,Paper,0.125,g,0,0
diff --git a/core/resources-src/datafiles/rocksim_components/quest/MATERIAL.CSV b/core/resources-src/datafiles/rocksim_components/quest/MATERIAL.CSV
new file mode 100644 (file)
index 0000000..5c9db02
--- /dev/null
@@ -0,0 +1,162 @@
+Material Name,Units,Density,Low,High,Class,Rocketry Use,Body Tubes,Fin Sets,Launch Lugs,Cords,Nose,Chute,Stream,Trans,Ring,Bulkhead,Engine Block,Sleeve,Tube Coupler,spare,spare,spare,spare,spare,spare,spare,Known Dim type,Known Dim Units,Known Dim Value\r
+,kg/m3,0,0,0,unknown,1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+"G10 (PML 0.062"")",kg/m3,1309.,1309.,1309.,unknown,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+.060 Carbon Fiber,kg/m3,1400,1400,1400,Carbon Fiber,1,1,0,0,0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+.125 in Fiberglass/Honeycomb,lb/ft3,28.8,28.8,28.8,unknown,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+.25 in Fiberglass/Honeycomb,lb/ft3,14.7,14.7,14.7,unknown,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1 in. Flat Elastic,oz/in,0.0139,0.0139,0.0139,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1 in. Tubular Nylon,oz/in,0.04,0.04,0.04,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.1 Ounce Rip Stop Nylon,lb/ft3,0.0037351,0.0037351,0.0037351,Nylon,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.1 oz. Rip Stop Nylon,oz/in2,0.00085,0.00085,0.00085,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.3 oz. Ripstop Nylon (SkyAngle),oz/in2,0.001003,0.001003,0.001003,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.7 oz. Ripstop Nylon ,oz/in2,0.0013117,0.0013117,0.0013117,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.9 oz. Ripstop Nylon (SkyAngle),oz/in2,0.001466,0.001466,0.001466,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.9 oz. Ripstop Nylon (PML),oz/in2,0.002,0.002,0.002,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1.9 oz. Ripstop Nylon ,oz/in2,0.001466,0.001466,0.001466,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/16 in. Aircraft Plywood,kg/m3,361.3765253,361.3765253,361.3765253,Wood,1,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/16 in. Braided Nylon,g/cm,0.0102,0.0102,0.0102,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/16 in. Round Elastic,g/cm,0.0183,0.0183,0.0183,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/2 in. Flat Elastic,oz/in,0.0028,0.0028,0.0028,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/2 in. Tubular Kevlar,oz/in,0.04,0.04,0.04,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/2 in. Tubular Nylon,lb/ft3,0.0038,0.0038,0.0038,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/32 in. Kevlar,g/cm,0.00659,0.00659,0.00659,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 Aircraft Plywood,kg/m3,344.269,344.269,344.269,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 in. Braided Nylon,lb/ft3,0.00408,0.00408,0.00408,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 in. Aircraft Plywood,kg/m3,344.2688068,344.2688068,344.2688068,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 In. Flat Elastic,g/cm,0.0402,0.0402,0.0402,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/4 in. Tubular Kevlar,oz/in,0.02,0.02,0.02,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 Aircraft Plywood,kg/m3,337.541,337.541,337.541,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in Birch Plywood (Revell),lb/ft3,40,40,40,unknown,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Aircraft Plywood,lb/ft3,42,42,42,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Braided Nylon,lb/ft3,0.00204,0.00204,0.00204,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Flat Elastic,g/cm,0.0205,0.0205,0.0205,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Flat Rubber,g/cm,0.0231,0.0231,0.0231,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1/8 in. Tubular Kevlar,oz/in,0.01,0.01,0.01,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+100 lb Kevlar (Apogee 29505),lb/ft3,0.000397,0.000397,0.000397,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+100 lb. Kevlar,lb/ft3,0.00205,0.00205,0.00205,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+100lb Kevlar (Apogee 29505),lb/ft3,0.000397,0.000397,0.000397,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1500 lb. Kevlar,lb/ft3,0.0059875,0.0059875,0.0059875,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+1500lb Kevlar (Apogee 29507),lb/ft3,0.0059875,0.0059875,0.0059875,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+260 lb. Elastic,kg/m3,0,0,0,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/16 Aircraft Plywood,kg/m3,344.2688068,344.2688068,344.2688068,unknown,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/16 in. Aircraft Plywood,kg/m3,344.2688068,344.2688068,344.2688068,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/4 in. Flat Elastic,oz/in,0.011,0.011,0.011,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 in. Flat Elastic,lb/ft3,0.0038,0.0038,0.0038,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 in. Tubular Nylon ,oz/in,0.0166667,0.0166667,0.0166667,Nylon,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 in. Tubular Nylon (SkyAngle),oz/in,0.0166667,0.0166667,0.0166667,Nylon,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+3/8 inch Flat Elastic,lb/ft3,0.0038,0.0038,0.0038,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+"3/8"" tubular nylon (SkyAngle)",lb/ft3,0.186021,0.186021,0.186021,unknown,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+"3/8"" tubular nylon (SkyAngle)",lb/ft3,0.186021,0.186021,0.186021,unknown,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+30 Lb. Kevlar,g/cm,0.00178,0.00178,0.00178,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+300 lb. Kevlar (Apogee 29506),lb/ft3,0.0011286,0.0011286,0.0011286,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+300 lb. Kevlar,lb/ft3,0.0011286,0.0011286,0.0011286,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+300lb Kevlar (Apogee 29506),lb/ft3,0.0011286,0.0011286,0.0011286,unknown,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+4000 lb. nylon,kg/m3,0,0,0,Nylon,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+5/64 in. Round Elastic,g/cm,0.0242,0.0242,0.0242,Rubber,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+5/8 in. Tubular Nylon,oz/in,0.02,0.02,0.02,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+5/8 in. Tubular Nylon (SkyAngle),oz/in,0.02,0.02,0.02,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+6000 lb. nylon,kg/m3,0,0,0,Nylon,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+6oz & 2oz FG & Poster board,kg/m3,798.85,798.85,798.85,Paper,1,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+7/16 in. Flat Braided Kevlar,oz/in,0.045,0.045,0.045,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+70 Lb. Kevlar,g/cm,0.0033,0.0033,0.0033,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+750 Lb. Kevlar,oz/in,0.0027,0.0027,0.0027,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+9/16 in. Tubular Nylon,oz/in,0.015,0.015,0.015,Nylon,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Acrylic (Cast),lb/ft3,74,74,74,Acrylic,1,0,1,0,0,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Aircraft plywood (Birch),lb/ft3,45.26,43.56,46.96,Wood,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Aircraft plywood (LOC),lb/ft3,45.26,43.56,46.96,Wood,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Aluminum,kg/m3,2698.9,2698.9,2698.9,Metal,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Aluminum (Al),kg/m3,2698.9,2698.9,2698.9,Metal,1,0,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Aluminum 2024,kg/m3,2780,2780,2780,Metal,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Aluminum 7075,kg/m3,2810,2810,2810,Metal,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Ash,lb/ft3,42.5,40,45,Wood,1,0,1,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Balsa,lb/ft3,8,8,8,Wood,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+Basswood,lb/ft3,26.5,25,28,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Beech,lb/ft3,45,45,45,Wood,0,0,1,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Birch,lb/ft3,42.5,42.5,42.5,Wood,1,1,1,0,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Birch Plywood (Revell),lb/ft3,41,41,41,unknown,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Blue Tube,g/cm3,1.237,1.237,1.237,Paper,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Blue Tube 2,g/cm3,1.25,1.25,1.25,Paper,1,1,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Brass,lb/ft3,534,534,534,Metal,1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Carbon Fiber,kg/m3,1400,1400,1400,Carbon Fiber,1,1,1,0,0,1,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Cardboard,lb/ft3,43,43,43,Cardboard,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Carpet String,g/cm,0.0032972,0.0032972,0.0032972,String,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Carpet String (Apogee 29500),g/cm,0.0032972,0.0032972,0.0032972,String,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Cellulose Acetate Propionate,lb/ft3,74.9,74.9,74.9,Plastic,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Chalk (Fine),lb/ft3,70,70,70,Chalk,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Copper (cast),lb/ft3,542,542,542,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Copper (rolled),lb/ft3,556,556,556,Metal,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Cork (Solid),lb/ft3,15,15,15,Cork,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Cottonwood,lb/ft3,25,25,25,Wood,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Composite Fin Material,lb/ft3,39.6,39.6,39.6,Cardboard,1,0,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Custom,kg/m3,0.,0.,0.,unknown,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Fiber,lb/ft3,41,41,41,Fiber ,1,1,0,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Fiberglass,lb/ft3,118.94,118.94,118.94,Fiberglass,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Fir (Douglas),lb/ft3,35,35,35,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Fir (White),lb/ft3,25,25,25,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 (PML 0.062"),lb/ft3,0.0044074,0.0044074,0.0044074,unknown,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 (PML 0.062),oz/in2,0.0714,0.0714,0.0714,Fiberglass,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 (PML 0.093),oz/in2,0.1143,0.1143,0.1143,Fiberglass,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 (PML 0.125),oz/in2,0.1404,0.1404,0.1404,Fiberglass,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 Fiberglass Filament Wound,kg/m3,1934,1934,1934,Fiberglass,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+G10 Fiberglass Filament Wound Tube,kg/m3,1820,1820,1820,Fiberglass,1,1,0,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+G10 Fiberglass,lb/ft3,135.8,135.8,135.8,Fiberglass,1,1,1,0,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+G10 Fiberglass (LOC),lb/ft3,118.94,118.94,118.94,Fiberglass,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+G10 Phenolic,lb/ft3,118.94,118.94,118.94,Fiberglass,1,1,1,0,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+G12 Fiberglass,kg/m3,0.,0.,0.,unknown,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Glassed Phenolic,kg/m3,1900,1900,1900,unknown,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Gold (24 kt.),lb/ft3,1204,1204,1204,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Kevlar Thread (Apogee 29502),g/cm,0.0008858,0.0008858,0.0008858,Kevlar,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Kraft phenolic,lb/ft3,58.9,58.9,58.9,unknown,1,1,0,0,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Kraft phenolic (Glassed),kg/m3,1153.329336,1153.329336,1153.329336,Paper,1,1,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Lead (cast),lb/ft3,708,708,708,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Lead (rolled),lb/ft3,711,711,711,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Lead Shot,kg/m3,6727.75,6727.75,6727.75,Metal,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Leather,lb/ft3,59,59,59,Leather,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Lexan,g/cm3,1.218,1.218,1.218,Lexan,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Mat Board 4-Ply,kg/m3,710.579,710.579,710.579,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Spiral/Glassine-Thick,kg/m3,768.886,768.886,768.886,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Vulcanized Fiber,kg/m3,1250,1250,1250,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Lite Plywood,lb/ft3,22,22,22,Wood,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Mail Tube Paper,kg/m3,800,800,800,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Magna Phenolic,g/cm3,1.1,1.1,1.1,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Dyna-Wind Tubing,g/cm3,1.21,1.21,1.21,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0\r
+Maple (Hard),lb/ft3,39.5,35,44,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Mylar,g/cm3,1.309,1.309,1.309,unknown,1,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Nickel 200,kg/m3,8890,8890,8890,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel 400,kg/m3,8800,8800,8800,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel 600,kg/m3,8410,8410,8410,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel 625,kg/m3,8440,8440,8440,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel 718,kg/m3,8230,8230,8230,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nickel C276,kg/m3,8890,8890,8890,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Nylon,g/cm3,1.14,1.141.14,0,Nylon,1,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0\r
+Oak (Brown),lb/ft3,45,45,45,Wood,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Oak (Red),lb/ft3,45,45,45,Wood,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Oak (White),lb/ft3,47,47,47,Wood,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Paper,lb/ft3,38,38,38,Paper,1,1,1,1,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Paper/2layers 8 oz.  glass,kg/m3,1681.94,1681.94,1681.94,Paper,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Pine (White Northern),lb/ft3,25,25,25,Wood,1,1,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+Pine (White Western),lb/ft3,27,27,27,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0\r
+Plastic,kg/m3,920,920,920,Plastic,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Polycarbonate,lb/ft3,74.9,74.9,74.9,Plastic,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Polyethylene,kg/m3,920,920,920,Plastic,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Polyethylene LDPE,lb/ft3,57.7,57.7,57.7,Plastic,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Polystyrene PS,lb/ft3,65.5,65.5,65.5,Plastic,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Poplar (Yellow),lb/ft3,30,30,30,Wood,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+PVC,lb/ft3,81.2,81.2,81.2,Plastic,1,1,1,0,0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Quantum Tubing,g/cm3,1.1,1.1,1.1,Paper,1,1,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0\r
+Rip stop nylon,g/cm2,0.006685,0.006685,0.006685,Nylon,1,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Rocketwood,lb/ft3,33.03,33.03,33.03,Wood,1,1,1,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Russian 1/8 in. Plywood,kg/m3,685.1,685.1,685.1,Wood,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Silver,lb/ft3,653,653,653,Metal,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Spiral/Glassine,lb/ft3,53,53,53,Paper,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Spruce,lb/ft3,28,28,28,Wood,1,0,1,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+Stainless steel 17-4PH,kg/m3,7600,7600,7600,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Stainless steel 17-5PH,kg/m3,7800,7800,7800,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Stainless steel 17-7PH,kg/m3,7800,7800,7800,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Steel,kg/m3,7850,7850,7850,Metal,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Steel 4130,kg/m3,7850,7850,7850,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Steel 4340,kg/m3,7850,7850,7850,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Sycamore,lb/ft3,35,35,35,Wood,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\r
+Titanium,kg/m3,4500,4500,4500,Metal,0,1,1,1,0,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0\r
+Urethane,lb/ft3,52.88,52.88,52.88,unknown,1,0,0,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0\r
+lite ply,kg/m3,352.406186,352.406186,352.406186,Wood,1,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/quest/NCDATA.CSV b/core/resources-src/datafiles/rocksim_components/quest/NCDATA.CSV
new file mode 100644 (file)
index 0000000..f2a8ec5
--- /dev/null
@@ -0,0 +1,11 @@
+Mfg.,Part No.,Desc.,Units,Length,Outer Dia,L/D Ratio,Insert Length,Insert OD,Thickness,Shape,Config,Material,CG Loc,Mass Units,Mass,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len,Base Ext. Len\r
+Quest,19990,MMX ,in,1,0.392,0,0.375,0.372,0,ogive,solid,Balsa,,oz,0.5,0,,,,,,,,,,,,,
+Quest,PNC15,15mm Plastic Nose Cone,in,1,0.59,0,0.25,0.54,0.125,ogive,hollow,Polystyrene PS,0.625,oz,0.08,0,,,,,,,,,,,,,
+Quest,PNC20,20mm Plastic Nose Cone,in,2.53,0.787,0,0.5,0.75,0.125,ogive,hollow,Polystyrene PS,1.51,oz,0.1,0,,,,,,,,,,,,,
+Quest,PNC25,25mm Plastic Nose Cone,in,3.15,0.984,0,0.5,0.934,0.125,ogive,hollow,Polystyrene PS,1.82,oz,0.25,0,,,,,,,,,,,,,
+Quest,PNC30,30mm Plastic Nose Cone,in,3.25,1.18,0,0.75,1.13,0.125,ogive,hollow,Polystyrene PS,0,oz,0.5,0,,,,,,,,,,,,,
+Quest,PNC35,35mm Plastic Nose Cone,in,4.12,1.38,0,0.75,1.33,0.125,ogive,hollow,Polystyrene PS,2.44,oz,0.36,0,,,,,,,,,,,,,
+Quest,PNC35N,35mm Plastic Nike Nose Cone,in,8,1.38,0,0.75,1.33,0.125,cone,hollow,Polystyrene PS,4.53,oz,0.9,0,,,,,,,,,,,,,
+Quest,PNC35B2,35mm Plastic X-15 Nose Cone,in,4.5,1.38,0,0.75,1.33,0.125,ogive,hollow,Polystyrene PS,0,oz,0.43,0,,,,,,,,,,,,,
+Quest,PNC40,40mm Plastic Nose Cone,in,2.5,1.57,0,0.75,1.5,0.125,elliptical,hollow,Polystyrene PS,1.75,oz,0.4,0,,,,,,,,,,,,,
+Quest,PNC50,50mm Plastic Nose Cone,mm,152.40000000000001,50.038000000000004,0.,57.150000000000006,48.260000000000005,3.175,ogive,hollow,Polystyrene PS,134.36600000000001,g,42.524000000000001,0.
diff --git a/core/resources-src/datafiles/rocksim_components/quest/PCDATA.CSV b/core/resources-src/datafiles/rocksim_components/quest/PCDATA.CSV
new file mode 100644 (file)
index 0000000..4a3ff9a
--- /dev/null
@@ -0,0 +1,2 @@
+Mfg.,Part No.,Desc.,Units,n sides,OD,ID,Shroud Count,Shroud Len,Shroud Material,Chute Thickness,Chute Material,Mass Units,Mass,CG,Cd,AutoSize,AutoSize,AutoSize,AutoSize,0,0,0,0,0,0,0,0,0,0\r
+Quest,7810,14 in Plastic Parachute,in,6,14,0,6,14,Carpet String,0.002,Polyethylene LDPE,oz,1,0,0.75,,,,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/quest/STDATA.CSV b/core/resources-src/datafiles/rocksim_components/quest/STDATA.CSV
new file mode 100644 (file)
index 0000000..3c5aa4a
--- /dev/null
@@ -0,0 +1,2 @@
+Mfg.,Part No.,Desc.,Units,Length,Width,Thickness,Count,Material\r
+Quest,7811,Streamer 3in x 36in (2mil Plastic),in,36,3,0.001,1,Polyethylene LDPE
diff --git a/core/resources-src/datafiles/rocksim_components/quest/TCDATA.CSV b/core/resources-src/datafiles/rocksim_components/quest/TCDATA.CSV
new file mode 100644 (file)
index 0000000..6d0efab
--- /dev/null
@@ -0,0 +1,4 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize,AutoSize\r
+Quest,10100,.98in Tube coupler/2in,in,0.922,0.984,2,Kraft Phenolic,1,oz,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Quest,3535,1.34in Plastic tube coupler 1in shoulder,in,1.215,1.34,2.125,Plastic,1.06,oz,0.35,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
+Quest,10104,1.34in Tube coupler/2.5in,in,1.3,1.34,2.5,Kraft Phenolic,1.25,oz,1,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/quest/TRDATA.CSV b/core/resources-src/datafiles/rocksim_components/quest/TRDATA.CSV
new file mode 100644 (file)
index 0000000..747cc75
--- /dev/null
@@ -0,0 +1,9 @@
+Mfg.,Part No.,Desc.,Units,Front Insert Len,Front Insert OD,Front OD,Length,Rear OD,Core Dia.,Rear Insert Len,Rear Insert OD,Thickness,Config,Material,CG Loc,Mass Units,Mass,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape,Shape\r
+Quest,2520,Ribbed Plastic Reducer 25mm/20mm,in,0.75,0.944,0.984,0.5,0.788,0,0.75,0.752,0.125,hollow,Polystyrene PS,0,oz,0.2,cone,,,,,,,,,,,
+Quest,2520 -R,Ribbed Plastic Reducer 20mm/25mm -Rev,in,0.75,0.752,0.788,0.5,0.984,0,0.75,0.944,0.125,hollow,Polystyrene PS,0,oz,0.2,cone,,,,,,,,,,,
+Quest,3025,Ribbed Plastic Reducer 30mm/25mm ,in,0.75,1.141,1.181,0.5,0.984,0,0.75,0.944,0.125,hollow,Polystyrene PS,0,oz,0.25,cone,,,,,,,,,,,
+Quest,3025 -R,Ribbed Plastic Reducer 25mm/30mm -Rev,in,0.75,0.94,0.984,0.5,1.181,0,0.75,1.141,0.125,hollow,Polystyrene PS,0,oz,0.25,cone,,,,,,,,,,,
+Quest,3525,Ribbed Plastic Reducer 35mm/25mm ,in,0.5,1.34,1.38,0.75,0.984,0,0.375,0.944,0.125,hollow,Polystyrene PS,0,oz,0.25,cone,,,,,,,,,,,
+Quest,3525 -R,Ribbed Plastic Reducer 25mm/35mm -Rev,in,0.375,0.94,0.984,0.75,1.38,0,0.5,1.34,0.125,hollow,Polystyrene PS,0,oz,0.25,cone,,,,,,,,,,,
+Quest,3530,Ribbed Plastic Reducer 35mm/30mm ,in,0.5,1.34,1.38,0.75,1.181,0,0.375,1.14,0.125,hollow,Polystyrene PS,0,oz,0.25,cone,,,,,,,,,,,
+Quest,3530 -R,Ribbed Plastic Reducer 30mm/35mm -Rev ,in,0.375,1.141,1.181,0.75,1.38,0,0.5,1.34,0.125,hollow,Polystyrene PS,0,oz,0.25,cone,,,,,,,,,,,
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/BHDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/BHDATA.CSV
new file mode 100644 (file)
index 0000000..443e54c
--- /dev/null
@@ -0,0 +1,31 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+SEMROC Astronautics,BTC-5,Semroc Solid Balsa Tube Adapter - Series 5,in,0.000,0.515,0.750,Balsa,0.375,oz,0.010,0\r
+SEMROC Astronautics,BTC-7,Semroc Solid Balsa Tube Adapter - Series 7,in,0.000,0.715,1.000,Balsa,0.500,oz,0.026,0\r
+SEMROC Astronautics,BTC-8,Semroc Solid Balsa Tube Adapter - Series 8,in,0.000,0.865,1.000,Balsa,0.500,oz,0.038,0\r
+SEMROC Astronautics,BTC-8F,Semroc Solid Balsa Tube Adapter - Series 8F,in,0.000,0.885,1.000,Balsa,0.500,oz,0.038,0\r
+SEMROC Astronautics,BTC-9,Semroc Solid Balsa Tube Adapter - Series 9,in,0.000,0.950,1.500,Balsa,0.750,oz,0.045,0\r
+SEMROC Astronautics,BTC-10,Semroc Solid Balsa Tube Adapter - Series 10,in,0.000,1.000,1.500,Balsa,0.750,oz,0.064,0\r
+SEMROC Astronautics,BTC-11,Semroc Solid Balsa Tube Adapter - Series 11,in,0.000,1.130,1.500,Balsa,0.750,oz,0.069,0\r
+SEMROC Astronautics,BTC-13,Semroc Solid Balsa Tube Adapter - Series 13,in,0.000,1.300,1.750,Balsa,0.875,oz,0.125,0\r
+SEMROC Astronautics,BTC-16,Semroc Solid Balsa Tube Adapter - Series 16,in,0.000,1.600,1.750,Balsa,0.875,oz,0.175,0\r
+SEMROC Astronautics,BTC-18,Semroc Solid Balsa Tube Adapter - Series 18,in,0.000,1.800,1.750,Balsa,0.875,oz,0.200,0\r
+SEMROC Astronautics,BTC-20,Semroc Solid Balsa Tube Adapter - Series 20,in,0.000,2.000,2.100,Balsa,1.050,oz,0.265,0\r
+SEMROC Astronautics,BTC-085,Semroc Solid Balsa Tube Adapter - Series 85,in,0.000,0.865,1.500,Balsa,0.750,oz,0.057,0\r
+SEMROC Astronautics,BTC-115,Semroc Solid Balsa Tube Adapter - Series 115,in,0.000,1.150,1.750,Balsa,0.875,oz,0.112,0\r
+SEMROC Astronautics,BTC-125,Semroc Solid Balsa Tube Adapter - Series 125,in,0.000,1.250,2.000,Balsa,1.000,oz,0.160,0\r
+SEMROC Astronautics,BTC-150,Semroc Solid Balsa Tube Adapter - Series 150,in,0.000,1.500,2.000,Balsa,1.000,oz,0.235,0\r
+SEMROC Astronautics,BTC-175,Semroc Solid Balsa Tube Adapter - Series 175,in,0.000,1.750,2.250,Balsa,1.125,oz,0.335,0\r
+SEMROC Astronautics,BTC-225,Semroc Solid Balsa Tube Adapter - Series 225,in,0.000,2.250,2.500,Balsa,1.250,oz,0.635,0\r
+SEMROC Astronautics,BTC-275,Semroc Solid Balsa Tube Adapter - Series 275,in,0.000,2.750,3.000,Balsa,1.500,oz,1.135,0\r
+SEMROC Astronautics,NB-3,Semroc Solid Balsa Tube Adapter - Series BT-3,in,0.000,0.349,0.750,Balsa,0.375,oz,0.007,0\r
+SEMROC Astronautics,NB-5,Semroc Solid Balsa Tube Adapter - Series BT-5,in,0.000,0.515,0.750,Balsa,0.375,oz,0.010,0\r
+SEMROC Astronautics,NB-20,Semroc Solid Balsa Tube Adapter - Series BT-20,in,0.000,0.710,0.750,Balsa,0.375,oz,0.020,0\r
+SEMROC Astronautics,NB-30,Semroc Solid Balsa Tube Adapter - Series BT-30,in,0.000,0.725,0.750,Balsa,0.375,oz,0.020,0\r
+SEMROC Astronautics,NB-40,Semroc Solid Balsa Tube Adapter - Series BT-40,in,0.000,0.765,1.000,Balsa,0.500,oz,0.028,0\r
+SEMROC Astronautics,NB-50,Semroc Solid Balsa Tube Adapter - Series BT-50,in,0.000,0.950,1.000,Balsa,0.500,oz,0.040,0\r
+SEMROC Astronautics,NB-50L,Semroc Solid Balsa Tube Adapter - Series BT-50,in,0.000,0.950,1.190,Balsa,0.595,oz,0.077,0\r
+SEMROC Astronautics,NB-55,Semroc Solid Balsa Tube Adapter - Series BT-55,in,0.000,1.283,1.250,Balsa,0.625,oz,0.115,0\r
+SEMROC Astronautics,NB-60,Semroc Solid Balsa Tube Adapter - Series BT-60,in,0.000,1.595,1.500,Balsa,0.750,oz,0.170,0\r
+SEMROC Astronautics,NB-65,Semroc Solid Balsa Tube Adapter - Series BT-65,in,0.000,1.750,1.750,Balsa,0.875,oz,0.210,0\r
+SEMROC Astronautics,NB-70,Semroc Solid Balsa Tube Adapter - Series BT-70,in,0.000,2.175,2.000,Balsa,1.000,oz,0.220,0\r
+SEMROC Astronautics,NB-80,Semroc Solid Balsa Tube Adapter - Series BT-80,in,0.000,2.558,3.000,Balsa,1.500,oz,0.370,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/BTDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/BTDATA.CSV
new file mode 100644 (file)
index 0000000..2a161f2
--- /dev/null
@@ -0,0 +1,269 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,Engine,Mass Units,Mass\r
+SEMROC Astronautics,BT-100CE,Classic Body Tube BT-100,in,3.702,3.744,3.5,Spiral/Glassine,,oz,0.43\r
+SEMROC Astronautics,BT-100D,Classic Body Tube BT-100,in,3.702,3.744,4.09,Spiral/Glassine,,oz,0.5\r
+SEMROC Astronautics,BT-100Z,Classic Body Tube BT-100,in,3.702,3.744,10.89,Spiral/Glassine,,oz,1.34\r
+SEMROC Astronautics,BT-101,Classic Body Tube BT-101,in,3.896,3.938,16.5,Spiral/Glassine,,oz,1.97\r
+SEMROC Astronautics,BT-101K,Classic Body Tube BT-101,in,3.896,3.938,7.59,Spiral/Glassine,,oz,0.91\r
+SEMROC Astronautics,BT-101LA,Classic Body Tube BT-101,in,3.896,3.938,21.4,Spiral/Glassine,,oz,2.56\r
+SEMROC Astronautics,BT-101SV,Classic Body Tube BT-101,in,3.896,3.938,24.63,Spiral/Glassine,,oz,2.95\r
+SEMROC Astronautics,BT-101T,Classic Body Tube BT-101,in,3.896,3.938,2.78,Spiral/Glassine,,oz,0.36\r
+SEMROC Astronautics,BT-20,Classic Body Tube BT-20,in,0.71,0.736,18,Spiral/Glassine,,oz,0.27\r
+SEMROC Astronautics,BT-20AE,Classic Body Tube BT-20,in,0.71,0.736,1.5,Spiral/Glassine,,oz,0.02\r
+SEMROC Astronautics,BT-20B,Classic Body Tube BT-20,in,0.71,0.736,8.65,Spiral/Glassine,,oz,0.13\r
+SEMROC Astronautics,BT-20D,Classic Body Tube BT-20,in,0.71,0.736,6.5,Spiral/Glassine,,oz,0.1\r
+SEMROC Astronautics,BT-20DJ,Classic Body Tube BT-20,in,0.71,0.736,4,Spiral/Glassine,,oz,0.06\r
+SEMROC Astronautics,BT-20G,Classic Body Tube BT-20,in,0.71,0.736,3.5,Spiral/Glassine,,oz,0.05\r
+SEMROC Astronautics,BT-20J,Classic Body Tube BT-20,in,0.71,0.736,2.75,Spiral/Glassine,,oz,0.04\r
+SEMROC Astronautics,BT-20L,Classic Body Tube BT-20,in,0.71,0.736,12,Spiral/Glassine,,oz,0.18\r
+SEMROC Astronautics,BT-20M,Classic Body Tube BT-20,in,0.71,0.736,2.25,Spiral/Glassine,,oz,0.03\r
+SEMROC Astronautics,BT-3,Classic Body Tube BT-3,in,0.345,0.375,18,Spiral/Glassine,,oz,0.13\r
+SEMROC Astronautics,BT-30,Classic Body Tube BT-30,in,0.725,0.765,9,Spiral/Glassine,,oz,0.22\r
+SEMROC Astronautics,BT-30-180,Classic Body Tube BT-30,in,0.725,0.765,18,Spiral/Glassine,,oz,0.44\r
+SEMROC Astronautics,BT-30A,Classic Body Tube BT-30,in,0.725,0.765,3.5,Spiral/Glassine,,oz,0.09\r
+SEMROC Astronautics,BT-30B,Classic Body Tube BT-30,in,0.725,0.765,6.13,Spiral/Glassine,,oz,0.15\r
+SEMROC Astronautics,BT-30C,Classic Body Tube BT-30,in,0.725,0.765,5.5,Spiral/Glassine,,oz,0.13\r
+SEMROC Astronautics,BT-30F,Classic Body Tube BT-30,in,0.725,0.765,7,Spiral/Glassine,,oz,0.17\r
+SEMROC Astronautics,BT-30J,Classic Body Tube BT-30,in,0.725,0.765,2.75,Spiral/Glassine,,oz,0.07\r
+SEMROC Astronautics,BT-30K,Classic Body Tube BT-30,in,0.725,0.765,2.34,Spiral/Glassine,,oz,0.06\r
+SEMROC Astronautics,BT-30XW,Classic Body Tube BT-30,in,0.725,0.765,3,Spiral/Glassine,,oz,0.07\r
+SEMROC Astronautics,BT-3H,Classic Body Tube BT-3,in,0.345,0.375,3,Spiral/Glassine,,oz,0.02\r
+SEMROC Astronautics,BT-3XW,Classic Body Tube BT-3,in,0.345,0.375,1.5,Spiral/Glassine,,oz,0.01\r
+SEMROC Astronautics,BT-40,Classic Body Tube BT-40,in,0.765,0.825,13.75,Spiral/Glassine,,oz,0.04\r
+SEMROC Astronautics,BT-40-185,Classic Body Tube BT-40,in,0.765,0.825,18.5,Spiral/Glassine,,oz,0.06\r
+SEMROC Astronautics,BT-40W,Classic Body Tube BT-40,in,0.765,0.825,9.25,Spiral/Glassine,,oz,0.03\r
+SEMROC Astronautics,BT-5,Classic Body Tube BT-5,in,0.515,0.541,18,Spiral/Glassine,,oz,0.22\r
+SEMROC Astronautics,BT-50,Classic Body Tube BT-50,in,0.95,0.976,18,Spiral/Glassine,,oz,0.35\r
+SEMROC Astronautics,BT-50A,Classic Body Tube BT-50,in,0.95,0.976,10,Spiral/Glassine,,oz,0.2\r
+SEMROC Astronautics,BT-50AE,Classic Body Tube BT-50,in,0.95,0.976,1.5,Spiral/Glassine,,oz,0.03\r
+SEMROC Astronautics,BT-50AH,Classic Body Tube BT-50,in,0.95,0.976,1.88,Spiral/Glassine,,oz,0.04\r
+SEMROC Astronautics,BT-50B,Classic Body Tube BT-50,in,0.95,0.976,10.25,Spiral/Glassine,,oz,0.2\r
+SEMROC Astronautics,BT-50EE,Classic Body Tube BT-50,in,0.95,0.976,5.5,Spiral/Glassine,,oz,0.11\r
+SEMROC Astronautics,BT-50F,Classic Body Tube BT-50,in,0.95,0.976,5,Spiral/Glassine,,oz,0.1\r
+SEMROC Astronautics,BT-50FE,Classic Body Tube BT-50,in,0.95,0.976,6.5,Spiral/Glassine,,oz,0.13\r
+SEMROC Astronautics,BT-50H,Classic Body Tube BT-50,in,0.95,0.976,7.75,Spiral/Glassine,,oz,0.15\r
+SEMROC Astronautics,BT-50IJ,Classic Body Tube BT-50,in,0.95,0.976,9,Spiral/Glassine,,oz,0.18\r
+SEMROC Astronautics,BT-50J,Classic Body Tube BT-50,in,0.95,0.976,2.75,Spiral/Glassine,,oz,0.05\r
+SEMROC Astronautics,BT-50KE,Classic Body Tube BT-50,in,0.95,0.976,15.5,Spiral/Glassine,,oz,0.3\r
+SEMROC Astronautics,BT-50L,Classic Body Tube BT-50,in,0.95,0.976,12.7,Spiral/Glassine,,oz,0.25\r
+SEMROC Astronautics,BT-50N,Classic Body Tube BT-50,in,0.95,0.976,14,Spiral/Glassine,,oz,0.28\r
+SEMROC Astronautics,BT-50P,Classic Body Tube BT-50,in,0.95,0.976,11,Spiral/Glassine,,oz,0.22\r
+SEMROC Astronautics,BT-50S,Classic Body Tube BT-50,in,0.95,0.976,4,Spiral/Glassine,,oz,0.08\r
+SEMROC Astronautics,BT-50SV,Classic Body Tube BT-50,in,0.95,0.976,16.25,Spiral/Glassine,,oz,0.32\r
+SEMROC Astronautics,BT-50TF,Classic Body Tube BT-50,in,0.95,0.976,16,Spiral/Glassine,,oz,0.32\r
+SEMROC Astronautics,BT-50V,Classic Body Tube BT-50,in,0.95,0.976,16.5,Spiral/Glassine,,oz,0.33\r
+SEMROC Astronautics,BT-50W,Classic Body Tube BT-50,in,0.95,0.976,9.5,Spiral/Glassine,,oz,0.19\r
+SEMROC Astronautics,BT-51CI,Classic Body Tube BT-51,in,0.984,1.011,3.88,Spiral/Glassine,,oz,0.08\r
+SEMROC Astronautics,BT-51N,Classic Body Tube BT-51,in,0.984,1.011,12.42,Spiral/Glassine,,oz,0.25\r
+SEMROC Astronautics,BT-52,Classic Body Tube BT-52,in,0.988,1.014,18,Spiral/Glassine,,oz,0.37\r
+SEMROC Astronautics,BT-52AG,Classic Body Tube BT-52,in,0.988,1.014,2.1,Spiral/Glassine,,oz,0.05\r
+SEMROC Astronautics,BT-52S,Classic Body Tube BT-52,in,0.988,1.014,3.94,Spiral/Glassine,,oz,0.08\r
+SEMROC Astronautics,BT-55,Classic Body Tube BT-55,in,1.283,1.325,18,Spiral/Glassine,,oz,0.77\r
+SEMROC Astronautics,BT-55C,Classic Body Tube BT-55,in,1.283,1.325,14,Spiral/Glassine,,oz,0.6\r
+SEMROC Astronautics,BT-55E,Classic Body Tube BT-55,in,1.283,1.325,2.1,Spiral/Glassine,,oz,0.09\r
+SEMROC Astronautics,BT-55IJ,Classic Body Tube BT-55,in,1.283,1.325,9,Spiral/Glassine,,oz,0.39\r
+SEMROC Astronautics,BT-55J,Classic Body Tube BT-55,in,1.283,1.325,2.75,Spiral/Glassine,,oz,0.12\r
+SEMROC Astronautics,BT-55KA,Classic Body Tube BT-55,in,1.283,1.325,10.5,Spiral/Glassine,,oz,0.45\r
+SEMROC Astronautics,BT-55KG,Classic Body Tube BT-55,in,1.283,1.325,16.75,Spiral/Glassine,,oz,0.72\r
+SEMROC Astronautics,BT-55S,Classic Body Tube BT-55,in,1.283,1.325,4,Spiral/Glassine,,oz,0.17\r
+SEMROC Astronautics,BT-55V,Classic Body Tube BT-55,in,1.283,1.325,16.35,Spiral/Glassine,,oz,0.7\r
+SEMROC Astronautics,BT-55W,Classic Body Tube BT-55,in,1.283,1.325,12,Spiral/Glassine,,oz,0.52\r
+SEMROC Astronautics,BT-58,Classic Body Tube BT-58,in,1.498,1.54,12.75,Spiral/Glassine,,oz,0.63\r
+SEMROC Astronautics,BT-58-180,Classic Body Tube BT-58,in,1.498,1.54,18,Spiral/Glassine,,oz,0.89\r
+SEMROC Astronautics,BT-58LJ,Classic Body Tube BT-58,in,1.498,1.54,5.38,Spiral/Glassine,,oz,0.27\r
+SEMROC Astronautics,BT-58SB,Classic Body Tube BT-58,in,1.498,1.54,6.38,Spiral/Glassine,,oz,0.32\r
+SEMROC Astronautics,BT-58SV,Classic Body Tube BT-58,in,1.498,1.54,6.13,Spiral/Glassine,,oz,0.3\r
+SEMROC Astronautics,BT-5BJ,Classic Body Tube BT-5,in,0.515,0.541,2,Spiral/Glassine,,oz,0.02\r
+SEMROC Astronautics,BT-5CJ,Classic Body Tube BT-5,in,0.515,0.541,3,Spiral/Glassine,,oz,0.04\r
+SEMROC Astronautics,BT-5P,Classic Body Tube BT-5,in,0.515,0.541,5.1,Spiral/Glassine,,oz,0.06\r
+SEMROC Astronautics,BT-5T,Classic Body Tube BT-5,in,0.515,0.541,1.5,Spiral/Glassine,,oz,0.02\r
+SEMROC Astronautics,BT-60,Classic Body Tube BT-60,in,1.595,1.637,18,Spiral/Glassine,,oz,0.96\r
+SEMROC Astronautics,BT-60AD,Classic Body Tube BT-60,in,1.595,1.637,14,Spiral/Glassine,,oz,0.75\r
+SEMROC Astronautics,BT-60AJ,Classic Body Tube BT-60,in,1.595,1.637,10,Spiral/Glassine,,oz,0.53,,,\r
+SEMROC Astronautics,BT-60C,Classic Body Tube BT-60,in,1.595,1.637,1,Spiral/Glassine,,oz,0.05,,,\r
+SEMROC Astronautics,BT-60D,Classic Body Tube BT-60,in,1.595,1.637,11,Spiral/Glassine,,oz,0.59,,,\r
+SEMROC Astronautics,BT-60DS,Classic Body Tube BT-60,in,1.595,1.637,12.5,Spiral/Glassine,,oz,0.67,,,\r
+SEMROC Astronautics,BT-60FG,Classic Body Tube BT-60,in,1.595,1.637,6.7,Spiral/Glassine,,oz,0.36,,,\r
+SEMROC Astronautics,BT-60HE,Classic Body Tube BT-60,in,1.595,1.637,8.5,Spiral/Glassine,,oz,0.45,,,\r
+SEMROC Astronautics,BT-60J,Classic Body Tube BT-60,in,1.595,1.637,2.75,Spiral/Glassine,,oz,0.15,,,\r
+SEMROC Astronautics,BT-60K,Classic Body Tube BT-60,in,1.595,1.637,7,Spiral/Glassine,,oz,0.37,,,\r
+SEMROC Astronautics,BT-60KC,Classic Body Tube BT-60,in,1.595,1.637,12.84,Spiral/Glassine,,oz,0.68,,,\r
+SEMROC Astronautics,BT-60KF,Classic Body Tube BT-60,in,1.595,1.637,16.1,Spiral/Glassine,,oz,0.86,,,\r
+SEMROC Astronautics,BT-60P,Classic Body Tube BT-60,in,1.595,1.637,16,Spiral/Glassine,,oz,0.85,,,\r
+SEMROC Astronautics,BT-60R,Classic Body Tube BT-60,in,1.595,1.637,5,Spiral/Glassine,,oz,0.27,,,\r
+SEMROC Astronautics,BT-60V,Classic Body Tube BT-60,in,1.595,1.637,4.31,Spiral/Glassine,,oz,0.23,,,\r
+SEMROC Astronautics,BT-65,Classic Body Tube BT-65,in,1.750,1.796,18,Spiral/Glassine,,oz,1.045,,,\r
+SEMROC Astronautics,BT-70,Classic Body Tube BT-70,in,2.175,2.217,18,Spiral/Glassine,,oz,1.69,,,\r
+SEMROC Astronautics,BT-70H,Classic Body Tube BT-70,in,2.175,2.217,7.15,Spiral/Glassine,,oz,0.67,,,\r
+SEMROC Astronautics,BT-70KD,Classic Body Tube BT-70,in,2.175,2.217,17.5,Spiral/Glassine,,oz,1.64\r
+SEMROC Astronautics,BT-70V,Classic Body Tube BT-70,in,2.175,2.217,10.6,Spiral/Glassine,,oz,1\r
+SEMROC Astronautics,BT-80,Classic Body Tube BT-80,in,2.558,2.6,18,Spiral/Glassine,,oz,1.53\r
+SEMROC Astronautics,BT-80KD,Classic Body Tube BT-80,in,2.558,2.6,14.2,Spiral/Glassine,,oz,1.21\r
+SEMROC Astronautics,BT-80S,Classic Body Tube BT-80,in,2.558,2.6,4.5,Spiral/Glassine,,oz,0.38\r
+SEMROC Astronautics,BTH-70-120,Classic Body Tube BTH-70,in,2.175,2.247,12,Spiral/Glassine,,oz,1.48\r
+SEMROC Astronautics,BTH-70-180,Classic Body Tube BTH-70,in,2.175,2.247,18,Spiral/Glassine,,oz,2.22\r
+SEMROC Astronautics,BTH-70-286,Classic Body Tube BTH-70,in,2.175,2.247,28.6,Spiral/Glassine,,oz,3.5\r
+SEMROC Astronautics,BTH-70-300,Classic Body Tube BTH-70,in,2.175,2.247,30,Spiral/Glassine,,oz,3.7\r
+SEMROC Astronautics,BTH-70-58,Classic Body Tube BTH-70,in,2.175,2.247,5.8,Spiral/Glassine,,oz,0.72\r
+SEMROC Astronautics,BTH-80-300,Classic Body Tube BTH-80,in,2.558,2.64,30,Spiral/Glassine,,oz,5.06\r
+SEMROC Astronautics,CPT-7180,Clear Plastic Body Tube - Series 7,in,0.715,0.741,18,Polycarbonate,,oz,0.38\r
+SEMROC Astronautics,CPT-722,Clear Plastic Body Tube - Series 7,in,0.715,0.741,2.25,Polycarbonate,,oz,0.05\r
+SEMROC Astronautics,CPT-8180,Clear Plastic Body Tube - Series 8,in,0.865,0.891,18,Polycarbonate,,oz,0.47\r
+SEMROC Astronautics,CPT-825,Clear Plastic Body Tube - Series 8,in,0.865,0.891,2.5,Polycarbonate,,oz,0.07\r
+SEMROC Astronautics,CPT-835,Clear Plastic Body Tube - Series 8,in,0.865,0.891,3.5,Polycarbonate,,oz,0.09\r
+SEMROC Astronautics,LT-085160,Large Body Tube - Series 085,in,0.865,0.945,16,Spiral/Glassine,,oz,0.8\r
+SEMROC Astronautics,LT-085220,Large Body Tube - Series 085,in,0.865,0.945,22,Spiral/Glassine,,oz,1.1\r
+SEMROC Astronautics,LT-085300,Large Body Tube - Series 085,in,0.865,0.945,30,Spiral/Glassine,,oz,1.5\r
+SEMROC Astronautics,LT-08580,Large Body Tube - Series 085,in,0.865,0.945,8,Spiral/Glassine,,oz,0.4\r
+SEMROC Astronautics,LT-115220,Large Body Tube - Series 115,in,1.14,1.22,22,Spiral/Glassine,,oz,1.82\r
+SEMROC Astronautics,LT-11530,Large Body Tube - Series 115,in,1.14,1.22,3,Spiral/Glassine,,oz,0.248\r
+SEMROC Astronautics,LT-115300,Large Body Tube - Series 115,in,1.14,1.22,30,Spiral/Glassine,,oz,2.48\r
+SEMROC Astronautics,LT-11535,Large Body Tube - Series 115,in,1.14,1.22,3.5,Spiral/Glassine,,oz,0.289\r
+SEMROC Astronautics,LT-11550,Large Body Tube - Series 115,in,1.14,1.22,5,Spiral/Glassine,,oz,0.413\r
+SEMROC Astronautics,LT-11555,Large Body Tube - Series 115,in,1.14,1.22,5.5,Spiral/Glassine,,oz,0.45\r
+SEMROC Astronautics,LT-11560,Large Body Tube - Series 115,in,1.14,1.22,6,Spiral/Glassine,,oz,0.5\r
+SEMROC Astronautics,LT-11575,Large Body Tube - Series 115,in,1.14,1.22,7.5,Spiral/Glassine,,oz,0.62\r
+SEMROC Astronautics,LT-11580,Large Body Tube - Series 115,in,1.14,1.22,8,Spiral/Glassine,,oz,0.66\r
+SEMROC Astronautics,LT-125122,Large Body Tube - Series 125,in,1.25,1.34,12.25,Spiral/Glassine,,oz,0.93\r
+SEMROC Astronautics,LT-125157,Large Body Tube - Series 125,in,1.25,1.34,15.75,Spiral/Glassine,,oz,1.2\r
+SEMROC Astronautics,LT-125220,Large Body Tube - Series 125,in,1.25,1.34,22,Spiral/Glassine,,oz,2.25\r
+SEMROC Astronautics,LT-125300,Large Body Tube - Series 125,in,1.25,1.34,30,Spiral/Glassine,,oz,3.05\r
+SEMROC Astronautics,LT-12580,Large Body Tube - Series 125,in,1.25,1.34,8,Spiral/Glassine,,oz,0.81\r
+SEMROC Astronautics,LT-150220,Large Body Tube - Series 150,in,1.5,1.59,22,Spiral/Glassine,,oz,2.25\r
+SEMROC Astronautics,LT-150300,Large Body Tube - Series 150,in,1.5,1.59,30,Spiral/Glassine,,oz,3.05\r
+SEMROC Astronautics,LT-15080,Large Body Tube - Series 150,in,1.5,1.59,8,Spiral/Glassine,,oz,0.97\r
+SEMROC Astronautics,LT-175220,Large Body Tube - Series 175,in,1.75,1.84,22,Spiral/Glassine,,oz,3.1\r
+SEMROC Astronautics,LT-175300,Large Body Tube - Series 175,in,1.75,1.84,30,Spiral/Glassine,,oz,4.23\r
+SEMROC Astronautics,LT-17580,Large Body Tube - Series 175,in,1.75,1.84,8,Spiral/Glassine,,oz,1.13\r
+SEMROC Astronautics,LT-200220,Large Body Tube - Series 200,in,2,2.08,22,Spiral/Glassine,,oz,3.52\r
+SEMROC Astronautics,LT-200300,Large Body Tube - Series 200,in,2,2.08,30,Spiral/Glassine,,oz,4.8\r
+SEMROC Astronautics,LT-20080,Large Body Tube - Series 200,in,2,2.08,8,Spiral/Glassine,,oz,0.768\r
+SEMROC Astronautics,LT-225140,Large Body Tube - Series 225,in,2.25,2.34,14,Spiral/Glassine,,oz,2.52\r
+SEMROC Astronautics,LT-225220,Large Body Tube - Series 225,in,2.25,2.34,22,Spiral/Glassine,,oz,3.97\r
+SEMROC Astronautics,LT-225300,Large Body Tube - Series 225,in,2.25,2.34,30,Spiral/Glassine,,oz,5.41\r
+SEMROC Astronautics,LT-22580,Large Body Tube - Series 225,in,2.25,2.34,8,Spiral/Glassine,,oz,1.44\r
+SEMROC Astronautics,LT-275220,Large Body Tube - Series 275,in,2.75,2.84,22,Spiral/Glassine,,oz,4.83\r
+SEMROC Astronautics,LT-275300,Large Body Tube - Series 275,in,2.75,2.84,30,Spiral/Glassine,,oz,6.59\r
+SEMROC Astronautics,LT-27580,Large Body Tube - Series 275,in,2.75,2.84,8,Spiral/Glassine,,oz,1.76\r
+SEMROC Astronautics,PST-50MJ,Clear Plastic Body Tube - BT50,in,0.95,0.976,6,Polycarbonate,,oz,0.17\r
+SEMROC Astronautics,PST-50S,Clear Plastic Body Tube - BT50,in,0.95,0.976,4,Polycarbonate,,oz,0.11\r
+SEMROC Astronautics,PST-55,Clear Plastic Body Tube - BT55,in,1.283,1.325,12,Polycarbonate,,oz,0.45\r
+SEMROC Astronautics,PST-55-180,Clear Plastic Body Tube - BT55,in,1.283,1.325,18,Polycarbonate,,oz,0.67\r
+SEMROC Astronautics,RT-70,Classic Body Tube BT-70,in,2.175,2.217,0.68,Spiral/Glassine,,oz,0.09\r
+SEMROC Astronautics,RT-99D,Classic Body Tube BT-99,in,3.668,3.7,0.39,Spiral/Glassine,,oz,1.42\r
+SEMROC Astronautics,ST-10100,Standard Body Tube - Series 10,in,1,1.04,10,Spiral/Glassine,,oz,0.307\r
+SEMROC Astronautics,ST-10105,Standard Body Tube - Series 10,in,1,1.04,10.5,Spiral/Glassine,,oz,0.323\r
+SEMROC Astronautics,ST-10120,Standard Body Tube - Series 10,in,1,1.04,12,Spiral/Glassine,,oz,0.369\r
+SEMROC Astronautics,ST-10180,Standard Body Tube - Series 10,in,1,1.04,18,Spiral/Glassine,,oz,0.553\r
+SEMROC Astronautics,ST-1020,Standard Body Tube - Series 10,in,1,1.04,2,Spiral/Glassine,,oz,0.061\r
+SEMROC Astronautics,ST-1030,Standard Body Tube - Series 10,in,1,1.04,3,Spiral/Glassine,,oz,0.092\r
+SEMROC Astronautics,ST-1040,Standard Body Tube - Series 10,in,1,1.04,4,Spiral/Glassine,,oz,0.123\r
+SEMROC Astronautics,ST-1050,Standard Body Tube - Series 10,in,1,1.04,5,Spiral/Glassine,,oz,0.154\r
+SEMROC Astronautics,ST-1060,Standard Body Tube - Series 10,in,1,1.04,6,Spiral/Glassine,,oz,0.184\r
+SEMROC Astronautics,ST-1080,Standard Body Tube - Series 10,in,1,1.04,8,Spiral/Glassine,,oz,0.246\r
+SEMROC Astronautics,ST-1095,Standard Body Tube - Series 10,in,1,1.04,9.5,Spiral/Glassine,,oz,0.292\r
+SEMROC Astronautics,ST-11120,Standard Body Tube - Series 11,in,1.13,1.17,12,Spiral/Glassine,,oz,0.432\r
+SEMROC Astronautics,ST-11180,Standard Body Tube - Series 11,in,1.13,1.17,18,Spiral/Glassine,,oz,0.648\r
+SEMROC Astronautics,ST-1160,Standard Body Tube - Series 11,in,1.13,1.17,6,Spiral/Glassine,,oz,0.216\r
+SEMROC Astronautics,ST-1180,Standard Body Tube - Series 11,in,1.13,1.17,8,Spiral/Glassine,,oz,0.288\r
+SEMROC Astronautics,ST-1190,Standard Body Tube - Series 11,in,1.13,1.17,9,Spiral/Glassine,,oz,0.324\r
+SEMROC Astronautics,ST-13105,Standard Body Tube - Series 13,in,1.3,1.34,10.5,Spiral/Glassine,,oz,0.436\r
+SEMROC Astronautics,ST-13130,Standard Body Tube - Series 13,in,1.3,1.34,13,Spiral/Glassine,,oz,0.54\r
+SEMROC Astronautics,ST-13135,Standard Body Tube - Series 13,in,1.3,1.34,13.5,Spiral/Glassine,,oz,0.56\r
+SEMROC Astronautics,ST-13180,Standard Body Tube - Series 13,in,1.3,1.34,18,Spiral/Glassine,,oz,0.747\r
+SEMROC Astronautics,ST-1322,Standard Body Tube - Series 13,in,1.3,1.34,2.2,Spiral/Glassine,,oz,0.091\r
+SEMROC Astronautics,ST-1330,Standard Body Tube - Series 13,in,1.3,1.34,3,Spiral/Glassine,,oz,0.125\r
+SEMROC Astronautics,ST-1340,Standard Body Tube - Series 13,in,1.3,1.34,4,Spiral/Glassine,,oz,0.166\r
+SEMROC Astronautics,ST-1363,Standard Body Tube - Series 13,in,1.3,1.34,6.25,Spiral/Glassine,,oz,0.26\r
+SEMROC Astronautics,ST-1380,Standard Body Tube - Series 13,in,1.3,1.34,8,Spiral/Glassine,,oz,0.332\r
+SEMROC Astronautics,ST-1383,Standard Body Tube - Series 13,in,1.3,1.34,8.25,Spiral/Glassine,,oz,0.342\r
+SEMROC Astronautics,ST-16100,Standard Body Tube - Series 16,in,1.6,1.64,10,Spiral/Glassine,,oz,0.509\r
+SEMROC Astronautics,ST-16109,Standard Body Tube - Series 16,in,1.6,1.64,10.9,Spiral/Glassine,,oz,0.555\r
+SEMROC Astronautics,ST-16110,Standard Body Tube - Series 16,in,1.6,1.64,11,Spiral/Glassine,,oz,0.56\r
+SEMROC Astronautics,ST-16120,Standard Body Tube - Series 16,in,1.6,1.64,12,Spiral/Glassine,,oz,0.61\r
+SEMROC Astronautics,ST-16128,Standard Body Tube - Series 16,in,1.6,1.64,12.8,Spiral/Glassine,,oz,0.651\r
+SEMROC Astronautics,ST-16130,Standard Body Tube - Series 16,in,1.6,1.64,13,Spiral/Glassine,,oz,0.662\r
+SEMROC Astronautics,ST-16132,Standard Body Tube - Series 16,in,1.6,1.64,13.2,Spiral/Glassine,,oz,0.672\r
+SEMROC Astronautics,ST-16151,Standard Body Tube - Series 16,in,1.6,1.64,15.12,Spiral/Glassine,,oz,0.77\r
+SEMROC Astronautics,ST-16160,Standard Body Tube - Series 16,in,1.6,1.64,16,Spiral/Glassine,,oz,0.814\r
+SEMROC Astronautics,ST-16161,Standard Body Tube - Series 16,in,1.6,1.64,16.125,Spiral/Glassine,,oz,0.821\r
+SEMROC Astronautics,ST-16163,Standard Body Tube - Series 16,in,1.6,1.64,16.25,Spiral/Glassine,,oz,0.827\r
+SEMROC Astronautics,ST-16180,Standard Body Tube - Series 16,in,1.6,1.64,18,Spiral/Glassine,,oz,0.916\r
+SEMROC Astronautics,ST-1620,Standard Body Tube - Series 16,in,1.6,1.64,2,Spiral/Glassine,,oz,0.102\r
+SEMROC Astronautics,ST-1622,Standard Body Tube - Series 16,in,1.6,1.64,2.25,Spiral/Glassine,,oz,0.114\r
+SEMROC Astronautics,ST-1630,Standard Body Tube - Series 16,in,1.6,1.64,3,Spiral/Glassine,,oz,0.153\r
+SEMROC Astronautics,ST-1650,Standard Body Tube - Series 16,in,1.6,1.64,5,Spiral/Glassine,,oz,0.254\r
+SEMROC Astronautics,ST-1652,Standard Body Tube - Series 16,in,1.6,1.64,5.25,Spiral/Glassine,,oz,0.267\r
+SEMROC Astronautics,ST-1660,Standard Body Tube - Series 16,in,1.6,1.64,6,Spiral/Glassine,,oz,0.305\r
+SEMROC Astronautics,ST-1667,Standard Body Tube - Series 16,in,1.6,1.64,6.7,Spiral/Glassine,,oz,0.341\r
+SEMROC Astronautics,ST-1675,Standard Body Tube - Series 16,in,1.6,1.64,7.5,Spiral/Glassine,,oz,0.382\r
+SEMROC Astronautics,ST-1685,Standard Body Tube - Series 16,in,1.6,1.64,8.5,Spiral/Glassine,,oz,0.432\r
+SEMROC Astronautics,ST-1690,Standard Body Tube - Series 16,in,1.6,1.64,9,Spiral/Glassine,,oz,0.458\r
+SEMROC Astronautics,ST-18120,Standard Body Tube - Series 18,in,1.8,1.84,12,Spiral/Glassine,,oz,0.686\r
+SEMROC Astronautics,ST-18180,Standard Body Tube - Series 18,in,1.8,1.84,18,Spiral/Glassine,,oz,1.029\r
+SEMROC Astronautics,ST-1830,Standard Body Tube - Series 18,in,1.8,1.84,3,Spiral/Glassine,,oz,0.171\r
+SEMROC Astronautics,ST-1844,Standard Body Tube - Series 18,in,1.8,1.84,4.375,Spiral/Glassine,,oz,0.241\r
+SEMROC Astronautics,ST-1860,Standard Body Tube - Series 18,in,1.8,1.84,6,Spiral/Glassine,,oz,0.343\r
+SEMROC Astronautics,ST-1890,Standard Body Tube - Series 18,in,1.8,1.84,9,Spiral/Glassine,,oz,0.514\r
+SEMROC Astronautics,ST-20120,Standard Body Tube - Series 20,in,2,2.04,12,Spiral/Glassine,,oz,0.762\r
+SEMROC Astronautics,ST-20128,Standard Body Tube - Series 20,in,2,2.04,12.8,Spiral/Glassine,,oz,0.814\r
+SEMROC Astronautics,ST-20180,Standard Body Tube - Series 20,in,2,2.04,18,Spiral/Glassine,,oz,1.145\r
+SEMROC Astronautics,ST-2030,Standard Body Tube - Series 20,in,2,2.04,3,Spiral/Glassine,,oz,0.191\r
+SEMROC Astronautics,ST-2050,Standard Body Tube - Series 20,in,2,2.04,5,Spiral/Glassine,,oz,0.318\r
+SEMROC Astronautics,ST-2060,Standard Body Tube - Series 20,in,2,2.04,6,Spiral/Glassine,,oz,0.381\r
+SEMROC Astronautics,ST-2098,Standard Body Tube - Series 20,in,2,2.04,9.8,Spiral/Glassine,,oz,0.623\r
+SEMROC Astronautics,ST-5120,Standard Body Tube - Series 5,in,0.515,0.543,12,Spiral/Glassine,,oz,0.16\r
+SEMROC Astronautics,ST-515,Standard Body Tube - Series 5,in,0.515,0.543,1.5,Spiral/Glassine,,oz,0.021\r
+SEMROC Astronautics,ST-5180,Standard Body Tube - Series 5,in,0.515,0.543,18,Spiral/Glassine,,oz,0.24\r
+SEMROC Astronautics,ST-520,Standard Body Tube - Series 5,in,0.515,0.543,2,Spiral/Glassine,,oz,0.027\r
+SEMROC Astronautics,ST-520E,Standard Body Tube - Series 5,in,0.515,0.543,2,Spiral/Glassine,,oz,0.027\r
+SEMROC Astronautics,ST-525,Standard Body Tube - Series 5,in,0.515,0.543,2.5,Spiral/Glassine,,oz,0.033\r
+SEMROC Astronautics,ST-530,Standard Body Tube - Series 5,in,0.515,0.543,3,Spiral/Glassine,,oz,0.04\r
+SEMROC Astronautics,ST-540,Standard Body Tube - Series 5,in,0.515,0.543,4,Spiral/Glassine,,oz,0.054\r
+SEMROC Astronautics,ST-545,Standard Body Tube - Series 5,in,0.515,0.543,4.5,Spiral/Glassine,,oz,0.06\r
+SEMROC Astronautics,ST-560,Standard Body Tube - Series 5,in,0.515,0.543,6,Spiral/Glassine,,oz,0.08\r
+SEMROC Astronautics,ST-590,Standard Body Tube - Series 5,in,0.515,0.543,9,Spiral/Glassine,,oz,0.12\r
+SEMROC Astronautics,ST-7100,Standard Body Tube - Series 7,in,0.715,0.759,10,Spiral/Glassine,,oz,0.158\r
+SEMROC Astronautics,ST-7120,Standard Body Tube - Series 7,in,0.715,0.759,12,Spiral/Glassine,,oz,0.192\r
+SEMROC Astronautics,ST-7180,Standard Body Tube - Series 7,in,0.715,0.759,18,Spiral/Glassine,,oz,0.288\r
+SEMROC Astronautics,ST-720,Standard Body Tube - Series 7,in,0.715,0.759,2,Spiral/Glassine,,oz,0.036\r
+SEMROC Astronautics,ST-720H,Standard Body Tube - Series 7,in,0.715,0.759,2,Spiral/Glassine,,oz,0.036\r
+SEMROC Astronautics,ST-723,Standard Body Tube - Series 7,in,0.715,0.759,2.25,Spiral/Glassine,,oz,0.039\r
+SEMROC Astronautics,ST-730,Standard Body Tube - Series 7,in,0.715,0.759,3,Spiral/Glassine,,oz,0.048\r
+SEMROC Astronautics,ST-730E,Standard Body Tube - Series 7,in,0.715,0.759,3,Spiral/Glassine,,oz,0.048\r
+SEMROC Astronautics,ST-740,Standard Body Tube - Series 7,in,0.715,0.759,4,Spiral/Glassine,,oz,0.06\r
+SEMROC Astronautics,ST-749,Standard Body Tube - Series 7,in,0.715,0.759,4.9,Spiral/Glassine,,oz,0.08\r
+SEMROC Astronautics,ST-753,Standard Body Tube - Series 7,in,0.715,0.759,5.25,Spiral/Glassine,,oz,0.085\r
+SEMROC Astronautics,ST-755,Standard Body Tube - Series 7,in,0.715,0.759,5.5,Spiral/Glassine,,oz,0.087\r
+SEMROC Astronautics,ST-758,Standard Body Tube - Series 7,in,0.715,0.759,5.8,Spiral/Glassine,,oz,0.092\r
+SEMROC Astronautics,ST-760,Standard Body Tube - Series 7,in,0.715,0.759,6,Spiral/Glassine,,oz,0.096\r
+SEMROC Astronautics,ST-765,Standard Body Tube - Series 7,in,0.715,0.759,6.5,Spiral/Glassine,,oz,0.104\r
+SEMROC Astronautics,ST-770,Standard Body Tube - Series 7,in,0.715,0.759,7,Spiral/Glassine,,oz,0.112\r
+SEMROC Astronautics,ST-790,Standard Body Tube - Series 7,in,0.715,0.759,9,Spiral/Glassine,,oz,0.144\r
+SEMROC Astronautics,ST-8100,Standard Body Tube - Series 8,in,0.865,0.908,10,Spiral/Glassine,,oz,0.25\r
+SEMROC Astronautics,ST-8103,Standard Body Tube - Series 8,in,0.865,0.908,10.3,Spiral/Glassine,,oz,0.258\r
+SEMROC Astronautics,ST-8113,Standard Body Tube - Series 8,in,0.865,0.908,11.3,Spiral/Glassine,,oz,0.283\r
+SEMROC Astronautics,ST-8120,Standard Body Tube - Series 8,in,0.865,0.908,12,Spiral/Glassine,,oz,0.36\r
+SEMROC Astronautics,ST-8150,Standard Body Tube - Series 8,in,0.865,0.908,15,Spiral/Glassine,,oz,0.375\r
+SEMROC Astronautics,ST-8180,Standard Body Tube - Series 8,in,0.865,0.908,18,Spiral/Glassine,,oz,0.45\r
+SEMROC Astronautics,ST-820,Standard Body Tube - Series 8,in,0.865,0.908,2,Spiral/Glassine,,oz,0.05\r
+SEMROC Astronautics,ST-823,Standard Body Tube - Series 8,in,0.865,0.908,2.25,Spiral/Glassine,,oz,0.055\r
+SEMROC Astronautics,ST-825,Standard Body Tube - Series 8,in,0.865,0.908,2.5,Spiral/Glassine,,oz,0.063\r
+SEMROC Astronautics,ST-830,Standard Body Tube - Series 8,in,0.865,0.908,3,Spiral/Glassine,,oz,0.075\r
+SEMROC Astronautics,ST-845,Standard Body Tube - Series 8,in,0.865,0.908,4.5,Spiral/Glassine,,oz,0.113\r
+SEMROC Astronautics,ST-855,Standard Body Tube - Series 8,in,0.865,0.908,5.5,Spiral/Glassine,,oz,0.138\r
+SEMROC Astronautics,ST-857,Standard Body Tube - Series 8,in,0.865,0.908,5.7,Spiral/Glassine,,oz,0.143\r
+SEMROC Astronautics,ST-873,Standard Body Tube - Series 8,in,0.865,0.908,7.3,Spiral/Glassine,,oz,0.183\r
+SEMROC Astronautics,ST-880,Standard Body Tube - Series 8,in,0.865,0.908,8,Spiral/Glassine,,oz,0.2\r
+SEMROC Astronautics,ST-890,Standard Body Tube - Series 8,in,0.865,0.908,9,Spiral/Glassine,,oz,0.225\r
+SEMROC Astronautics,ST-8F120,Standard Body Tube - Series 8F,in,0.885,0.921,12,Spiral/Glassine,,oz,0.3\r
+SEMROC Astronautics,ST-8F180,Standard Body Tube - Series 8F,in,0.885,0.921,18,Spiral/Glassine,,oz,0.45\r
+SEMROC Astronautics,ST-8F60,Standard Body Tube - Series 8F,in,0.885,0.921,6,Spiral/Glassine,,oz,0.149\r
+SEMROC Astronautics,ST-8F90,Standard Body Tube - Series 8F,in,0.885,0.921,9,Spiral/Glassine,,oz,0.225\r
+SEMROC Astronautics,ST-9180,Standard Body Tube - Series 9,in,0.95,0.998,18,Spiral/Glassine,,oz,0.522\r
+SEMROC Astronautics,ST-930,Standard Body Tube - Series 9,in,0.95,0.998,3,Spiral/Glassine,,oz,0.087\r
+SEMROC Astronautics,ST-940,Standard Body Tube - Series 9,in,0.95,0.998,4,Spiral/Glassine,,oz,0.116\r
+SEMROC Astronautics,ST-940E,Standard Body Tube - Series 9,in,0.95,0.998,4,Spiral/Glassine,,oz,0.116\r
+SEMROC Astronautics,ST-950,Standard Body Tube - Series 9,in,0.95,0.998,5,Spiral/Glassine,,oz,0.145\r
+SEMROC Astronautics,ST-950E,Standard Body Tube - Series 9,in,0.95,0.998,5,Spiral/Glassine,,oz,0.145\r
+SEMROC Astronautics,ST-980,Standard Body Tube - Series 9,in,0.95,0.998,8,Spiral/Glassine,,oz,0.232\r
+SEMROC Astronautics,ST-990,Standard Body Tube - Series 9,in,0.95,0.998,9,Spiral/Glassine,,oz,0.261\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/CRDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/CRDATA.CSV
new file mode 100644 (file)
index 0000000..67ccd0c
--- /dev/null
@@ -0,0 +1,60 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+SEMROC Astronautics,CR-57,Centering Ring #5 to #7,in,0.545,0.713,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,CR-58,Centering Ring #5 to #8,in,0.545,0.863,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,CR-510,Centering Ring #5 to #10,in,0.545,0.998,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-513,Centering Ring #5 to #13,in,0.545,1.298,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-78,Centering Ring #7 to #8,in,0.761,0.863,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,CR-78F,Centering Ring #7 to #8F,in,0.761,0.883,0.070,Fiber,0.035,oz,0,0\r
+SEMROC Astronautics,CR-78L,Centering Ring #7 to #8,in,0.761,0.863,0.080,Fiber,0.040,oz,0,0\r
+SEMROC Astronautics,CR-79,Centering Ring #7 to #9,in,0.761,0.948,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,CR-710,Centering Ring #7 to #10,in,0.761,0.998,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,CR-711,Centering Ring #7 to #11,in,0.761,1.110,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-713,Centering Ring #7 to #13,in,0.761,1.298,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-716,Centering Ring #7 to #16,in,0.761,1.598,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-718,Centering Ring #7 to #18,in,0.761,1.798,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-720,Centering Ring #7 to #20,in,0.761,1.998,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-9115,Centering Ring #9 to #115,in,1.000,1.120,1.000,Fiber,0.500,oz,0,0\r
+SEMROC Astronautics,CR-9-13,Centering Ring #9 to #13,in,1.000,1.298,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-916,Centering Ring #9 to #16,in,1.000,1.598,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-9-16P,Centering Ring #9 to #16,in,1.000,1.598,0.110,lite ply,0.055,oz,0,0\r
+SEMROC Astronautics,CR-918,Centering Ring #9 to #18,in,1.000,1.798,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-9-20,Centering Ring #9 to #20,in,1.000,1.998,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-9-225P,Centering Ring #9 to #225,in,1.000,2.248,0.110,lite ply,0.055,oz,0,0\r
+SEMROC Astronautics,CR-9-150P,Centering Ring #9 to #150,in,1.000,1.498,0.110,lite ply,0.055,oz,0,0\r
+SEMROC Astronautics,CR-9-70,Centering Ring #9 to BT-70,in,1.000,2.173,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-9-80,Centering Ring #9 to BT-80,in,1.000,2.566,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-9-80P,Centering Ring #9 to BT-80,in,1.000,2.566,0.110,lite ply,0.055,oz,0,0\r
+SEMROC Astronautics,CR-10-13,Centering Ring #10 to #13,in,1.042,1.298,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-10-16,Centering Ring #10 to #16,in,1.042,1.598,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-10-20,Centering Ring #10 to #20,in,1.042,1.998,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-11516,Centering Ring #115 to #16,in,1.222,1.598,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-11520,Centering Ring #115 to #20,in,1.222,1.998,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-115-18,Centering Ring #115 to #18,in,1.222,1.798,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-115-70P,Centering Ring #115 to BT-70,in,1.222,2.173,0.110,lite ply,0.055,oz,0,0\r
+SEMROC Astronautics,CR-115-150P,Centering Ring #115 to #150,in,1.222,1.498,0.100,lite ply,0.050,oz,0,0\r
+SEMROC Astronautics,CR-115-16P,Centering Ring #115 to #16,in,1.222,1.598,0.110,lite ply,0.055,oz,0,0\r
+SEMROC Astronautics,CR-115-175P,Centering Ring #115 to #175,in,1.222,1.748,0.100,lite ply,0.050,oz,0,0\r
+SEMROC Astronautics,CR-115-225P,Centering Ring #115 to #225,in,1.222,2.248,0.100,lite ply,0.050,oz,0,0\r
+SEMROC Astronautics,CR-115-275P,Centering Ring #115 to #275,in,1.222,2.748,0.100,lite ply,0.050,oz,0,0\r
+SEMROC Astronautics,RA-115-80P,Centering Ring #115 to BT-80,in,1.222,2.566,0.110,lite ply,0.055,oz,0,0\r
+SEMROC Astronautics,AR-520,Centering Ring BT-5 to BT-20,in,0.543,0.708,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,RA-520,Centering Ring BT-5 to BT-20,in,0.543,0.708,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-550,Centering Ring BT-5 to BT-50,in,0.543,0.948,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-555,Centering Ring BT-5 to BT-55,in,0.543,1.281,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-560,Centering Ring BT-5 to BT-60,in,0.543,1.593,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,AR-2050,Centering Ring BT-20 to BT-50,in,0.738,0.948,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,AR-2050S,Centering Ring BT-20 to BT-50 Split,in,0.738,0.948,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,RA-2050,Centering Ring BT-20 to BT-50,in,0.738,0.948,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-2055,Centering Ring BT-20 to BT-55,in,0.738,1.281,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-2060,Centering Ring BT-20 to BT-60,in,0.738,1.593,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-2070,Centering Ring BT-20 to BT-70,in,0.738,2.173,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-2080,Centering Ring BT-20 to BT-80,in,0.738,2.566,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,CR-50-18,Centering Ring BT-50 to #18,in,0.978,1.798,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-5055,Centering Ring BT-50 to BT-55,in,0.978,1.281,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RAH-5055,Centering Ring BT-50 to BT-55,in,0.978,1.281,0.070,Fiber,0.035,oz,0,0\r
+SEMROC Astronautics,RA-5060,Centering Ring BT-50 to BT-60,in,0.978,1.593,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RAH-5060,Centering Ring BT-50 to BT-60,in,0.978,1.593,0.070,Fiber,0.035,oz,0,0\r
+SEMROC Astronautics,RA-5070,Centering Ring BT-50 to BT-70,in,0.978,2.173,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-5080,Centering Ring BT-50 to BT-80,in,0.978,2.566,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-5560,Centering Ring BT-55 to BT-60,in,1.013,1.593,0.050,Fiber,0.025,oz,0,0\r
+SEMROC Astronautics,RA-7080,Centering Ring BT-70 to BT-80,in,2.219,2.566,0.050,Fiber,0.025,oz,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/EBDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/EBDATA.CSV
new file mode 100644 (file)
index 0000000..dd125e3
--- /dev/null
@@ -0,0 +1,12 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+SEMROC Astronautics,TB-115,Thrust Block #115,in,1.000,1.140,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,TR-115,Thrust Ring #115,in,1.000,1.140,1.000,Fiber,0.500,oz,0,0\r
+SEMROC Astronautics,TB-5,Thrust Block #5,in,0.413,0.513,0.188,Fiber,0.094,oz,0,0\r
+SEMROC Astronautics,TR-5,Thrust Ring #5,in,0.413,0.513,0.375,Fiber,0.188,oz,0,0\r
+SEMROC Astronautics,TB-7,Thrust Block #7,in,0.575,0.713,0.188,Fiber,0.094,oz,0,0\r
+SEMROC Astronautics,TR-7,Thrust Ring #7,in,0.575,0.713,0.375,Fiber,0.188,oz,0,0\r
+SEMROC Astronautics,TR-9,Thrust Ring #9,in,0.761,0.948,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,TS-9,Thrust Spacer #9,in,0.865,0.948,1.000,Fiber,0.500,oz,0,0\r
+SEMROC Astronautics,EB-20A,Engine Block BT-20,in,0.517,0.708,0.250,Fiber,0.125,oz,0,0\r
+SEMROC Astronautics,EB-20B,Engine Block BT-20,in,0.517,0.708,0.125,Fiber,0.063,oz,0,0\r
+SEMROC Astronautics,EB-30,Engine Block BT-30,in,0.532,0.723,0.750,Fiber,0.375,oz,0,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/LLDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/LLDATA.CSV
new file mode 100644 (file)
index 0000000..942e22b
--- /dev/null
@@ -0,0 +1,20 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material\r
+SEMROC Astronautics,LL-2A,Launch Lug 1/8 x 1.25,in,0.15,0.176,1.25,Paper\r
+SEMROC Astronautics,LL-2AM,Launch Lug 1/8 x .375,in,0.15,0.176,0.375,Paper\r
+SEMROC Astronautics,LL-2B,Launch Lug 1/8 x 2.375,in,0.15,0.176,2.375,Paper\r
+SEMROC Astronautics,LL-2C,Launch Lug 1/8 x 5,in,0.15,0.176,5,Paper\r
+SEMROC Astronautics,LL-2D,Launch Lug 1/8 x 8,in,0.15,0.176,8,Paper\r
+SEMROC Astronautics,LL-2E,Launch Lug 1/8 x 9.5,in,0.15,0.176,9.5,Paper\r
+SEMROC Astronautics,LL-3B,Launch Lug 3/16 x 2,in,0.214,0.24,2,Paper\r
+SEMROC Astronautics,LL-103,Launch Lug 1/8 x .375,in,0.15,0.176,0.375,Paper\r
+SEMROC Astronautics,LL-110,Launch Lug 1/8 x 1,in,0.15,0.176,1,Paper\r
+SEMROC Astronautics,LL-115,Launch Lug 1/8 x 1.5,in,0.15,0.176,1.5,Paper\r
+SEMROC Astronautics,LL-117,Launch Lug 1/8 x 1.75,in,0.15,0.176,1.75,Paper\r
+SEMROC Astronautics,LL-122,Launch Lug 1/8 x 2.25,in,0.15,0.176,2.25,Paper\r
+SEMROC Astronautics,LL-130,Launch Lug 1/8 x 3,in,0.15,0.176,3,Paper\r
+SEMROC Astronautics,LL-180,Launch Lug 1/8 x 8,in,0.15,0.176,8,Paper\r
+SEMROC Astronautics,LL-195,Launch Lug 1/8 x 9.5,in,0.15,0.176,9.5,Paper\r
+SEMROC Astronautics,LL-310,Launch Lug 3/16 x 1,in,0.214,0.24,1,Paper\r
+SEMROC Astronautics,LL-320,Launch Lug 3/16 x 2,in,0.214,0.24,2,Paper\r
+SEMROC Astronautics,LL-330,Launch Lug 3/16 x 3,in,0.214,0.24,3,Paper\r
+SEMROC Astronautics,LL-423,Launch Lug 1/4 x 2.25,in,0.276,0.302,2.25,Paper\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/MATERIAL.CSV b/core/resources-src/datafiles/rocksim_components/semroc/MATERIAL.CSV
new file mode 100644 (file)
index 0000000..6de0683
--- /dev/null
@@ -0,0 +1,11 @@
+Material Name,Units,Density,Low,High,Class,Rocketry Use,Body Tubes,Fin Sets,Launch Lugs,Cords,Nose,Chute,Stream,Trans,Ring,Bulkhead,Engine Block,Sleeve,Tube Coupler,spare,spare,spare,spare,spare,spare,spare,Known Dim type,Known Dim Units,Known Dim Value
+Balsa,lb/ft3,8,,,Wood,1,1,1,0,0,1,0,0,1,1,1,1,0,0,,,,,,,,None,0,0
+Polycarbonate,lb/ft3,74.9,,,,1,1,1,1,0,1,0,0,1,1,1,1,1,1,,,,,,,,None,0,0
+Spiral/Glassine,lb/ft3,53,,,,1,1,1,1,0,1,0,0,1,1,1,1,1,1,,,,,,,,None,0,0
+Fiber,lb/ft3,41,,,,1,0,0,0,0,0,0,0,0,1,1,0,0,0,,,,,,,,None,0,0
+lite ply,lb/ft3,22,,,Composite,1,0,1,0,0,0,0,0,0,1,1,1,0,0,,,,,,,,None,0,0
+Paper,lb/ft3,70,,,,1,1,1,1,0,1,0,1,1,1,1,1,1,1,,,,,,,,None,0,0
+Polyethylene LDPE,lb/ft3,57.7,,,,1,0,0,0,0,0,1,1,0,0,0,0,0,0,,,,,,,,None,0,0
+Rip stop nylon,g/cm2,0.006685,,,,1,0,0,0,0,0,1,1,0,0,0,0,0,0,,,,,,,,None,0,0
+30 Lb. kevlar,g/cm,0.00178,,,,1,0,0,0,1,0,0,0,0,0,0,0,0,0,,,,,,,,None,0,0
+1/16 In. braided nylon,g/cm,0.0102,,,,1,0,0,0,1,0,0,0,0,0,0,0,0,0,,,,,,,,None,0,0
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/NCDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/NCDATA.CSV
new file mode 100644 (file)
index 0000000..75bc5ab
--- /dev/null
@@ -0,0 +1,276 @@
+Mfg.,Part No.,Desc.,Units,Length,Outer Dia,L/D Ratio,Insert Length,Insert OD,Thickness,Shape,Config,Material,CG Loc,Mass Units,Mass,Base Ext. Len\r
+SEMROC Astronautics,BC-08542,Ogive,in,4.200,0.940,0,0.500,0.850,0,ogive,0,Balsa,3.337,oz,0.150,0\r
+SEMROC Astronautics,BC-1016,Ogive,in,1.600,1.040,0,0.500,1.000,0,ogive,0,Balsa,1.491,oz,0.120,0\r
+SEMROC Astronautics,BC-1019,Ogive,in,1.900,1.040,0,0.500,1.000,0,ogive,0,Balsa,1.704,oz,0.130,0\r
+SEMROC Astronautics,BC-1020E,Elliptical,in,2.000,1.040,0,0.500,1.000,0,elliptical,0,Balsa,1.775,oz,0.130,0\r
+SEMROC Astronautics,BC-1022,Bezier,in,2.200,1.040,0,0.500,1.000,0,elliptical,0,Balsa,1.917,oz,0.150,0\r
+SEMROC Astronautics,BC-1024,Ogive,in,2.400,1.040,0,0.500,1.000,0,ogive,0,Balsa,2.059,oz,0.150,0\r
+SEMROC Astronautics,BC-1031,Bezier,in,3.100,1.040,0,0.500,1.000,0,elliptical,0,Balsa,2.556,oz,0.150,0\r
+SEMROC Astronautics,BC-1032,Ogive,in,3.200,1.040,0,0.500,1.000,0,ogive,0,Balsa,2.627,oz,0.150,0\r
+SEMROC Astronautics,BC-1037,Ogive,in,3.700,1.040,0,0.500,1.000,0,ogive,0,Balsa,2.982,oz,0.160,0\r
+SEMROC Astronautics,BC-1039,Ogive,in,3.900,1.040,0,0.500,1.000,0,ogive,0,Balsa,3.124,oz,0.170,0\r
+SEMROC Astronautics,BC-1041,Conical,in,4.100,1.040,0,0.500,1.000,0,cone,0,Balsa,3.266,oz,0.180,0\r
+SEMROC Astronautics,BC-1041G,Bezier,in,4.100,1.040,0,0.500,1.000,0,elliptical,0,Balsa,3.266,oz,0.180,0\r
+SEMROC Astronautics,BC-1041P,Bezier,in,4.100,1.040,0,0.500,1.000,0,elliptical,0,Balsa,3.266,oz,0.180,0\r
+SEMROC Astronautics,BC-1045,Ogive,in,4.500,1.040,0,0.500,1.000,0,ogive,0,Balsa,3.550,oz,0.190,0\r
+SEMROC Astronautics,BC-1045P,Rounded Ogive,in,4.500,1.040,0,0.500,1.000,0,ogive,0,Balsa,3.550,oz,0.190,0\r
+SEMROC Astronautics,BC-1048,Rounded Ogive,in,4.800,1.040,0,0.500,1.000,0,ogive,0,Balsa,3.763,oz,0.190,0\r
+SEMROC Astronautics,BC-1050,Bezier,in,5.000,1.040,0,0.500,1.000,0,elliptical,0,Balsa,3.905,oz,0.200,0\r
+SEMROC Astronautics,BC-1051,Conical,in,5.100,1.040,0,0.500,1.000,0,cone,0,Balsa,3.976,oz,0.200,0\r
+SEMROC Astronautics,BC-1052,Ogive,in,5.200,1.040,0,0.500,1.000,0,ogive,0,Balsa,4.047,oz,0.220,0\r
+SEMROC Astronautics,BC-1135,Rounded Ogive,in,3.500,1.170,0,0.500,1.130,0,ogive,0,Balsa,2.840,oz,0.150,0\r
+SEMROC Astronautics,BC-11518,Elliptical,in,3.500,1.220,0,0.800,1.140,0,elliptical,0,Balsa,3.053,oz,0.130,0\r
+SEMROC Astronautics,BC-11524,Bezier,in,2.400,1.220,0,0.800,1.140,0,elliptical,0,Balsa,2.272,oz,0.150,0\r
+SEMROC Astronautics,BC-11535,Bezier,in,3.500,1.220,0,0.800,1.140,0,elliptical,0,Balsa,3.053,oz,0.200,0\r
+SEMROC Astronautics,BC-11544,Ogive,in,4.400,1.220,0,0.800,1.140,0,ogive,0,Balsa,3.692,oz,0.220,0\r
+SEMROC Astronautics,BC-11546,Ogive,in,4.600,1.220,0,0.800,1.140,0,ogive,0,Balsa,3.834,oz,0.230,0\r
+SEMROC Astronautics,BC-11549,Ogive,in,4.900,1.220,0,0.800,1.140,0,ogive,0,Balsa,4.047,oz,0.250,0\r
+SEMROC Astronautics,BC-11554,Ogive,in,5.400,1.220,0,0.800,1.140,0,ogive,0,Balsa,4.402,oz,0.270,0\r
+SEMROC Astronautics,BC-11560,Ogive,in,6.000,1.220,0,0.800,1.140,0,ogive,0,Balsa,4.828,oz,0.280,0\r
+SEMROC Astronautics,BC-12525,Ogive,in,2.500,1.340,0,0.800,1.250,0,ogive,0,Balsa,2.343,oz,0.150,0\r
+SEMROC Astronautics,BC-12536,Bezier,in,3.600,1.340,0,0.800,1.140,0,elliptical,0,Balsa,3.124,oz,0.210,0\r
+SEMROC Astronautics,BC-12545,Elliptical,in,4.500,1.340,0,0.800,1.140,0,elliptical,0,Balsa,3.763,oz,0.240,0\r
+SEMROC Astronautics,BC-12548,Ogive,in,4.800,1.340,0,0.800,1.140,0,ogive,0,Balsa,3.976,oz,0.250,0\r
+SEMROC Astronautics,BC-12555,Ogive,in,5.500,1.340,0,0.800,1.140,0,ogive,0,Balsa,4.473,oz,0.340,0\r
+SEMROC Astronautics,BC-12561,Ogive,in,6.100,1.340,0,0.800,1.140,0,ogive,0,Balsa,4.899,oz,0.370,0\r
+SEMROC Astronautics,BC-1319,Elliptical,in,1.900,1.340,0,0.500,1.300,0,elliptical,0,Balsa,1.704,oz,0.180,0\r
+SEMROC Astronautics,BC-1321,Bezier,in,2.100,1.340,0,0.500,1.300,0,ogive,0,Balsa,1.846,oz,0.190,0\r
+SEMROC Astronautics,BC-1327,Bezier,in,2.700,1.340,0,0.500,1.300,0,ogive,0,Balsa,2.272,oz,0.210,0\r
+SEMROC Astronautics,BC-1329,Rounded-Ogive,in,2.900,1.340,0,0.500,1.300,0,ogive,0,Balsa,2.414,oz,0.240,0\r
+SEMROC Astronautics,BC-1330,Ogive,in,3.000,1.340,0,0.500,1.300,0,ogive,0,Balsa,2.485,oz,0.250,0\r
+SEMROC Astronautics,BC-1331,Elliptical,in,3.100,1.340,0,0.500,1.300,0,elliptical,0,Balsa,2.556,oz,0.270,0\r
+SEMROC Astronautics,BC-1336,Ogive,in,3.600,1.340,0,0.500,1.300,0,ogive,0,Balsa,2.911,oz,0.280,0\r
+SEMROC Astronautics,BC-1339,Rounded-Ogive,in,3.900,1.340,0,0.500,1.300,0,ogive,0,Balsa,3.124,oz,0.300,0\r
+SEMROC Astronautics,BC-1344,Ogive,in,4.400,1.340,0,0.500,1.300,0,ogive,0,Balsa,3.479,oz,0.320,0\r
+SEMROC Astronautics,BC-1345,Elliptical,in,4.400,1.340,0,0.500,1.300,0,elliptical,0,Balsa,3.479,oz,0.320,0\r
+SEMROC Astronautics,BC-1353,Secant Ogive,in,5.370,1.340,0,0.500,1.300,0,ogive,0,Balsa,4.168,oz,0.490,0\r
+SEMROC Astronautics,BC-1353F,Ogive,in,5.300,1.340,0,0.500,1.300,0,ogive,0,Balsa,4.118,oz,0.470,0\r
+SEMROC Astronautics,BC-1354,Ogive,in,5.400,1.340,0,0.500,1.300,0,ogive,0,Balsa,4.189,oz,0.550,0\r
+SEMROC Astronautics,BC-1354C,Parabolic,in,5.400,1.340,0,0.500,1.300,0,parabolic,0,Balsa,4.189,oz,0.580,0\r
+SEMROC Astronautics,BC-1364,Rounded-Ogive,in,6.400,1.340,0,0.500,1.300,0,ogive,0,Balsa,4.899,oz,0.620,0\r
+SEMROC Astronautics,BC-15044,Conical,in,4.400,1.590,0,0.800,1.500,0,cone,0,Balsa,3.692,oz,0.250,0\r
+SEMROC Astronautics,BC-15066,Ogive,in,6.600,1.590,0,0.800,1.500,0,ogive,0,Balsa,5.254,oz,0.350,0\r
+SEMROC Astronautics,BC-15070,Ogive,in,7.000,1.590,0,0.800,1.500,0,ogive,0,Balsa,5.538,oz,0.390,0\r
+SEMROC Astronautics,BC-15080,Ogive,in,8.000,1.590,0,0.800,1.500,0,ogive,0,Balsa,6.248,oz,0.450,0\r
+SEMROC Astronautics,BC-15081,Rounded Ogive,in,8.100,1.590,0,0.800,1.500,0,elliptical,0,Balsa,6.319,oz,0.430,0\r
+SEMROC Astronautics,BC-16100,Conical,in,10.000,1.640,0,0.500,1.600,0,cone,0,Balsa,7.455,oz,0.456,0\r
+SEMROC Astronautics,BC-1625,Elliptical,in,2.500,1.640,0,0.500,1.600,0,elliptical,0,Balsa,2.130,oz,0.200,0\r
+SEMROC Astronautics,BC-1625P,Bezier,in,2.500,1.640,0,0.500,1.600,0,ogive,0,Balsa,2.130,oz,0.200,0\r
+SEMROC Astronautics,BC-1631,Ogive,in,3.100,1.640,0,0.500,1.600,0,ogive,0,Balsa,2.556,oz,0.300,0\r
+SEMROC Astronautics,BC-1634,Rounded-Ogive,in,3.400,1.640,0,0.500,1.600,0,elliptical,0,Balsa,2.769,oz,0.310,0\r
+SEMROC Astronautics,BC-1636,Bezier,in,3.600,1.640,0,0.500,1.600,0,ogive,0,Balsa,2.911,oz,0.350,0\r
+SEMROC Astronautics,BC-1646,Ogive,in,4.600,1.640,0,0.500,1.600,0,ogive,0,Balsa,3.621,oz,0.390,0\r
+SEMROC Astronautics,BC-1647,Ogive,in,4.700,1.640,0,0.500,1.600,0,ogive,0,Balsa,3.692,oz,0.400,0\r
+SEMROC Astronautics,BC-1648,Ogive,in,4.800,1.640,0,0.500,1.600,0,ogive,0,Balsa,3.763,oz,0.410,0\r
+SEMROC Astronautics,BC-1650,Parabolic,in,5.000,1.640,0,0.500,1.600,0,parabolic,0,Balsa,3.905,oz,0.430,0\r
+SEMROC Astronautics,BC-1655,Ogive,in,5.500,1.640,0,0.500,1.600,0,ogive,0,Balsa,4.260,oz,0.460,0\r
+SEMROC Astronautics,BC-1660,Ogive,in,6.000,1.640,0,0.500,1.600,0,ogive,0,Balsa,4.615,oz,0.480,0\r
+SEMROC Astronautics,BC-1667,Parabolic,in,6.700,1.640,0,0.500,1.600,0,parabolic,0,Balsa,5.112,oz,0.510,0\r
+SEMROC Astronautics,BC-1672,Conical-Ogive,in,7.200,1.640,0,0.500,1.600,0,ogive,0,Balsa,5.467,oz,0.580,0\r
+SEMROC Astronautics,BC-1674,Ogive,in,7.400,1.640,0,0.500,1.600,0,ogive,0,Balsa,5.609,oz,0.620,0\r
+SEMROC Astronautics,BC-17535,Ogive,in,3.500,1.840,0,0.800,1.750,0,ogive,0,Balsa,3.053,oz,0.480,0\r
+SEMROC Astronautics,BC-17541,Ogive,in,4.100,1.840,0,0.800,1.750,0,ogive,0,Balsa,3.479,oz,0.530,0\r
+SEMROC Astronautics,BC-17560,Ogive,in,6.000,1.840,0,0.800,1.750,0,ogive,0,Balsa,4.828,oz,0.690,0\r
+SEMROC Astronautics,BC-17561,Elliptical,in,6.100,1.840,0,0.800,1.750,0,elliptical,0,Balsa,4.899,oz,0.720,0\r
+SEMROC Astronautics,BC-17567,Bezier,in,6.700,1.840,0,0.800,1.750,0,elliptical,0,Balsa,5.325,oz,0.760,0\r
+SEMROC Astronautics,BC-17585,Ogive,in,8.500,1.840,0,0.800,1.750,0,ogive,0,Balsa,6.603,oz,0.920,0\r
+SEMROC Astronautics,BC-17590,Conical,in,9.000,1.840,0,0.800,1.750,0,cone,0,Balsa,6.958,oz,1.130,0\r
+SEMROC Astronautics,BC-17592,Ogive,in,9.200,1.840,0,0.800,1.750,0,ogive,0,Balsa,7.100,oz,1.890,0\r
+SEMROC Astronautics,BC-1828,Elliptical,in,2.800,1.840,0,0.700,1.800,0,elliptical,0,Balsa,2.485,oz,0.700,0\r
+SEMROC Astronautics,BC-1835,Elliptical,in,3.500,1.840,0,0.700,1.800,0,elliptical,0,Balsa,2.982,oz,1.000,0\r
+SEMROC Astronautics,BC-1837,Bezier,in,3.700,1.840,0,0.700,1.800,0,elliptical,0,Balsa,3.124,oz,1.000,0\r
+SEMROC Astronautics,BC-1842,Elliptical,in,4.200,1.840,0,0.700,1.800,0,elliptical,0,Balsa,3.479,oz,1.000,0\r
+SEMROC Astronautics,BC-1853,Ogive,in,5.300,1.840,0,0.700,1.800,0,ogive,0,Balsa,4.260,oz,0.650,0\r
+SEMROC Astronautics,BC-1856,Ogive,in,5.600,1.840,0,0.700,1.800,0,ogive,0,Balsa,4.473,oz,1.100,0\r
+SEMROC Astronautics,BC-1861,Elliptical,in,6.100,1.840,0,0.700,1.800,0,elliptical,0,Balsa,4.828,oz,1.200,0\r
+SEMROC Astronautics,BC-1869,Ogive,in,6.900,1.840,0,0.700,1.800,0,ogive,0,Balsa,5.396,oz,1.200,0\r
+SEMROC Astronautics,BC-1869C,Conical,in,6.900,1.840,0,0.700,1.800,0,cone,0,Balsa,5.396,oz,1.200,0\r
+SEMROC Astronautics,BC-20045,Elliptical,in,4.500,2.040,0,0.800,2.000,0,elliptical,0,Balsa,3.763,oz,0.630,0\r
+SEMROC Astronautics,BC-20107,Conical,in,10.700,2.040,0,0.700,2.000,0,cone,0,Balsa,8.094,oz,1.780,0\r
+SEMROC Astronautics,BC-2025,Elliptical,in,2.500,2.040,0,0.700,2.000,0,elliptical,0,Balsa,2.272,oz,0.420,0\r
+SEMROC Astronautics,BC-2026,Bezier,in,2.600,2.040,0,0.700,2.000,0,elliptical,0,Balsa,2.343,oz,0.430,0\r
+SEMROC Astronautics,BC-2033,Elliptical,in,3.300,2.040,0,0.700,2.000,0,elliptical,0,Balsa,2.840,oz,0.610,0\r
+SEMROC Astronautics,BC-2039,Bezier,in,3.900,2.040,0,0.700,2.000,0,elliptical,0,Balsa,3.266,oz,0.690,0\r
+SEMROC Astronautics,BC-2045,Ogive,in,4.500,2.040,0,0.700,2.000,0,ogive,0,Balsa,3.692,oz,1.540,0\r
+SEMROC Astronautics,BC-2050,Conical,in,5.000,2.040,0,0.700,2.000,0,cone,0,Balsa,4.047,oz,1.360,0\r
+SEMROC Astronautics,BC-2057,Ogive,in,5.700,2.040,0,0.700,2.000,0,ogive,0,Balsa,4.544,oz,1.680,0\r
+SEMROC Astronautics,BC-2065,Ogive,in,6.500,2.040,0,0.700,2.000,0,ogive,0,Balsa,5.112,oz,1.770,0\r
+SEMROC Astronautics,BC-2080,Elliptical,in,8.000,2.040,0,0.700,2.000,0,elliptical,0,Balsa,6.177,oz,1.970,0\r
+SEMROC Astronautics,BC-225103,Fat Ogive,in,10.300,2.340,0,0.800,2.250,0,ogive,0,Balsa,7.881,oz,2.900,0\r
+SEMROC Astronautics,BC-22530,Bezier,in,3.000,2.340,0,0.800,2.250,0,elliptical,0,Balsa,2.698,oz,0.900,0\r
+SEMROC Astronautics,BC-22545,Elliptical,in,4.500,2.340,0,0.800,2.250,0,elliptical,0,Balsa,3.763,oz,1.050,0\r
+SEMROC Astronautics,BC-22563,Bezier,in,6.300,2.340,0,0.800,2.250,0,elliptical,0,Balsa,5.041,oz,1.480,0\r
+SEMROC Astronautics,BC-22567,Bezier,in,6.700,2.340,0,0.800,2.250,0,elliptical,0,Balsa,5.325,oz,1.550,0\r
+SEMROC Astronautics,BC-22567E,Ogive,in,6.700,2.340,0,0.800,2.250,0,ogive,0,Balsa,5.325,oz,1.510,0\r
+SEMROC Astronautics,BC-22569,Ogive,in,6.900,2.340,0,0.800,2.250,0,ogive,0,Balsa,5.467,oz,1.670,0\r
+SEMROC Astronautics,BC-22578,Elliptical,in,7.800,2.340,0,0.800,2.250,0,elliptical,0,Balsa,6.106,oz,1.800,0\r
+SEMROC Astronautics,BC-22579,Ogive,in,7.900,2.340,0,0.800,2.250,0,ogive,0,Balsa,6.177,oz,1.700,0\r
+SEMROC Astronautics,BC-22588,Elliptical,in,8.800,2.340,0,0.800,2.250,0,elliptical,0,Balsa,6.816,oz,2.200,0\r
+SEMROC Astronautics,BC-22595,Secant-Ogive,in,9.500,2.340,0,0.800,2.250,0,Sears-haack,0,Balsa,7.313,oz,2.500,0\r
+SEMROC Astronautics,BC-22597,Ogive,in,9.700,2.340,0,0.800,2.250,0,ogive,0,Balsa,7.455,oz,2.600,0\r
+SEMROC Astronautics,BC-27540,Blunt Ogive,in,4.000,2.840,0,0.800,2.750,0,elliptical,0,Balsa,3.408,oz,1.230,0\r
+SEMROC Astronautics,BC-27554,Ogive,in,5.400,2.840,0,0.800,2.750,0,ogive,0,Balsa,4.402,oz,1.550,0\r
+SEMROC Astronautics,BC-27555,Bezier,in,5.500,2.840,0,0.800,2.750,0,elliptical,0,Balsa,4.473,oz,1.610,0\r
+SEMROC Astronautics,BC-505,Spherical,in,0.500,0.543,0,0.400,0.515,0,elliptical,0,Balsa,0.639,oz,0.020,0\r
+SEMROC Astronautics,BC-508,Elliptical,in,0.800,0.543,0,0.400,0.515,0,elliptical,0,Balsa,0.852,oz,0.020,0\r
+SEMROC Astronautics,BC-510,Conical,in,1.000,0.543,0,0.400,0.515,0,cone,0,Balsa,0.994,oz,0.200,0\r
+SEMROC Astronautics,BC-510P,Elliptical,in,1.000,0.543,0,0.400,0.515,0,elliptical,0,Balsa,0.994,oz,0.020,0\r
+SEMROC Astronautics,BC-512,Ogive,in,1.200,0.543,0,0.400,0.515,0,ogive,0,Balsa,1.136,oz,0.020,0\r
+SEMROC Astronautics,BC-514,Ogive,in,1.400,0.543,0,0.400,0.515,0,ogive,0,Balsa,1.278,oz,0.030,0\r
+SEMROC Astronautics,BC-515,Conical,in,1.500,0.543,0,0.400,0.515,0,cone,0,Balsa,1.349,oz,0.030,0\r
+SEMROC Astronautics,BC-515E,Ogive,in,1.500,0.543,0,0.400,0.515,0,ogive,0,Balsa,1.349,oz,0.030,0\r
+SEMROC Astronautics,BC-516,Conical,in,1.600,0.543,0,0.400,0.515,0,cone,0,Balsa,1.420,oz,0.030,0\r
+SEMROC Astronautics,BC-517,Ogive,in,1.700,0.543,0,0.400,0.515,0,ogive,0,Balsa,1.491,oz,0.030,0\r
+SEMROC Astronautics,BC-518,Ogive,in,1.800,0.543,0,0.400,0.515,0,ogive,0,Balsa,1.562,oz,0.030,0\r
+SEMROC Astronautics,BC-522,Elliptical,in,2.200,0.543,0,0.400,0.515,0,elliptical,0,Balsa,1.846,oz,0.040,0\r
+SEMROC Astronautics,BC-522P,Ogive,in,2.200,0.543,0,0.400,0.515,0,ogive,0,Balsa,1.846,oz,0.040,0\r
+SEMROC Astronautics,BC-523,Taper-Conical,in,2.300,0.543,0,0.400,0.515,0,Power-series,0,Balsa,1.917,oz,0.060,0\r
+SEMROC Astronautics,BC-524,Ogive,in,2.400,0.543,0,0.400,0.515,0,ogive,0,Balsa,1.988,oz,0.040,0\r
+SEMROC Astronautics,BC-526,Conical,in,2.600,0.543,0,0.400,0.515,0,cone,0,Balsa,2.130,oz,0.030,0\r
+SEMROC Astronautics,BC-528,Conical,in,2.800,0.543,0,0.400,0.515,0,cone,0,Balsa,2.272,oz,0.030,0\r
+SEMROC Astronautics,BC-529,Ogive,in,2.900,0.543,0,0.400,0.515,0,ogive,0,Balsa,2.343,oz,0.040,0\r
+SEMROC Astronautics,BC-708,Conical,in,0.800,0.759,0,0.500,0.715,0,cone,0,Balsa,0.923,oz,0.200,0\r
+SEMROC Astronautics,BC-710,Conical,in,1.000,0.759,0,0.500,0.715,0,cone,0,Balsa,1.065,oz,0.030,0\r
+SEMROC Astronautics,BC-711,Conical,in,1.100,0.759,0,0.500,0.715,0,cone,0,Balsa,1.136,oz,0.030,0\r
+SEMROC Astronautics,BC-714,Ogive,in,1.400,0.759,0,0.500,0.715,0,ogive,0,Balsa,1.349,oz,0.040,0\r
+SEMROC Astronautics,BC-715,Rounded Ogive,in,1.500,0.759,0,0.500,0.715,0,elliptical,0,Balsa,1.420,oz,0.040,0\r
+SEMROC Astronautics,BC-716,Elliptical,in,1.600,0.759,0,0.500,0.715,0,elliptical,0,Balsa,1.491,oz,0.040,0\r
+SEMROC Astronautics,BC-719,Ogive,in,1.900,0.759,0,0.500,0.715,0,ogive,0,Balsa,1.704,oz,0.040,0\r
+SEMROC Astronautics,BC-720,Bezier,in,2.000,0.759,0,0.500,0.715,0,elliptical,0,Balsa,1.775,oz,0.040,0\r
+SEMROC Astronautics,BC-721,Ogive,in,2.100,0.759,0,0.500,0.715,0,ogive,0,Balsa,1.846,oz,0.040,0\r
+SEMROC Astronautics,BC-722,Rounded Ogive,in,2.200,0.759,0,0.500,0.715,0,elliptical,0,Balsa,1.917,oz,0.040,0\r
+SEMROC Astronautics,BC-723,Ogive,in,2.300,0.759,0,0.500,0.715,0,ogive,0,Balsa,1.988,oz,0.040,0\r
+SEMROC Astronautics,BC-723P,Rounded Ogive,in,2.300,0.759,0,0.500,0.715,0,elliptical,0,Balsa,1.988,oz,0.050,0\r
+SEMROC Astronautics,BC-727,Ogive,in,2.700,0.759,0,0.500,0.715,0,ogive,0,Balsa,2.272,oz,0.050,0\r
+SEMROC Astronautics,BC-728,Conical,in,2.800,0.759,0,0.500,0.715,0,cone,0,Balsa,2.343,oz,0.050,0\r
+SEMROC Astronautics,BC-728F,Elliptical,in,2.800,0.759,0,0.500,0.715,0,elliptical,0,Balsa,2.343,oz,0.050,0\r
+SEMROC Astronautics,BC-730,Ogive,in,3.000,0.759,0,0.500,0.715,0,ogive,0,Balsa,2.485,oz,0.060,0\r
+SEMROC Astronautics,BC-730P,Rounded Ogive,in,3.000,0.759,0,0.500,0.715,0,elliptical,0,Balsa,2.485,oz,0.060,0\r
+SEMROC Astronautics,BC-731,Rounded Ogive,in,3.100,0.759,0,0.500,0.715,0,elliptical,0,Balsa,2.556,oz,0.060,0\r
+SEMROC Astronautics,BC-731F,Ogive,in,3.100,0.759,0,0.500,0.715,0,ogive,0,Balsa,2.556,oz,0.060,0\r
+SEMROC Astronautics,BC-733,Ogive,in,3.300,0.759,0,0.500,0.715,0,ogive,0,Balsa,2.698,oz,0.060,0\r
+SEMROC Astronautics,BC-734P,Pointed Ogive,in,3.400,0.759,0,0.500,0.715,0,ogive,0,Balsa,2.769,oz,0.060,0\r
+SEMROC Astronautics,BC-735,Ogive,in,3.500,0.759,0,0.500,0.715,0,ogive,0,Balsa,2.840,oz,0.060,0\r
+SEMROC Astronautics,BC-736,Conical,in,3.600,0.759,0,0.500,0.715,0,cone,0,Balsa,2.911,oz,0.060,0\r
+SEMROC Astronautics,BC-737,Ogive,in,3.700,0.759,0,0.500,0.715,0,ogive,0,Balsa,2.982,oz,0.060,0\r
+SEMROC Astronautics,BC-739,Conical,in,3.900,0.759,0,0.500,0.715,0,cone,0,Balsa,3.124,oz,0.060,0\r
+SEMROC Astronautics,BC-739O,Ogive,in,3.900,0.759,0,0.500,0.715,0,ogive,0,Balsa,3.124,oz,0.070,0\r
+SEMROC Astronautics,BC-744,Ogive,in,4.400,0.759,0,0.500,0.715,0,ogive,0,Balsa,3.479,oz,0.070,0\r
+SEMROC Astronautics,BC-812,Conical,in,1.200,0.908,0,0.500,0.865,0,cone,0,Balsa,1.207,oz,0.040,0\r
+SEMROC Astronautics,BC-813,Elliptical,in,1.300,0.908,0,0.500,0.865,0,elliptical,0,Balsa,1.278,oz,0.050,0\r
+SEMROC Astronautics,BC-814,Elliptical,in,1.400,0.908,0,0.500,0.865,0,elliptical,0,Balsa,1.349,oz,0.070,0\r
+SEMROC Astronautics,BC-815,Ogive,in,1.500,0.908,0,0.500,0.865,0,ogive,0,Balsa,1.420,oz,0.070,0\r
+SEMROC Astronautics,BC-817,Ogive,in,1.700,0.908,0,0.500,0.865,0,ogive,0,Balsa,1.562,oz,0.080,0\r
+SEMROC Astronautics,BC-818,Bezier,in,1.800,0.908,0,0.500,0.865,0,elliptical,0,Balsa,1.633,oz,0.080,0\r
+SEMROC Astronautics,BC-818L,Ogive,in,1.800,0.908,0,0.500,0.865,0,ogive,0,Balsa,1.633,oz,0.080,0\r
+SEMROC Astronautics,BC-819,Ogive,in,1.900,0.908,0,0.500,0.865,0,ogive,0,Balsa,1.704,oz,0.080,0\r
+SEMROC Astronautics,BC-820,Bezier,in,2.000,0.908,0,0.500,0.865,0,elliptical,0,Balsa,1.775,oz,0.080,0\r
+SEMROC Astronautics,BC-821,Elliptical,in,2.100,0.908,0,0.500,0.865,0,elliptical,0,Balsa,1.846,oz,0.090,0\r
+SEMROC Astronautics,BC-823,Ogive,in,2.300,0.908,0,0.500,0.865,0,ogive,0,Balsa,1.988,oz,0.100,0\r
+SEMROC Astronautics,BC-823E,Fat Ogive,in,2.300,0.908,0,0.500,0.865,0,elliptical,0,Balsa,1.988,oz,0.100,0\r
+SEMROC Astronautics,BC-826,Rounded Ogive,in,2.600,0.908,0,0.500,0.865,0,elliptical,0,Balsa,2.201,oz,0.110,0\r
+SEMROC Astronautics,BC-830,Ogive,in,3.000,0.908,0,0.500,0.865,0,ogive,0,Balsa,2.485,oz,0.120,0\r
+SEMROC Astronautics,BC-832,Bezier,in,3.200,0.908,0,0.500,0.865,0,elliptical,0,Balsa,2.627,oz,0.130,0\r
+SEMROC Astronautics,BC-832C,Conical,in,3.200,0.908,0,0.500,0.865,0,cone,0,Balsa,2.627,oz,0.110,0\r
+SEMROC Astronautics,BC-833,Elliptical,in,3.300,0.908,0,0.500,0.865,0,elliptical,0,Balsa,2.698,oz,0.130,0\r
+SEMROC Astronautics,BC-834C,Bezier,in,3.400,0.908,0,0.500,0.865,0,elliptical,0,Balsa,2.769,oz,0.120,0\r
+SEMROC Astronautics,BC-836,Secant-Ogive,in,3.600,0.908,0,0.500,0.865,0,Sears-Haack,0,Balsa,2.911,oz,0.130,0\r
+SEMROC Astronautics,BC-837,Ogive,in,3.700,0.908,0,0.500,0.865,0,ogive,0,Balsa,2.982,oz,0.130,0\r
+SEMROC Astronautics,BC-840,Elliptical,in,4.000,0.908,0,0.500,0.865,0,elliptical,0,Balsa,3.195,oz,0.150,0\r
+SEMROC Astronautics,BC-845,Ogive,in,4.500,0.908,0,0.500,0.865,0,ogive,0,Balsa,3.550,oz,0.160,0\r
+SEMROC Astronautics,BC-845P,Rounded Ogive,in,4.500,0.908,0,0.500,0.865,0,elliptical,0,Balsa,3.550,oz,0.170,0\r
+SEMROC Astronautics,BC-846,Rounded Ogive,in,4.600,0.908,0,0.500,0.865,0,elliptical,0,Balsa,3.621,oz,0.160,0\r
+SEMROC Astronautics,BC-847,Conical,in,4.700,0.908,0,0.500,0.865,0,cone,0,Balsa,3.692,oz,0.190,0\r
+SEMROC Astronautics,BC-847W,Ogive,in,4.700,0.908,0,0.500,0.865,0,ogive,0,Balsa,3.692,oz,0.190,0\r
+SEMROC Astronautics,BC-848,Ogive,in,4.800,0.908,0,0.500,0.865,0,ogive,0,Balsa,3.763,oz,0.200,0\r
+SEMROC Astronautics,BC-853,Ogive,in,5.300,0.908,0,0.500,0.865,0,ogive,0,Balsa,4.118,oz,0.270,0\r
+SEMROC Astronautics,BC-8F28,Ogive,in,2.750,0.921,0,0.500,0.865,0,ogive,0,Balsa,2.308,oz,0.120,0\r
+SEMROC Astronautics,BC-927,Ogive,in,2.700,0.998,0,0.600,0.950,0,ogive,0,Balsa,2.343,oz,0.130,0\r
+SEMROC Astronautics,BC-932,Elliptical,in,3.200,0.998,0,0.600,0.950,0,elliptical,0,Balsa,2.698,oz,0.150,0\r
+SEMROC Astronautics,BC-940,Bezier,in,4.000,0.998,0,0.600,0.950,0,elliptical,0,Balsa,3.266,oz,0.160,0\r
+SEMROC Astronautics,BC-944,Ogive,in,4.400,0.998,0,0.600,0.950,0,ogive,0,Balsa,3.550,oz,0.160,0\r
+SEMROC Astronautics,BNC-3A,Conical,in,0.750,0.375,0,0.250,0.349,0,cone,0,Balsa,0.710,oz,0.010,0\r
+SEMROC Astronautics,BNC-5AW,Elliptical,in,2.250,0.541,0,0.250,0.515,0,elliptical,0,Balsa,1.775,oz,0.210,0\r
+SEMROC Astronautics,BNC-5AX,Ogive,in,2.250,0.541,0,0.250,0.515,0,ogive,0,Balsa,1.775,oz,0.200,0\r
+SEMROC Astronautics,BNC-5E,Ogive,in,1.380,0.541,0,0.250,0.515,0,ogive,0,Balsa,1.157,oz,0.020,0\r
+SEMROC Astronautics,BNC-5S,Conical,in,1.500,0.541,0,0.250,0.515,0,cone,0,Balsa,1.243,oz,0.016,0\r
+SEMROC Astronautics,BNC-5V,Elliptical,in,0.750,0.541,0,0.250,0.515,0,elliptical,0,Balsa,0.710,oz,0.013,0\r
+SEMROC Astronautics,BNC-5W,Ogive,in,2.870,0.541,0,0.250,0.515,0,ogive,0,Balsa,2.215,oz,0.040,0\r
+SEMROC Astronautics,BNC-10A,Blunt Ogive,in,0.810,0.720,0,0.250,0.710,0,elliptical,0,Balsa,0.753,oz,0.030,0\r
+SEMROC Astronautics,BNC-10B,Elliptical,in,1.700,0.720,0,0.250,0.710,0,elliptical,0,Balsa,1.385,oz,0.050,0\r
+SEMROC Astronautics,BNC-20A,Blunt Ogive,in,0.810,0.736,0,0.375,0.710,0,elliptical,0,Balsa,0.841,oz,0.030,0\r
+SEMROC Astronautics,BNC-20AZ,Ogive,in,2.500,0.736,0,0.375,0.710,0,ogive,0,Balsa,2.041,oz,0.070,0\r
+SEMROC Astronautics,BNC-20B,Elliptical,in,1.700,0.736,0,0.375,0.710,0,elliptical,0,Balsa,1.473,oz,0.050,0\r
+SEMROC Astronautics,BNC-20CB,Ogive,in,1.750,0.736,0,0.375,0.710,0,ogive,0,Balsa,1.509,oz,0.050,0\r
+SEMROC Astronautics,BNC-20H,Elliptical,in,0.800,0.736,0,0.375,0.710,0,elliptical,0,Balsa,0.834,oz,0.030,0\r
+SEMROC Astronautics,BNC-20L,Ogive,in,1.400,0.736,0,0.375,0.710,0,ogive,0,Balsa,1.260,oz,0.040,0\r
+SEMROC Astronautics,BNC-20N,Ogive,in,2.750,0.736,0,0.375,0.710,0,ogive,0,Balsa,2.219,oz,0.080,0\r
+SEMROC Astronautics,BNC-20R,Conical,in,2.750,0.736,0,0.375,0.710,0,cone,0,Balsa,2.219,oz,0.070,0\r
+SEMROC Astronautics,BNC-20SP,Elliptical,in,0.250,0.736,0,0.375,0.710,0,elliptical,0,Balsa,0.444,oz,0.010,0\r
+SEMROC Astronautics,BNC-20Y,Conical,in,1.000,0.736,0,0.375,0.710,0,cone,0,Balsa,0.976,oz,0.020,0\r
+SEMROC Astronautics,BNC-30C,Blunt Ogive,in,0.750,0.765,0,0.375,0.725,0,elliptical,0,Balsa,0.799,oz,0.040,0\r
+SEMROC Astronautics,BNC-30D,Ogive,in,1.500,0.765,0,0.375,0.725,0,ogive,0,Balsa,1.331,oz,0.060,0\r
+SEMROC Astronautics,BNC-30DE,Ogive,in,1.380,0.765,0,0.375,0.725,0,ogive,0,Balsa,1.246,oz,0.060,0\r
+SEMROC Astronautics,BNC-30E,Ogive,in,2.300,0.765,0,0.375,0.725,0,ogive,0,Balsa,1.899,oz,0.070,0\r
+SEMROC Astronautics,BNC-40D,Ogive,in,1.500,0.825,0,0.400,0.765,0,ogive,0,Balsa,1.349,oz,0.040,0\r
+SEMROC Astronautics,BNC-40F,Conical,in,1.900,0.825,0,0.400,0.765,0,cone,0,Balsa,1.633,oz,0.070,0\r
+SEMROC Astronautics,BNC-40G,Ogive,in,4.500,0.825,0,0.400,0.765,0,ogive,0,Balsa,3.479,oz,0.160,0\r
+SEMROC Astronautics,BNC-50C,Conical,in,1.270,0.976,0,0.500,0.950,0,cone,0,Balsa,1.257,oz,0.060,0\r
+SEMROC Astronautics,BNC-50G,Ogive,in,5.700,0.976,0,0.500,0.950,0,ogive,0,Balsa,4.402,oz,0.230,0\r
+SEMROC Astronautics,BNC-50J,Blunt Ogive,in,1.375,0.976,0,0.500,0.950,0,elliptical,0,Balsa,1.331,oz,0.080,0\r
+SEMROC Astronautics,BNC-50K,Fat Ogive,in,2.750,0.976,0,0.500,0.950,0,ogive,0,Balsa,2.308,oz,0.130,0\r
+SEMROC Astronautics,BNC-50KP,Parabolic,in,2.750,0.976,0,0.500,0.950,0,elliptical,0,Balsa,2.308,oz,0.130,0\r
+SEMROC Astronautics,BNC-50V,Conical,in,5.750,0.976,0,0.500,0.950,0,cone,0,Balsa,4.438,oz,0.190,0\r
+SEMROC Astronautics,BNC-50X,Elliptical,in,3.250,0.976,0,0.500,0.950,0,elliptical,0,Balsa,2.663,oz,0.150,0\r
+SEMROC Astronautics,BNC-50Y,Ogive,in,4.375,0.976,0,0.500,0.950,0,ogive,0,Balsa,3.461,oz,0.160,0\r
+SEMROC Astronautics,BNC-50YP,Ogive,in,4.280,0.976,0,0.500,0.950,0,ogive,0,Balsa,3.394,oz,0.160,0\r
+SEMROC Astronautics,BNC-55AA,Ogive,in,3.125,1.325,0,0.600,1.283,0,ogive,0,Balsa,2.645,oz,0.150,0\r
+SEMROC Astronautics,BNC-55AC,Secant-Ogive,in,5.375,1.325,0,0.600,1.283,0,Sears-haack,0,Balsa,4.242,oz,0.320,0\r
+SEMROC Astronautics,BNC-55ACP,Secant-Ogive,in,5.750,1.325,0,0.600,1.283,0,Sears-haack,0,Balsa,4.509,oz,0.330,0\r
+SEMROC Astronautics,BNC-55AO,Elliptical,in,5.000,1.325,0,0.600,1.283,0,elliptical,0,Balsa,3.976,oz,0.430,0\r
+SEMROC Astronautics,BNC55B,Elliptical,in,3.000,1.325,0,0.600,1.283,0,elliptical,0,Balsa,2.556,oz,0.270,0\r
+SEMROC Astronautics,BNC-55CT,Rounded Ogive,in,2.900,1.325,0,0.600,1.283,0,elliptical,0,Balsa,2.485,oz,0.240,0\r
+SEMROC Astronautics,BNC-55EX,Fat Ogive,in,3.400,1.325,0,0.600,1.283,0,ogive,0,Balsa,2.840,oz,0.290,0\r
+SEMROC Astronautics,BNC-55F,Ogive,in,4.200,1.325,0,0.600,1.283,0,ogive,0,Balsa,3.408,oz,0.360,0\r
+SEMROC Astronautics,BNC-55FD,Base-Drilled Ogive,in,4.200,1.325,0,0.600,1.283,0,ogive,0,Balsa,3.408,oz,0.210,0\r
+SEMROC Astronautics,BNC-55PT,Conical,in,6.150,1.325,0,0.600,1.283,0,cone,0,Balsa,4.793,oz,0.560,0\r
+SEMROC Astronautics,BNC-55X,Elliptical,in,4.100,1.325,0,0.600,1.283,0,elliptical,0,Balsa,3.337,oz,0.370,0\r
+SEMROC Astronautics,BNC-55Z,Ogive,in,3.000,1.325,0,0.600,1.283,0,ogive,0,Balsa,2.556,oz,0.250,0\r
+SEMROC Astronautics,BNC-60AH,Elliptical,in,6.625,1.637,0,0.800,1.595,0,elliptical,0,Balsa,5.272,oz,0.800,0\r
+SEMROC Astronautics,BNC-60L,Elliptical,in,3.125,1.637,0,0.800,1.595,0,elliptical,0,Balsa,2.787,oz,0.340,0\r
+SEMROC Astronautics,BNC-60LP,Elliptical,in,2.750,1.637,0,0.800,1.595,0,elliptical,0,Balsa,2.521,oz,0.240,0\r
+SEMROC Astronautics,BNC-60MS,Elliptical,in,2.600,1.637,0,0.800,1.595,0,elliptical,0,Balsa,2.414,oz,0.210,0\r
+SEMROC Astronautics,BNC-60NA,Rounded Ogive,in,4.800,1.637,0,0.800,1.595,0,elliptical,0,Balsa,3.976,oz,0.370,0\r
+SEMROC Astronautics,BNC-60NS,Conical,in,10.000,1.637,0,0.800,1.595,0,cone,0,Balsa,7.668,oz,0.456,0\r
+SEMROC Astronautics,BNC-60RL,Ogive,in,8.375,1.637,0,0.800,1.595,0,ogive,0,Balsa,6.514,oz,0.810,0\r
+SEMROC Astronautics,BNC-60X,Elliptical,in,5.460,1.637,0,0.800,1.595,0,elliptical,0,Balsa,4.445,oz,0.620,0\r
+SEMROC Astronautics,BNC-60Y,Ogive,in,7.250,1.637,0,0.800,1.595,0,ogive,0,Balsa,5.716,oz,0.730,0\r
+SEMROC Astronautics,BNC-65AF,Elliptical,in,4.000,1.796,0,0.800,1.750,0,elliptical,0,Balsa,3.408,oz,0.520,0\r
+SEMROC Astronautics,BNC-65L,Elliptical,in,3.250,1.796,0,0.800,1.750,0,elliptical,0,Balsa,2.876,oz,0.410,0\r
+SEMROC Astronautics,BNC-70AJ,Elliptical,in,4.250,2.217,0,0.800,2.175,0,elliptical,0,Balsa,3.586,oz,0.850,0\r
+SEMROC Astronautics,BNC-70CT,Bezier,in,4.500,2.217,0,0.800,2.175,0,elliptical,0,Balsa,3.763,oz,0.900,0\r
+SEMROC Astronautics,BNC-70D,Ogive,in,4.250,2.217,0,0.800,2.175,0,ogive,0,Balsa,3.586,oz,0.900,0\r
+SEMROC Astronautics,BNC-70MS,Elliptical,in,3.540,2.217,0,0.800,2.175,0,elliptical,0,Balsa,3.081,oz,1.000,0\r
+SEMROC Astronautics,BNC-70NH,Elliptical,in,9.750,2.217,0,0.800,2.175,0,elliptical,0,Balsa,7.491,oz,1.480,0\r
+SEMROC Astronautics,BNC-70HAC,Secant-Ogive,in,9.160,2.247,0,0.800,2.175,0,Sears-haack,0,Balsa,7.072,oz,2.000,0\r
+SEMROC Astronautics,BNC-70HAJ,Elliptical,in,4.250,2.247,0,0.800,2.175,0,elliptical,0,Balsa,3.586,oz,0.850,0\r
+SEMROC Astronautics,BNC-70HB,Ogive,in,7.000,2.247,0,0.800,2.175,0,ogive,0,Balsa,5.538,oz,1.130,0\r
+SEMROC Astronautics,BNC-70HCT,Bezier,in,4.500,2.247,0,0.800,2.175,0,elliptical,0,Balsa,3.763,oz,0.900,0\r
+SEMROC Astronautics,BNC-70HD,Ogive,in,4.330,2.247,0,0.800,2.175,0,ogive,0,Balsa,3.642,oz,0.880,0\r
+SEMROC Astronautics,BNC-80AH,Ogive,in,10.500,2.600,0,1.000,2.558,0,ogive,0,Balsa,8.165,oz,2.810,0\r
+SEMROC Astronautics,BNC-80AO,Ogive,in,9.900,2.600,0,1.000,2.558,0,ogive,0,Balsa,7.739,oz,1.340,0\r
+SEMROC Astronautics,BNC-80BB,Elliptical,in,4.000,2.600,0,1.000,2.558,0,elliptical,0,Balsa,3.550,oz,1.100,0\r
+SEMROC Astronautics,BNC-80D,Ogive,in,5.000,2.600,0,1.000,2.558,0,ogive,0,Balsa,4.260,oz,0.980,0\r
+SEMROC Astronautics,BNC-80K,Ogive,in,8.200,2.600,0,1.000,2.558,0,ogive,0,Balsa,6.532,oz,1.230,0\r
+SEMROC Astronautics,BNC-80KA,Ogive,in,7.330,2.600,0,1.000,2.558,0,ogive,0,Balsa,5.914,oz,1.130,0\r
+SEMROC Astronautics,BNC-80KP,Rounded Ogive,in,6.930,2.600,0,1.000,2.558,0,elliptical,0,Balsa,5.630,oz,1.120,0\r
+SEMROC Astronautics,BNC-80L,Elliptical,in,5.000,2.600,0,1.000,2.558,0,elliptical,0,Balsa,4.260,oz,1.300,0\r
+SEMROC Astronautics,BNC-80VE,Ogive,in,4.900,2.600,0,1.000,2.558,0,ogive,0,Balsa,4.189,oz,1.300,0\r
+SEMROC Astronautics,BNC-80HAH,Ogive,in,10.500,2.640,0,1.000,2.558,0,ogive,0,Balsa,8.165,oz,2.810,0\r
+SEMROC Astronautics,BNC-80HAO,Ogive,in,9.900,2.640,0,1.000,2.558,0,ogive,0,Balsa,7.739,oz,1.340,0\r
+SEMROC Astronautics,BNC-80HBB,Elliptical,in,4.000,2.640,0,1.000,2.558,0,elliptical,0,Balsa,3.550,oz,1.100,0\r
+SEMROC Astronautics,BNC-80HD,Ogive,in,5.000,2.640,0,1.000,2.558,0,ogive,0,Balsa,4.260,oz,0.980,0\r
+SEMROC Astronautics,BNC-80HK,Ogive,in,8.200,2.640,0,1.000,2.558,0,ogive,0,Balsa,6.532,oz,1.230,0\r
+SEMROC Astronautics,BNC-80HKA,Ogive,in,7.330,2.640,0,1.000,2.558,0,ogive,0,Balsa,5.914,oz,1.130,0\r
+SEMROC Astronautics,BNC-80HKP,Rounded Ogive,in,6.930,2.640,0,1.000,2.558,0,elliptical,0,Balsa,5.630,oz,1.120,0\r
+SEMROC Astronautics,BNC-80HL,Ogive,in,5.000,2.640,0,1.000,2.558,0,ogive,0,Balsa,4.260,oz,1.300,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/PCDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/PCDATA.CSV
new file mode 100644 (file)
index 0000000..5e6ccf1
--- /dev/null
@@ -0,0 +1,11 @@
+Mfg.,Part No.,Desc.,Units,n sides,OD,ID,Shroud Count,Shroud Len,Shroud Material,Chute Thickness,Chute Material,Mass Units,Mass,CG,Cd\r
+SEMROC Astronautics,CP-12,12 in. Plastic Chute,in,6,12,0,6,12,30 Lb. kevlar,0.001,Polyethylene LDPE,0,0,0,0.75\r
+SEMROC Astronautics,CP-16,16 in. Plastic Chute,in,8,16,0,8,16,30 Lb. kevlar,0.001,Polyethylene LDPE,0,0,0,0.75\r
+SEMROC Astronautics,CP-20,20 in. Plastic Chute,in,8,20,0,8,20,30 Lb. kevlar,0.001,Polyethylene LDPE,0,0,0,0.75\r
+SEMROC Astronautics,CP-24,24 in. Plastic Chute,in,8,24,0,8,24,30 Lb. kevlar,0.001,Polyethylene LDPE,0,0,0,0.75\r
+SEMROC Astronautics,CP-32,32 in. Plastic Chute,in,8,32,0,8,32,30 Lb. kevlar,0.001,Polyethylene LDPE,0,0,0,0.75\r
+SEMROC Astronautics,PN-14,14 in. Nylon Chute,in,6,14,0,6,16,1/16 In. braided nylon,0.004,Rip Stop Nylon,0,0,0,0.75\r
+SEMROC Astronautics,PN-18,18 In. Nylon Chute,in,8,18,0,8,20,1/16 In. braided nylon,0.004,Rip Stop Nylon,0,0,0,0.75\r
+SEMROC Astronautics,PN-24,24 In. Nylon Chute,in,0,24,0,10,24,1/16 In. braided nylon,0.004,Rip Stop Nylon,0,0,0,0.75\r
+SEMROC Astronautics,PN-30,30 In. Nylon Chute,in,0,30,0,10,30,1/16 In. braided nylon,0.004,Rip Stop Nylon,0,0,0,0.75\r
+SEMROC Astronautics,PN-36,36 In. Nylon Chute,in,0,36,0,10,36,1/16 In. braided nylon,0.004,Rip Stop Nylon,0,0,0,0.75\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/STDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/STDATA.CSV
new file mode 100644 (file)
index 0000000..580328a
--- /dev/null
@@ -0,0 +1,8 @@
+Mfg.,Part No.,Desc.,Units,Length,Width,Thickness,Count,Material\r
+SEMROC Astronautics,SM-1A,"Streamer 1"" x 8""",in,8,1,0.002,1,Paper\r
+SEMROC Astronautics,RS-118,"Streamer 1"" x 18""",in,18,1,0.002,1,Paper\r
+SEMROC Astronautics,RS-124,"Streamer 1"" x 24""",in,24,1,0.002,1,Paper\r
+SEMROC Astronautics,RS-136,"Streamer 1"" x 36""",in,36,1,0.002,1,Paper\r
+SEMROC Astronautics,RS-224,"Streamer 1.75"" x 24""",in,24,1.75,0.002,1,Paper\r
+SEMROC Astronautics,RS-236,"Streamer 1.75"" x 36""",in,36,1.75,0.002,1,Paper\r
+SEMROC Astronautics,RSW-36,"Streamer 3"" x 36""",in,36,3,0.002,1,Paper\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/TCDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/TCDATA.CSV
new file mode 100644 (file)
index 0000000..38627cd
--- /dev/null
@@ -0,0 +1,21 @@
+Mfg.,Part No.,Desc.,Units,ID,OD,Length,Material,CG,Mass Units,Mass,AutoSize\r
+SEMROC Astronautics,HTC-5,Tube Coupler Series 5,in,0.473,0.515,0.750,Paper,0.375,oz,0.010,0\r
+SEMROC Astronautics,HTC-7,Tube Coupler Series 7,in,0.673,0.715,1.000,Paper,0.500,oz,0.026,0\r
+SEMROC Astronautics,HTC-7B,Tube Coupler Series 7,in,0.719,0.761,1.000,Paper,0.500,oz,0.026,0\r
+SEMROC Astronautics,HTC-8,Tube Coupler Series 8,in,0.823,0.865,1.000,Paper,0.500,oz,0.038,0\r
+SEMROC Astronautics,HTC-8F,Tube Coupler Series 8F,in,0.843,0.885,1.000,Paper,0.500,oz,0.039,0\r
+SEMROC Astronautics,HTC-9,Tube Coupler Series 9,in,0.908,0.950,1.000,Paper,0.500,oz,0.041,0\r
+SEMROC Astronautics,HTC-10,Tube Coupler Series 10,in,0.958,1.000,1.500,Paper,0.750,oz,0.064,0\r
+SEMROC Astronautics,HTC-11,Tube Coupler Series 11,in,1.088,1.130,1.500,Paper,0.750,oz,0.071,0\r
+SEMROC Astronautics,HTC-13,Tube Coupler Series 13,in,1.258,1.300,1.750,Paper,0.875,oz,0.125,0\r
+SEMROC Astronautics,HTC-16,Tube Coupler Series 16,in,1.558,1.600,1.750,Paper,0.875,oz,0.175,0\r
+SEMROC Astronautics,HTC-18,Tube Coupler Series 18,in,1.758,1.800,1.750,Paper,0.875,oz,0.210,0\r
+SEMROC Astronautics,HTC-20,Tube Coupler Series 20,in,1.958,2.000,2.100,Paper,1.050,oz,0.265,0\r
+SEMROC Astronautics,JT-5C,Tube Coupler Series BT-5,in,0.473,0.515,0.750,Paper,0.375,oz,0.010,0\r
+SEMROC Astronautics,JT-20C,Tube Coupler Series BT-20,in,0.668,0.710,1.000,Paper,0.500,oz,0.026,0\r
+SEMROC Astronautics,JT-50C,Tube Coupler Series BT-50,in,0.908,0.950,1.000,Paper,0.500,oz,0.039,0\r
+SEMROC Astronautics,JT-55C,Tube Coupler Series BT-55,in,1.241,1.283,1.500,Paper,0.750,oz,0.049,0\r
+SEMROC Astronautics,JT-60C,Tube Coupler Series BT-60,in,1.553,1.595,1.750,Paper,0.875,oz,0.055,0\r
+SEMROC Astronautics,JT-70D,Tube Coupler Series BT-70,in,2.133,2.175,0.625,Paper,0.313,oz,0.087,0\r
+SEMROC Astronautics,JT-70E,Tube Coupler Series BT-70,in,2.133,2.175,4.000,Paper,2.000,oz,0.557,0\r
+SEMROC Astronautics,JT-80E,Tube Coupler Series BT-80,in,2.514,2.556,4.000,Paper,2.000,oz,0.730,0\r
diff --git a/core/resources-src/datafiles/rocksim_components/semroc/TRDATA.CSV b/core/resources-src/datafiles/rocksim_components/semroc/TRDATA.CSV
new file mode 100644 (file)
index 0000000..ffd408c
--- /dev/null
@@ -0,0 +1,176 @@
+Mfg.,Part No.,Desc.,Units,Front Insert Len,Front Insert OD,Front OD,Length,Rear OD,Core Dia.,Rear Insert Len,Rear Insert OD,Thickness,Config,Material,CG Loc,Mass Units,Mass,Shape,Shape Param\r
+SEMROC Astronautics,BR-085225,Balsa Reducer 085 to 225,in,0.500,0.865,0.945,2.500,2.3400,0,0.500,2.250,0,0,Balsa,2.485,oz,0.780,cone,0\r
+SEMROC Astronautics,BR-085225 [R],Balsa Reducer 085 to 225 \96 Reversed,in,0.500,2.250,2.340,2.500,0.9450,0,0.500,0.865,0,0,Balsa,1.015,oz,0.780,cone,0\r
+SEMROC Astronautics,BR-1013,Balsa Reducer 10 to 13,in,0.500,1.000,1.040,0.750,1.3400,0,0.500,1.300,0,0,Balsa,1.243,oz,0.180,cone,0\r
+SEMROC Astronautics,BR-1013 [R],Balsa Reducer 10 to 13 \96 Reversed,in,0.500,1.300,1.340,0.750,1.0400,0,0.500,1.000,0,0,Balsa,0.508,oz,0.180,cone,0\r
+SEMROC Astronautics,BR-1016,Balsa Reducer 10 to 16,in,0.500,1.000,1.040,1.500,1.6400,0,0.500,1.600,0,0,Balsa,1.775,oz,0.320,cone,0\r
+SEMROC Astronautics,BR-1016 [R],Balsa Reducer 10 to 16 \96 Reversed,in,0.500,1.600,1.640,1.500,1.0400,0,0.500,1.000,0,0,Balsa,0.725,oz,0.320,cone,0\r
+SEMROC Astronautics,BR-1016S,Balsa Reducer 10 to 16,in,0.500,1.000,1.040,1.200,1.6400,0,0.500,1.600,0,0,Balsa,1.562,oz,0.290,cone,0\r
+SEMROC Astronautics,BR-1016S [R],Balsa Reducer 10 to 16 \96 Reversed,in,0.500,1.600,1.640,1.200,1.0400,0,0.500,1.000,0,0,Balsa,0.638,oz,0.290,cone,0\r
+SEMROC Astronautics,BR-1116,Balsa Reducer 11 to 16,in,0.500,1.130,1.170,1.500,1.6400,0,0.500,1.600,0,0,Balsa,1.775,oz,0.330,cone,0\r
+SEMROC Astronautics,BR-1116 [R],Balsa Reducer 11 to 16 \96 Reversed,in,0.500,1.600,1.640,1.500,1.1700,0,0.500,1.130,0,0,Balsa,0.725,oz,0.330,cone,0\r
+SEMROC Astronautics,BR-1118,Balsa Reducer 11 to 18,in,0.500,1.130,1.170,1.500,1.8400,0,0.500,1.800,0,0,Balsa,1.775,oz,0.360,cone,0\r
+SEMROC Astronautics,BR-1118 [R],Balsa Reducer 11 to 18 \96 Reversed,in,0.500,1.800,1.840,1.500,1.1700,0,0.500,1.130,0,0,Balsa,0.725,oz,0.360,cone,0\r
+SEMROC Astronautics,BR-11516,Balsa Reducer 115 to 16,in,0.500,1.140,1.220,3.375,1.6400,0,0.500,1.600,0,0,Balsa,3.106,oz,1.050,cone,0\r
+SEMROC Astronautics,BR-11516 [R],Balsa Reducer 115 to 16 \96 Reversed,in,0.500,1.600,1.640,3.375,1.2200,0,0.500,1.140,0,0,Balsa,1.269,oz,1.050,cone,0\r
+SEMROC Astronautics,BR-11518,Balsa Reducer 115 to 18,in,0.500,1.140,1.220,3.375,1.8400,0,0.500,1.800,0,0,Balsa,3.106,oz,1.100,cone,0\r
+SEMROC Astronautics,BR-11518 [R],Balsa Reducer 115 to 18 \96 Reversed,in,0.500,1.800,1.840,3.375,1.2200,0,0.500,1.140,0,0,Balsa,1.269,oz,1.100,cone,0\r
+SEMROC Astronautics,BR-125-175,Balsa Reducer 125 to 175,in,0.500,1.250,1.340,2.100,1.8400,0,0.500,1.750,0,0,Balsa,2.201,oz,0.500,cone,0\r
+SEMROC Astronautics,BR-125-175 [R],Balsa Reducer 125 to 175 \96 Reversed,in,0.500,1.750,1.840,2.100,1.3400,0,0.500,1.250,0,0,Balsa,0.899,oz,0.500,cone,0\r
+SEMROC Astronautics,BR-125-175L,Balsa Reducer 125 to 175,in,0.500,1.250,1.340,2.800,1.8400,0,0.500,1.750,0,0,Balsa,2.698,oz,0.650,cone,0\r
+SEMROC Astronautics,BR-125-175L [R],Balsa Reducer 125 to 175 \96 Reversed,in,0.500,1.750,1.840,2.800,1.3400,0,0.500,1.250,0,0,Balsa,1.102,oz,0.650,cone,0\r
+SEMROC Astronautics,BR-125-225,Balsa Reducer 125 to 225,in,0.500,1.250,1.340,2.800,2.3400,0,0.500,2.250,0,0,Balsa,2.698,oz,0.600,cone,0\r
+SEMROC Astronautics,BR-125-225 [R],Balsa Reducer 125 to 225 \96 Reversed,in,0.500,2.250,2.340,2.800,1.3400,0,0.500,1.250,0,0,Balsa,1.102,oz,0.600,cone,0\r
+SEMROC Astronautics,BR-1316,Balsa Reducer 13 to 16,in,0.500,1.300,1.340,0.750,1.6400,0,0.500,1.600,0,0,Balsa,1.243,oz,0.240,cone,0\r
+SEMROC Astronautics,BR-1316 [R],Balsa Reducer 13 to 16 \96 Reversed,in,0.500,1.600,1.640,0.750,1.3400,0,0.500,1.300,0,0,Balsa,0.508,oz,0.240,cone,0\r
+SEMROC Astronautics,BR-1316F,Balsa Reducer 13 to 16,in,0.500,1.300,1.340,1.750,1.6400,0,0.500,1.600,0,0,Balsa,1.953,oz,0.360,cone,0\r
+SEMROC Astronautics,BR-1316F [R],Balsa Reducer 13 to 16 \96 Reversed,in,0.500,1.600,1.640,1.750,1.3400,0,0.500,1.300,0,0,Balsa,0.798,oz,0.360,cone,0\r
+SEMROC Astronautics,BR-1316L,Balsa Reducer 13 to 16,in,0.500,1.300,1.340,1.500,1.6400,0,0.500,1.600,0,0,Balsa,1.775,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-1316L [R],Balsa Reducer 13 to 16 \96 Reversed,in,0.500,1.600,1.640,1.500,1.3400,0,0.500,1.300,0,0,Balsa,0.725,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-1316M,Balsa Reducer 13 to 16,in,0.500,1.300,1.340,1.000,1.6400,0,0.500,1.600,0,0,Balsa,1.420,oz,0.280,cone,0\r
+SEMROC Astronautics,BR-1316M [R],Balsa Reducer 13 to 16 \96 Reversed,in,0.500,1.600,1.640,1.000,1.3400,0,0.500,1.300,0,0,Balsa,0.580,oz,0.280,cone,0\r
+SEMROC Astronautics,BR-1320,Balsa Reducer 13 to 20,in,0.500,1.300,1.340,0.750,2.0400,0,0.500,2.000,0,0,Balsa,1.243,oz,0.280,cone,0\r
+SEMROC Astronautics,BR-1320 [R],Balsa Reducer 13 to 20 \96 Reversed,in,0.500,2.000,2.040,0.750,1.3400,0,0.500,1.300,0,0,Balsa,0.508,oz,0.280,cone,0\r
+SEMROC Astronautics,BR-1320L,Balsa Reducer 13 to 20,in,0.500,1.300,1.340,4.500,2.0400,0,0.500,2.000,0,0,Balsa,3.905,oz,0.560,cone,0\r
+SEMROC Astronautics,BR-1320L [R],Balsa Reducer 13 to 20 \96 Reversed,in,0.500,2.000,2.040,4.500,1.3400,0,0.500,1.300,0,0,Balsa,1.595,oz,0.560,cone,0\r
+SEMROC Astronautics,BR-150-225,Balsa Reducer 150 to 225,in,0.500,1.500,1.590,2.250,2.3400,0,0.500,2.250,0,0,Balsa,2.308,oz,1.050,cone,0\r
+SEMROC Astronautics,BR-150-225 [R],Balsa Reducer 150 to 225 \96 Reversed,in,0.500,2.250,2.340,2.250,1.5900,0,0.500,1.500,0,0,Balsa,0.943,oz,1.050,cone,0\r
+SEMROC Astronautics,BR-150-275,Balsa Reducer 150 to 275,in,0.500,1.500,1.590,2.900,2.8400,0,0.500,2.750,0,0,Balsa,2.769,oz,1.450,cone,0\r
+SEMROC Astronautics,BR-150-275 [R],Balsa Reducer 150 to 275 \96 Reversed,in,0.500,2.750,2.840,2.900,1.5900,0,0.500,1.500,0,0,Balsa,1.131,oz,1.450,cone,0\r
+SEMROC Astronautics,BR-1618,Balsa Reducer 16 to 18,in,0.500,1.600,1.640,1.500,1.8400,0,0.500,1.800,0,0,Balsa,1.775,oz,0.280,cone,0\r
+SEMROC Astronautics,BR-1618 [R],Balsa Reducer 16 to 18 \96 Reversed,in,0.500,1.800,1.840,1.500,1.6400,0,0.500,1.600,0,0,Balsa,0.725,oz,0.280,cone,0\r
+SEMROC Astronautics,BR-1618F,Balsa Reducer 16 to 18,in,0.500,1.600,1.640,1.800,1.8400,0,0.500,1.800,0,0,Balsa,1.988,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-1618F [R],Balsa Reducer 16 to 18 \96 Reversed,in,0.500,1.800,1.840,1.800,1.6400,0,0.500,1.600,0,0,Balsa,0.812,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-1620,Balsa Reducer 16 to 20,in,0.500,1.600,1.640,1.500,2.0400,0,0.500,2.000,0,0,Balsa,1.775,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-1620 [R],Balsa Reducer 16 to 20 \96 Reversed,in,0.500,2.000,2.040,1.500,1.6400,0,0.500,1.600,0,0,Balsa,0.725,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-1620F,Balsa Reducer 16 to 20,in,0.500,1.600,1.640,1.200,2.0400,0,0.500,2.000,0,0,Balsa,1.562,oz,0.270,cone,0\r
+SEMROC Astronautics,BR-1620F [R],Balsa Reducer 16 to 20 \96 Reversed,in,0.500,2.000,2.040,1.200,1.6400,0,0.500,1.600,0,0,Balsa,0.638,oz,0.270,cone,0\r
+SEMROC Astronautics,BR-16225F,Balsa Reducer 16 to 225,in,0.500,1.600,1.640,1.550,2.3400,0,0.500,2.250,0,0,Balsa,1.811,oz,0.330,cone,0\r
+SEMROC Astronautics,BR-16225F [R],Balsa Reducer 16 to 225 \96 Reversed,in,0.500,2.250,2.340,1.550,1.6400,0,0.500,1.600,0,0,Balsa,0.740,oz,0.330,cone,0\r
+SEMROC Astronautics,BR-175-225,Balsa Reducer 175 to 225,in,0.500,1.750,1.840,2.100,2.3400,0,0.500,2.250,0,0,Balsa,2.201,oz,0.800,cone,0\r
+SEMROC Astronautics,BR-175-225 [R],Balsa Reducer 175 to 225 \96 Reversed,in,0.500,2.250,2.340,2.100,1.8400,0,0.500,1.750,0,0,Balsa,0.899,oz,0.800,cone,0\r
+SEMROC Astronautics,BR-1820,Balsa Reducer 18 to 20,in,0.500,1.800,1.840,1.500,2.0400,0,0.500,2.000,0,0,Balsa,1.775,oz,0.250,cone,0\r
+SEMROC Astronautics,BR-1820 [R],Balsa Reducer 18 to 20 \96 Reversed,in,0.500,2.000,2.040,1.500,1.8400,0,0.500,1.800,0,0,Balsa,0.725,oz,0.250,cone,0\r
+SEMROC Astronautics,BR-18225,Balsa Reducer 18 to 225,in,0.500,1.800,1.840,2.000,2.3400,0,0.500,2.250,0,0,Balsa,2.130,oz,0.310,cone,0\r
+SEMROC Astronautics,BR-18225 [R],Balsa Reducer 18 to 225 \96 Reversed,in,0.500,2.250,2.340,2.000,1.8400,0,0.500,1.800,0,0,Balsa,0.870,oz,0.310,cone,0\r
+SEMROC Astronautics,BR-225-80H,Balsa Reducer 225 to BT-80H,in,0.500,2.250,2.340,2.100,2.6400,0,0.500,2.558,0,0,Balsa,2.201,oz,1.300,cone,0\r
+SEMROC Astronautics,BR-225-80H [R],Balsa Reducer 225 to BT-80H \96 Reversed,in,0.500,2.558,2.640,2.100,2.3400,0,0.500,2.250,0,0,Balsa,0.899,oz,1.300,cone,0\r
+SEMROC Astronautics,BR-510,Balsa Reducer 5 to 10,in,0.500,0.515,0.543,0.750,1.0400,0,0.500,1.000,0,0,Balsa,1.243,oz,0.110,cone,0\r
+SEMROC Astronautics,BR-510 [R],Balsa Reducer 5 to 10 \96 Reversed,in,0.500,1.000,1.040,0.750,0.5430,0,0.500,0.515,0,0,Balsa,0.508,oz,0.110,cone,0\r
+SEMROC Astronautics,BR-511,Balsa Reducer 5 to 11,in,0.500,0.515,0.543,0.750,1.1700,0,0.500,1.130,0,0,Balsa,1.243,oz,0.120,cone,0\r
+SEMROC Astronautics,BR-511 [R],Balsa Reducer 5 to 11 \96 Reversed,in,0.500,1.130,1.170,0.750,0.5430,0,0.500,0.515,0,0,Balsa,0.508,oz,0.120,cone,0\r
+SEMROC Astronautics,BR-513,Balsa Reducer 5 to 13,in,0.500,0.515,0.543,1.500,1.3400,0,0.500,1.300,0,0,Balsa,1.775,oz,0.160,cone,0\r
+SEMROC Astronautics,BR-513 [R],Balsa Reducer 5 to 13 \96 Reversed,in,0.500,1.300,1.340,1.500,0.5430,0,0.500,0.515,0,0,Balsa,0.725,oz,0.160,cone,0\r
+SEMROC Astronautics,BR-57,Balsa Reducer 5 to 7,in,0.500,0.515,0.543,0.500,0.7590,0,0.500,0.715,0,0,Balsa,1.065,oz,0.070,cone,0\r
+SEMROC Astronautics,BR-57 [R],Balsa Reducer 5 to 7 \96 Reversed,in,0.500,0.715,0.759,0.500,0.5430,0,0.500,0.515,0,0,Balsa,0.435,oz,0.070,cone,0\r
+SEMROC Astronautics,BR-58,Balsa Reducer 5 to 8,in,0.500,0.515,0.543,0.500,0.9080,0,0.500,0.865,0,0,Balsa,1.065,oz,0.100,cone,0\r
+SEMROC Astronautics,BR-58 [R],Balsa Reducer 5 to 8 \96 Reversed,in,0.500,0.865,0.908,0.500,0.5430,0,0.500,0.515,0,0,Balsa,0.435,oz,0.100,cone,0\r
+SEMROC Astronautics,BR-58F,Balsa Reducer 5 to 8F,in,0.500,0.515,0.543,0.500,0.9210,0,0.500,0.885,0,0,Balsa,1.065,oz,0.100,cone,0\r
+SEMROC Astronautics,BR-58F [R],Balsa Reducer 5 to 8F \96 Reversed,in,0.500,0.885,0.921,0.500,0.5430,0,0.500,0.515,0,0,Balsa,0.435,oz,0.100,cone,0\r
+SEMROC Astronautics,BR-59,Balsa Reducer 5 to 9,in,0.500,0.515,0.543,1.000,0.9980,0,0.500,0.950,0,0,Balsa,1.420,oz,0.180,cone,0\r
+SEMROC Astronautics,BR-59 [R],Balsa Reducer 5 to 9 \96 Reversed,in,0.500,0.950,0.998,1.000,0.5430,0,0.500,0.515,0,0,Balsa,0.580,oz,0.180,cone,0\r
+SEMROC Astronautics,BR-60-18,Balsa Reducer BT-60 to ST-18,in,0.500,1.595,1.637,1.000,1.8400,0,0.500,1.800,0,0,Balsa,1.420,oz,0.290,cone,0\r
+SEMROC Astronautics,BR-60-18 [R],Balsa Reducer BT-60 to ST-18 \96 Reversed,in,0.500,1.800,1.840,1.000,1.6370,0,0.500,1.595,0,0,Balsa,0.580,oz,0.290,cone,0\r
+SEMROC Astronautics,BR-710,Balsa Reducer 7 to 10,in,0.500,0.715,0.759,0.750,1.0400,0,0.500,1.000,0,0,Balsa,1.243,oz,0.120,cone,0\r
+SEMROC Astronautics,BR-710 [R],Balsa Reducer 7 to 10 \96 Reversed,in,0.500,1.000,1.040,0.750,0.7590,0,0.500,0.715,0,0,Balsa,0.508,oz,0.120,cone,0\r
+SEMROC Astronautics,BR-711,Balsa Reducer 7 to 11,in,0.500,0.715,0.759,0.750,1.1700,0,0.500,1.130,0,0,Balsa,1.243,oz,0.130,cone,0\r
+SEMROC Astronautics,BR-711 [R],Balsa Reducer 7 to 11 \96 Reversed,in,0.500,1.130,1.170,0.750,0.7590,0,0.500,0.715,0,0,Balsa,0.508,oz,0.130,cone,0\r
+SEMROC Astronautics,BR-713,Balsa Reducer 7 to 13,in,0.500,0.715,0.759,1.500,1.3400,0,0.500,1.300,0,0,Balsa,1.775,oz,0.180,cone,0\r
+SEMROC Astronautics,BR-713 [R],Balsa Reducer 7 to 13 \96 Reversed,in,0.500,1.300,1.340,1.500,0.7590,0,0.500,0.715,0,0,Balsa,0.725,oz,0.180,cone,0\r
+SEMROC Astronautics,BR-716,Balsa Reducer 7 to 16,in,0.500,0.715,0.759,2.000,1.6400,0,0.500,1.600,0,0,Balsa,2.130,oz,0.360,cone,0\r
+SEMROC Astronautics,BR-716 [R],Balsa Reducer 7 to 16 \96 Reversed,in,0.500,1.600,1.640,2.000,0.7590,0,0.500,0.715,0,0,Balsa,0.870,oz,0.360,cone,0\r
+SEMROC Astronautics,BR-718,Balsa Reducer 7 to 18,in,0.500,0.715,0.759,2.000,1.8400,0,0.500,1.800,0,0,Balsa,2.130,oz,0.420,cone,0\r
+SEMROC Astronautics,BR-718 [R],Balsa Reducer 7 to 18 \96 Reversed,in,0.500,1.800,1.840,2.000,0.7590,0,0.500,0.715,0,0,Balsa,0.870,oz,0.420,cone,0\r
+SEMROC Astronautics,BR-78,Balsa Reducer 7 to 8,in,0.500,0.715,0.759,0.875,0.9080,0,0.500,0.865,0,0,Balsa,1.331,oz,0.130,cone,0\r
+SEMROC Astronautics,BR-78 [R],Balsa Reducer 7 to 8 \96 Reversed,in,0.500,0.865,0.908,0.875,0.7590,0,0.500,0.715,0,0,Balsa,0.544,oz,0.130,cone,0\r
+SEMROC Astronautics,BR-78F,Balsa Reducer 7 to 8F,in,0.500,0.715,0.759,1.000,0.9210,0,0.500,0.885,0,0,Balsa,1.420,oz,0.170,cone,0\r
+SEMROC Astronautics,BR-78F [R],Balsa Reducer 7 to 8F \96 Reversed,in,0.500,0.885,0.921,1.000,0.7590,0,0.500,0.715,0,0,Balsa,0.580,oz,0.170,cone,0\r
+SEMROC Astronautics,BR-78S,Balsa Reducer 7 to 8,in,0.500,0.715,0.759,0.500,0.9080,0,0.500,0.865,0,0,Balsa,1.065,oz,0.100,cone,0\r
+SEMROC Astronautics,BR-78S [R],Balsa Reducer 7 to 8 \96 Reversed,in,0.500,0.865,0.908,0.500,0.7590,0,0.500,0.715,0,0,Balsa,0.435,oz,0.100,cone,0\r
+SEMROC Astronautics,BR-79,Balsa Reducer 7 to 9,in,0.500,0.715,0.759,1.000,0.9980,0,0.500,0.950,0,0,Balsa,1.420,oz,0.170,cone,0\r
+SEMROC Astronautics,BR-79 [R],Balsa Reducer 7 to 9 \96 Reversed,in,0.500,0.950,0.998,1.000,0.7590,0,0.500,0.715,0,0,Balsa,0.580,oz,0.170,cone,0\r
+SEMROC Astronautics,BR-79L,Balsa Reducer 7 to 9,in,0.500,0.715,0.759,2.000,0.9980,0,0.500,0.950,0,0,Balsa,2.130,oz,0.230,cone,0\r
+SEMROC Astronautics,BR-79L [R],Balsa Reducer 7 to 9 \96 Reversed,in,0.500,0.950,0.998,2.000,0.7590,0,0.500,0.715,0,0,Balsa,0.870,oz,0.230,cone,0\r
+SEMROC Astronautics,BR-810,Balsa Reducer 8 to 10,in,0.500,0.865,0.908,0.500,1.0400,0,0.500,1.000,0,0,Balsa,1.065,oz,0.140,cone,0\r
+SEMROC Astronautics,BR-810 [R],Balsa Reducer 8 to 10 \96 Reversed,in,0.500,1.000,1.040,0.500,0.9080,0,0.500,0.865,0,0,Balsa,0.435,oz,0.140,cone,0\r
+SEMROC Astronautics,BR-813,Balsa Reducer 8 to 13,in,0.500,0.865,0.908,1.700,1.3400,0,0.500,1.300,0,0,Balsa,1.917,oz,0.260,cone,0\r
+SEMROC Astronautics,BR-813 [R],Balsa Reducer 8 to 13 \96 Reversed,in,0.500,1.300,1.340,1.700,0.9080,0,0.500,0.865,0,0,Balsa,0.783,oz,0.260,cone,0\r
+SEMROC Astronautics,BR-813P,Balsa Reducer 8 to 13,in,0.500,0.865,0.908,1.500,1.3400,0,0.500,1.300,0,0,Balsa,1.775,oz,0.260,cone,0\r
+SEMROC Astronautics,BR-813P [R],Balsa Reducer 8 to 13 \96 Reversed,in,0.500,1.300,1.340,1.500,0.9080,0,0.500,0.865,0,0,Balsa,0.725,oz,0.260,cone,0\r
+SEMROC Astronautics,BR-816,Balsa Reducer 8 to 16,in,0.500,0.865,0.908,1.500,1.6400,0,0.500,1.600,0,0,Balsa,1.775,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-816 [R],Balsa Reducer 8 to 16 \96 Reversed,in,0.500,1.600,1.640,1.500,0.9080,0,0.500,0.865,0,0,Balsa,0.725,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-816NT,Balsa Reducer 8 to 16,in,0.500,0.865,0.908,1.700,1.6400,0,0.500,1.600,0,0,Balsa,1.917,oz,0.380,cone,0\r
+SEMROC Astronautics,BR-816NT [R],Balsa Reducer 8 to 16 \96 Reversed,in,0.500,1.600,1.640,1.700,0.9080,0,0.500,0.865,0,0,Balsa,0.783,oz,0.380,cone,0\r
+SEMROC Astronautics,BR-8F11,Balsa Reducer 8F to 11,in,0.500,0.885,0.921,1.000,1.1700,0,0.500,1.130,0,0,Balsa,1.420,oz,0.180,cone,0\r
+SEMROC Astronautics,BR-8F11 [R],Balsa Reducer 8F to 11 \96 Reversed,in,0.500,1.130,1.170,1.000,0.9210,0,0.500,0.885,0,0,Balsa,0.580,oz,0.180,cone,0\r
+SEMROC Astronautics,BR-8F11L,Balsa Reducer 8F to 11,in,0.500,0.885,0.921,1.500,1.1700,0,0.500,1.130,0,0,Balsa,1.775,oz,0.220,cone,0\r
+SEMROC Astronautics,BR-8F11L [R],Balsa Reducer 8F to 11 \96 Reversed,in,0.500,1.130,1.170,1.500,0.9210,0,0.500,0.885,0,0,Balsa,0.725,oz,0.220,cone,0\r
+SEMROC Astronautics,BR-916,Balsa Reducer 9 to 16,in,0.500,0.950,0.998,2.000,1.6400,0,0.500,1.600,0,0,Balsa,2.130,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-916 [R],Balsa Reducer 9 to 16 \96 Reversed,in,0.500,1.600,1.640,2.000,0.9980,0,0.500,0.950,0,0,Balsa,0.870,oz,0.300,cone,0\r
+SEMROC Astronautics,BR-918,Balsa Reducer 9 to 18,in,0.500,0.950,0.998,2.000,1.8400,0,0.500,1.800,0,0,Balsa,2.130,oz,0.320,cone,0\r
+SEMROC Astronautics,BR-918 [R],Balsa Reducer 9 to 18 \96 Reversed,in,0.500,1.800,1.840,2.000,0.9980,0,0.500,0.950,0,0,Balsa,0.870,oz,0.320,cone,0\r
+SEMROC Astronautics,BR-920,Balsa Reducer 9 to 20,in,0.500,0.950,0.998,2.000,2.0400,0,0.500,2.000,0,0,Balsa,2.130,oz,0.340,cone,0\r
+SEMROC Astronautics,BR-920 [R],Balsa Reducer 9 to 20 \96 Reversed,in,0.500,2.000,2.040,2.000,0.9980,0,0.500,0.950,0,0,Balsa,0.870,oz,0.340,cone,0\r
+SEMROC Astronautics,TA-2050,Balsa Reducer BT-20 to BT-50,in,0.500,0.710,0.736,2.000,0.9760,0,0.500,0.950,0,0,Balsa,2.130,oz,0.170,cone,0\r
+SEMROC Astronautics,TA-2050 [R],Balsa Reducer BT-20 to BT-50 \96 Reversed,in,0.500,0.950,0.976,2.000,0.7360,0,0.500,0.710,0,0,Balsa,0.870,oz,0.170,cone,0\r
+SEMROC Astronautics,TA-2050A,Balsa Reducer BT-20 to BT-50,in,0.500,0.710,0.736,1.000,0.9760,0,0.500,0.950,0,0,Balsa,1.420,oz,0.110,cone,0\r
+SEMROC Astronautics,TA-2050A [R],Balsa Reducer BT-20 to BT-50 \96 Reversed,in,0.500,0.950,0.976,1.000,0.7360,0,0.500,0.710,0,0,Balsa,0.580,oz,0.110,cone,0\r
+SEMROC Astronautics,TA-2050B,Balsa Reducer BT-20 to BT-50,in,0.500,0.710,0.736,2.500,0.9760,0,0.500,0.950,0,0,Balsa,2.485,oz,0.210,cone,0\r
+SEMROC Astronautics,TA-2050B [R],Balsa Reducer BT-20 to BT-50 \96 Reversed,in,0.500,0.950,0.976,2.500,0.7360,0,0.500,0.710,0,0,Balsa,1.015,oz,0.210,cone,0\r
+SEMROC Astronautics,TA-2055,Balsa Reducer BT-20 to BT-55,in,0.500,0.710,0.736,1.500,1.3250,0,0.500,1.283,0,0,Balsa,1.775,oz,0.220,cone,0\r
+SEMROC Astronautics,TA-2055 [R],Balsa Reducer BT-20 to BT-55 \96 Reversed,in,0.500,1.283,1.325,1.500,0.7360,0,0.500,0.710,0,0,Balsa,0.725,oz,0.220,cone,0\r
+SEMROC Astronautics,TA-2060,Balsa Reducer BT-20 to BT-60,in,0.500,0.710,0.736,2.000,1.6370,0,0.500,1.595,0,0,Balsa,2.130,oz,0.200,cone,0\r
+SEMROC Astronautics,TA-2060 [R],Balsa Reducer BT-20 to BT-60 \96 Reversed,in,0.500,1.595,1.637,2.000,0.7360,0,0.500,0.710,0,0,Balsa,0.870,oz,0.200,cone,0\r
+SEMROC Astronautics,TA-5055,Balsa Reducer BT-50 to BT-55,in,0.500,0.950,0.976,1.000,1.3250,0,0.500,1.283,0,0,Balsa,1.420,oz,0.600,cone,0\r
+SEMROC Astronautics,TA-5055 [R],Balsa Reducer BT-50 to BT-55 \96 Reversed,in,0.500,1.283,1.325,1.000,0.9760,0,0.500,0.950,0,0,Balsa,0.580,oz,0.600,cone,0\r
+SEMROC Astronautics,TA-5055L,Balsa Reducer BT-50 to BT-55,in,0.500,0.950,0.976,1.500,1.3250,0,0.500,1.283,0,0,Balsa,1.775,oz,0.710,cone,0\r
+SEMROC Astronautics,TA-5055L [R],Balsa Reducer BT-50 to BT-55 \96 Reversed,in,0.500,1.283,1.325,1.500,0.9760,0,0.500,0.950,0,0,Balsa,0.725,oz,0.710,cone,0\r
+SEMROC Astronautics,TA-5060,Balsa Reducer BT-50 to BT-60,in,0.500,0.950,0.976,2.000,1.6370,0,0.500,1.595,0,0,Balsa,2.130,oz,0.230,cone,0\r
+SEMROC Astronautics,TA-5060 [R],Balsa Reducer BT-50 to BT-60 \96 Reversed,in,0.500,1.595,1.637,2.000,0.9760,0,0.500,0.950,0,0,Balsa,0.870,oz,0.230,cone,0\r
+SEMROC Astronautics,TA-5060C,Balsa Reducer BT-50 to BT-60,in,0.500,0.950,0.976,0.500,1.6370,0,0.500,1.595,0,0,Balsa,1.065,oz,0.140,cone,0\r
+SEMROC Astronautics,TA-5060C [R],Balsa Reducer BT-50 to BT-60 \96 Reversed,in,0.500,1.595,1.637,0.500,0.9760,0,0.500,0.950,0,0,Balsa,0.435,oz,0.140,cone,0\r
+SEMROC Astronautics,TA-5060E,Balsa Reducer BT-50 to BT-60,in,0.500,0.950,0.976,2.000,1.6370,0,0.500,1.595,0,0,Balsa,2.130,oz,0.210,elliptical,0\r
+SEMROC Astronautics,TA-5060E [R],Balsa Reducer BT-50 to BT-60 \96 Reversed,in,0.500,1.595,1.637,2.000,0.9760,0,0.500,0.950,0,0,Balsa,0.870,oz,0.210,elliptical,0\r
+SEMROC Astronautics,TA-5065,Balsa Reducer BT-50 to BT-65,in,0.500,0.950,0.976,2.000,1.7960,0,0.500,1.750,0,0,Balsa,2.130,oz,0.260,cone,0\r
+SEMROC Astronautics,TA-5065 [R],Balsa Reducer BT-50 to BT-65 \96 Reversed,in,0.500,1.750,1.796,2.000,0.9760,0,0.500,0.950,0,0,Balsa,0.870,oz,0.260,cone,0\r
+SEMROC Astronautics,TA-520,Balsa Reducer BT-5 to BT-20,in,0.500,0.515,0.541,0.750,0.7360,0,0.500,0.710,0,0,Balsa,1.243,oz,0.040,cone,0\r
+SEMROC Astronautics,TA-520 [R],Balsa Reducer BT-5 to BT-20 \96 Reversed,in,0.500,0.710,0.736,0.750,0.5410,0,0.500,0.515,0,0,Balsa,0.508,oz,0.040,cone,0\r
+SEMROC Astronautics,TA-5260A,Balsa Reducer BT-52 to BT-60,in,0.500,0.988,1.014,1.000,1.6370,0,0.500,1.595,0,0,Balsa,1.420,oz,0.230,cone,0\r
+SEMROC Astronautics,TA-5260A [R],Balsa Reducer BT-52 to BT-60 \96 Reversed,in,0.500,1.595,1.637,1.000,1.0140,0,0.500,0.988,0,0,Balsa,0.580,oz,0.230,cone,0\r
+SEMROC Astronautics,TA-5260C,Balsa Reducer BT-52 to BT-60,in,0.500,0.988,1.014,3.800,1.6370,0,0.500,1.595,0,0,Balsa,3.408,oz,0.330,cone,0\r
+SEMROC Astronautics,TA-5260C [R],Balsa Reducer BT-52 to BT-60 \96 Reversed,in,0.500,1.595,1.637,3.800,1.0140,0,0.500,0.988,0,0,Balsa,1.392,oz,0.330,cone,0\r
+SEMROC Astronautics,TA-550,Balsa Reducer BT-5 to BT-50,in,0.500,0.515,0.541,1.000,0.9760,0,0.500,0.950,0,0,Balsa,1.420,oz,0.060,cone,0\r
+SEMROC Astronautics,TA-550 [R],Balsa Reducer BT-5 to BT-50 \96 Reversed,in,0.500,0.950,0.976,1.000,0.5410,0,0.500,0.515,0,0,Balsa,0.580,oz,0.060,cone,0\r
+SEMROC Astronautics,TA-5560,Balsa Reducer BT-55 to BT-60,in,0.500,1.283,1.325,1.000,1.6370,0,0.500,1.595,0,0,Balsa,1.420,oz,0.250,cone,0\r
+SEMROC Astronautics,TA-5560 [R],Balsa Reducer BT-55 to BT-60 \96 Reversed,in,0.500,1.595,1.637,1.000,1.3250,0,0.500,1.283,0,0,Balsa,0.580,oz,0.250,cone,0\r
+SEMROC Astronautics,TA-5560A,Balsa Reducer BT-55 to BT-60,in,0.500,1.283,1.325,1.250,1.6370,0,0.500,1.595,0,0,Balsa,1.598,oz,0.290,cone,0\r
+SEMROC Astronautics,TA-5560A [R],Balsa Reducer BT-55 to BT-60 \96 Reversed,in,0.500,1.595,1.637,1.250,1.3250,0,0.500,1.283,0,0,Balsa,0.653,oz,0.290,cone,0\r
+SEMROC Astronautics,TA-5565,Balsa Reducer BT-55 to BT-65,in,0.500,1.283,1.325,1.500,1.7960,0,0.500,1.750,0,0,Balsa,1.775,oz,0.380,cone,0\r
+SEMROC Astronautics,TA-5565 [R],Balsa Reducer BT-55 to BT-65 \96 Reversed,in,0.500,1.750,1.796,1.500,1.3250,0,0.500,1.283,0,0,Balsa,0.725,oz,0.380,cone,0\r
+SEMROC Astronautics,TA-6065,Balsa Reducer BT-60 to BT-65,in,0.500,1.595,1.637,0.500,1.7960,0,0.500,1.750,0,0,Balsa,1.065,oz,0.230,cone,0\r
+SEMROC Astronautics,TA-6065 [R],Balsa Reducer BT-60 to BT-65 \96 Reversed,in,0.500,1.750,1.796,0.500,1.6370,0,0.500,1.595,0,0,Balsa,0.435,oz,0.230,cone,0\r
+SEMROC Astronautics,TA-6070,Balsa Reducer BT-60 to BT-70,in,0.500,1.595,1.637,1.500,2.2170,0,0.500,2.175,0,0,Balsa,1.775,oz,0.650,cone,0\r
+SEMROC Astronautics,TA-6070 [R],Balsa Reducer BT-60 to BT-70 \96 Reversed,in,0.500,2.175,2.217,1.500,1.6370,0,0.500,1.595,0,0,Balsa,0.725,oz,0.650,cone,0\r
+SEMROC Astronautics,TA-6080,Balsa Reducer BT-60 to BT-80,in,0.500,1.595,1.637,1.500,2.6000,0,0.500,2.558,0,0,Balsa,1.775,oz,0.650,cone,0\r
+SEMROC Astronautics,TA-6080 [R],Balsa Reducer BT-60 to BT-80 \96 Reversed,in,0.500,2.558,2.600,1.500,1.6370,0,0.500,1.595,0,0,Balsa,0.725,oz,0.650,cone,0\r
+SEMROC Astronautics,TA-7080,Balsa Reducer BT-70 to BT-80,in,0.500,2.175,2.217,1.500,2.6000,0,0.500,2.558,0,0,Balsa,1.775,oz,0.650,cone,0\r
+SEMROC Astronautics,TA-7080 [R],Balsa Reducer BT-70 to BT-80 \96 Reversed,in,0.500,2.558,2.600,1.500,2.2170,0,0.500,2.175,0,0,Balsa,0.725,oz,0.650,cone,0\r
+SEMROC Astronautics,BC-08542 [R],Balsa Nose Cone \96 Reversed,in,0.500,0.850,0.000,4.200,0.0001,0,0.000,0.000,0,0,Balsa,1.363,oz,0.150,ogive,\r
+SEMROC Astronautics,BC-1016 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,1.600,0.0001,0,0.000,0.000,0,0,Balsa,0.609,oz,0.120,ogive,\r
+SEMROC Astronautics,BC-1019 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,1.900,0.0001,0,0.000,0.000,0,0,Balsa,0.696,oz,0.130,ogive,\r
+SEMROC Astronautics,BC-1020E [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,2.000,0.0001,0,0.000,0.000,0,0,Balsa,0.725,oz,0.130,elliptical\r
+SEMROC Astronautics,BC-1022 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,2.200,0.0001,0,0.000,0.000,0,0,Balsa,0.783,oz,0.150,elliptical\r
+SEMROC Astronautics,BC-1024 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,2.400,0.0001,0,0.000,0.000,0,0,Balsa,0.841,oz,0.150,ogive\r
+SEMROC Astronautics,BC-1031 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,3.100,0.0001,0,0.000,0.000,0,0,Balsa,1.044,oz,0.150,elliptical\r
+SEMROC Astronautics,BC-1032 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,3.200,0.0001,0,0.000,0.000,0,0,Balsa,1.073,oz,0.150,ogive\r
+SEMROC Astronautics,BC-1037 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,3.700,0.0001,0,0.000,0.000,0,0,Balsa,1.218,oz,0.160,ogive\r
+SEMROC Astronautics,BC-1039 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,3.900,0.0001,0,0.000,0.000,0,0,Balsa,1.276,oz,0.170,ogive\r
+SEMROC Astronautics,BC-1041 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,4.100,0.0001,0,0.000,0.000,0,0,Balsa,1.334,oz,0.180,ogive\r
+SEMROC Astronautics,BC-1041G [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,4.100,0.0001,0,0.000,0.000,0,0,Balsa,1.334,oz,0.180,cone\r
+SEMROC Astronautics,BC-1041P [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,4.100,0.0001,0,0.000,0.000,0,0,Balsa,1.334,oz,0.180,elliptical\r
+SEMROC Astronautics,BC-1045 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,4.500,0.0001,0,0.000,0.000,0,0,Balsa,1.450,oz,0.190,ogive\r
+SEMROC Astronautics,BC-1045P [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,4.500,0.0001,0,0.000,0.000,0,0,Balsa,1.450,oz,0.190,elliptical\r
+SEMROC Astronautics,BC-1048 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,4.800,0.0001,0,0.000,0.000,0,0,Balsa,1.537,oz,0.190,elliptical\r
+SEMROC Astronautics,BC-1050 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,5.000,0.0001,0,0.000,0.000,0,0,Balsa,1.595,oz,1.090,elliptical\r
+SEMROC Astronautics,BC-1051 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,5.100,0.0001,0,0.000,0.000,0,0,Balsa,1.624,oz,0.200,elliptical\r
+SEMROC Astronautics,BC-1052 [R],Balsa Nose Cone \96 Reversed,in,0.500,1.000,1.040,5.200,0.0001,0,0.000,0.000,0,0,Balsa,1.653,oz,0.220,ogive\r
diff --git a/core/resources-src/datafiles/thrustcurves/Quest_D5_1.eng b/core/resources-src/datafiles/thrustcurves/Quest_D5_1.eng
new file mode 100644 (file)
index 0000000..d122650
--- /dev/null
@@ -0,0 +1,35 @@
+; QUEST D5 RASP.ENG FILE\r
+; The total impulse, peak thrust, average thrust and burn time are\r
+; the same as the averaged static test data on the NAR web site in\r
+; the certification file. The curve drawn with these data points is as\r
+; close to the certification curve as can be with such a limited\r
+; number of points (32) allowed with wRASP up to v1.6.\r
+D5 20 96 4-6 0.0240 0.0451 QUEST\r
+0.010 1.014\r
+0.122 2.652\r
+0.172 4.836\r
+0.273 7.723\r
+0.331 10.610\r
+0.390 13.809\r
+0.448 16.800\r
+0.480 12.403\r
+0.484 8.266\r
+0.517 5.221\r
+0.713 4.125\r
+0.974 4.121\r
+1.135 3.338\r
+1.324 3.101\r
+1.550 3.254\r
+1.971 3.169\r
+2.393 3.162\r
+2.752 3.391\r
+3.069 3.386\r
+3.547 3.301\r
+3.694 3.064\r
+3.948 3.294\r
+4.215 3.290\r
+4.412 3.287\r
+4.496 2.505\r
+4.586 1.801\r
+4.610 0.000\r
+;\r
diff --git a/core/resources-src/datafiles/thrustcurves/Quest_Micro_Maxx_II.eng b/core/resources-src/datafiles/thrustcurves/Quest_Micro_Maxx_II.eng
new file mode 100644 (file)
index 0000000..274c231
--- /dev/null
@@ -0,0 +1,39 @@
+; Traced from NAR certification data dated 1-29-2009\r
+MicroMaxxII 6 26 1 5.0E-4 0.0010 Q\r
+   0.021 0.015\r
+   0.036 0.05\r
+   0.043 0.103\r
+   0.049 0.198\r
+   0.08 1.636\r
+   0.092 1.3\r
+   0.109 0.995\r
+   0.124 0.805\r
+   0.133 0.442\r
+   0.143 0.301\r
+   0.164 0.21\r
+   0.186 0.149\r
+   0.199 0.183\r
+   0.235 0.145\r
+   0.256 0.145\r
+   0.293 0.149\r
+   0.327 0.164\r
+   0.367 0.156\r
+   0.387 0.175\r
+   0.409 0.183\r
+   0.431 0.191\r
+   0.461 0.21\r
+   0.474 0.202\r
+   0.49 0.217\r
+   0.505 0.175\r
+   0.513 0.198\r
+   0.537 0.172\r
+   0.553 0.175\r
+   0.602 0.156\r
+   0.623 0.175\r
+   0.644 0.183\r
+   0.674 0.21\r
+   0.689 0.191\r
+   0.697 0.229\r
+   0.731 0.21\r
+   0.753 0.092\r
+   0.771 0.0\r
index 3c6da043914834d70d0a6a969442c6a41fd57c29..7adea3ab837404319608d8f72c2b3c6dd50ad6cd 100644 (file)
@@ -7,3 +7,6 @@ SF_*.eng - Thrust curves for Weco Feuerwerk motors, created by Sampo N.
 
 Loki_J175.rse - Corrected motor type from hybrid to reloadable
 
+Quest_D5_1.eng - Corrected motor mass from .451 to .0451
+
+Quest_Micro_Maxx_II.eng - Removed "NE" from delays since OR cannot handle it.
diff --git a/core/resources-src/pix/android-ic_launcher.xcf.gz b/core/resources-src/pix/android-ic_launcher.xcf.gz
new file mode 100644 (file)
index 0000000..e7a959f
Binary files /dev/null and b/core/resources-src/pix/android-ic_launcher.xcf.gz differ
index d12cc3a34a5b8e6572a5d12244d6b49f733aa7bb..d4cfa89103cfb143fb991fc603392e766e69fb37 100644 (file)
@@ -1,7 +1,7 @@
 
 # The OpenRocket build version
 
-build.version=12.03
+build.version=12.09
 
 
 # The source of the package.  When building a package for a specific
diff --git a/core/resources/datafiles/examples/Preset Usage.ork b/core/resources/datafiles/examples/Preset Usage.ork
new file mode 100644 (file)
index 0000000..9e78075
Binary files /dev/null and b/core/resources/datafiles/examples/Preset Usage.ork differ
index fe1799721b4d8c591efdc881f0cc163529281968..e7695cd7fc11b2abd730a978914dfc27af7ae259 100644 (file)
@@ -4,7 +4,7 @@
     <name>Roll-stabilized rocket</name>
     <comment>Canting the fins may increase the flight stability of a rocket.
 
-Be cautios when flying rockets with marginal or neurtal static stability!!</comment>
+Be cautious when flying rockets with marginal or neutral static stability!!</comment>
     <designer>Sampo Niskanen</designer>
     <motorconfiguration configid="e1dc7488-77c0-403a-b54f-c01db07aba2f"/>
     <motorconfiguration configid="d33813f0-2563-41f7-8bb3-96eae598f567" default="true"/>
diff --git a/core/resources/datafiles/presets/Estes.orc b/core/resources/datafiles/presets/Estes.orc
new file mode 100644 (file)
index 0000000..47e7939
--- /dev/null
@@ -0,0 +1,1603 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<OpenRocketComponent>
+    <Version>0.1</Version>
+    <Materials>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name></Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>.060 Carbon Fiber</Name>
+            <Density>1400.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>.125 in Fiberglass/Honeycomb</Name>
+            <Density>461.33174592000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>.25 in Fiberglass/Honeycomb</Name>
+            <Density>235.47141198</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1 in. Flat Elastic</Name>
+            <Density>0.015514109144</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1 in. Tubular Nylon</Name>
+            <Density>0.044644918400000004</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1.1 Ounce Rip Stop Nylon</Name>
+            <Density>0.05983056264534001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.1 oz. Rip Stop Nylon</Name>
+            <Density>0.037350571446</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.3 oz. Ripstop Nylon (SkyAngle)</Name>
+            <Density>0.04407367430628</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.7 oz. Ripstop Nylon</Name>
+            <Density>0.057638523018492004</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.9 oz. Ripstop Nylon</Name>
+            <Density>0.06441875028216</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.9 oz. Ripstop Nylon (PML)</Name>
+            <Density>0.08788369752</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.9 oz. Ripstop Nylon (SkyAngle)</Name>
+            <Density>0.06441875028216</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/16 in. Aircraft Plywood</Name>
+            <Density>361.3765253</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/16 in. Braided Nylon</Name>
+            <Density>0.00102</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/16 in. Round Elastic</Name>
+            <Density>0.00183</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/2 in. Flat Elastic</Name>
+            <Density>0.003125144288</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/2 in. Tubular Kevlar</Name>
+            <Density>0.044644918400000004</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/2 in. Tubular Nylon</Name>
+            <Density>0.060870160920000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/32 in. Kevlar</Name>
+            <Density>6.590000000000001E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/4 Aircraft Plywood</Name>
+            <Density>344.269</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/4 In. Flat Elastic</Name>
+            <Density>0.00402</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/4 in. Aircraft Plywood</Name>
+            <Density>344.2688068</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/4 in. Braided Nylon</Name>
+            <Density>0.06535533067200001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/4 in. Tubular Kevlar</Name>
+            <Density>0.022322459200000002</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/8 Aircraft Plywood</Name>
+            <Density>337.541</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/8 in Birch Plywood (Revell)</Name>
+            <Density>640.7385360000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/8 in. Aircraft Plywood</Name>
+            <Density>672.7754628</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/8 in. Braided Nylon</Name>
+            <Density>0.03267766533600001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/8 in. Flat Elastic</Name>
+            <Density>0.00205</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/8 in. Flat Rubber</Name>
+            <Density>0.00231</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/8 in. Tubular Kevlar</Name>
+            <Density>0.011161229600000001</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>100 lb Kevlar (Apogee 29505)</Name>
+            <Density>0.006359329969800001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>100 lb. Kevlar</Name>
+            <Density>0.032837849970000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>100lb Kevlar (Apogee 29505)</Name>
+            <Density>0.006359329969800001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1500 lb. Kevlar</Name>
+            <Density>0.0959105496075</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1500lb Kevlar (Apogee 29507)</Name>
+            <Density>0.0959105496075</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>260 lb. Elastic</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/16 Aircraft Plywood</Name>
+            <Density>344.2688068</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/16 in. Aircraft Plywood</Name>
+            <Density>344.2688068</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>3/4 in. Flat Elastic</Name>
+            <Density>0.01227735256</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/8 in. Flat Elastic</Name>
+            <Density>0.060870160920000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>3/8 in. Tubular Nylon</Name>
+            <Density>0.018602086537432</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>3/8 in. Tubular Nylon (SkyAngle)</Name>
+            <Density>0.018602086537432</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/8 inch Flat Elastic</Name>
+            <Density>0.060870160920000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/8 tubular nylon (SkyAngle)</Name>
+            <Density>2.9797705801314</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>30 Lb. Kevlar</Name>
+            <Density>1.78E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>300 lb. Kevlar</Name>
+            <Density>0.01807843779324</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>300 lb. Kevlar (Apogee 29506)</Name>
+            <Density>0.01807843779324</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>300lb Kevlar (Apogee 29506)</Name>
+            <Density>0.01807843779324</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>4000 lb. nylon</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>5/64 in. Round Elastic</Name>
+            <Density>0.0024200000000000003</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>5/8 in. Tubular Nylon</Name>
+            <Density>0.022322459200000002</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>5/8 in. Tubular Nylon (SkyAngle)</Name>
+            <Density>0.022322459200000002</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>6000 lb. nylon</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>6oz &amp; 2oz FG &amp; Poster board</Name>
+            <Density>798.85</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>7/16 in. Flat Braided Kevlar</Name>
+            <Density>0.0502255332</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>70 Lb. Kevlar</Name>
+            <Density>3.3E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>750 Lb. Kevlar</Name>
+            <Density>0.0030135319920000002</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>9/16 in. Tubular Nylon</Name>
+            <Density>0.0167418444</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Acrylic (Cast)</Name>
+            <Density>1185.3662916</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aircraft plywood (Birch)</Name>
+            <Density>724.9956534840001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aircraft plywood (LOC)</Name>
+            <Density>724.9956534840001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aluminum</Name>
+            <Density>2698.9</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aluminum (Al)</Name>
+            <Density>2698.9</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aluminum 2024</Name>
+            <Density>2780.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aluminum 7075</Name>
+            <Density>2810.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Ash</Name>
+            <Density>680.7846945000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Balsa</Name>
+            <Density>128.1477072</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Basswood</Name>
+            <Density>424.48928010000003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Beech</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Birch</Name>
+            <Density>680.7846945000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Birch Plywood (Revell)</Name>
+            <Density>656.7569994</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Blue Tube</Name>
+            <Density>1237.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Blue Tube 2</Name>
+            <Density>1250.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Brass</Name>
+            <Density>8553.8594556</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Carbon Fiber</Name>
+            <Density>1400.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cardboard</Name>
+            <Density>688.7939262000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>Carpet String</Name>
+            <Density>3.2972000000000003E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>Carpet String (Apogee 29500)</Name>
+            <Density>3.2972000000000003E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cellulose Acetate Propionate</Name>
+            <Density>1199.7829086600002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Chalk (Fine)</Name>
+            <Density>1121.2924380000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Composite Fin Material</Name>
+            <Density>634.3311506400001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Copper (cast)</Name>
+            <Density>8682.0071628</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Copper (rolled)</Name>
+            <Density>8906.2656504</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cork (Solid)</Name>
+            <Density>240.27695100000003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cottonwood</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Custom</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Dyna-Wind Tubing</Name>
+            <Density>1210.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fiber</Name>
+            <Density>656.7569994</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fiberglass</Name>
+            <Density>1905.2360367960002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fir (Douglas)</Name>
+            <Density>560.6462190000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fir (White)</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.062)</Name>
+            <Density>3.137448001464</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 (PML 0.062)</Name>
+            <Density>0.07059977558916</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.093)</Name>
+            <Density>5.022553313268</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.125)</Name>
+            <Density>6.169435565904</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Fiberglass</Name>
+            <Density>2175.3073297200003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Fiberglass (LOC)</Name>
+            <Density>1905.2360367960002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Fiberglass Filament Wound</Name>
+            <Density>1934.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Fiberglass Filament Wound Tube</Name>
+            <Density>1820.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Phenolic</Name>
+            <Density>1905.2360367960002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G12 Fiberglass</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Glassed Phenolic</Name>
+            <Density>1900.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Gold (24 kt.)</Name>
+            <Density>19286.229933600003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>Kevlar Thread (Apogee 29502)</Name>
+            <Density>8.858E-5</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Kraft phenolic</Name>
+            <Density>943.4874942600001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Kraft phenolic (Glassed)</Name>
+            <Density>1153.329336</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lead (cast)</Name>
+            <Density>11341.072087200002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lead (rolled)</Name>
+            <Density>11389.127477400001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lead Shot</Name>
+            <Density>6727.75</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Leather</Name>
+            <Density>945.0893406000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lexan</Name>
+            <Density>1218.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lite Plywood</Name>
+            <Density>352.40619480000004</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Magna Phenolic</Name>
+            <Density>1100.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Mail Tube Paper</Name>
+            <Density>800.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Maple (Hard)</Name>
+            <Density>632.7293043000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Mat Board 4-Ply</Name>
+            <Density>710.579</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Mylar</Name>
+            <Density>1309.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 200</Name>
+            <Density>8890.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 400</Name>
+            <Density>8800.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 600</Name>
+            <Density>8410.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 625</Name>
+            <Density>8440.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 718</Name>
+            <Density>8230.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel C276</Name>
+            <Density>8890.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nylon</Name>
+            <Density>1140.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (Brown)</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (Red)</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (White)</Name>
+            <Density>752.8677798000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>PVC</Name>
+            <Density>1300.6992280800002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Paper</Name>
+            <Density>608.7016092000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Paper/2layers 8 oz.  glass</Name>
+            <Density>1681.94</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Pine (White Northern)</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Pine (White Western)</Name>
+            <Density>432.4985118000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Plastic</Name>
+            <Density>920.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polycarbonate</Name>
+            <Density>1199.7829086600002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polyethylene</Name>
+            <Density>920.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polyethylene LDPE</Name>
+            <Density>924.2653381800002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Polyethylene LDPE(0.051)</Name>
+            <Density>0.04713753224718001</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polystyrene PS</Name>
+            <Density>1049.2093527000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Poplar (Yellow)</Name>
+            <Density>480.55390200000005</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Quantum Tubing</Name>
+            <Density>1100.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Rip stop nylon</Name>
+            <Density>0.06684999999999999</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Rocketwood</Name>
+            <Density>529.089846102</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Russian 1/8 in. Plywood</Name>
+            <Density>685.1</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Silver</Name>
+            <Density>10460.056600200001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spiral/Glassine</Name>
+            <Density>848.9785602000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spiral/Glassine-Thick</Name>
+            <Density>768.886</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spruce</Name>
+            <Density>448.51697520000005</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Stainless steel 17-4PH</Name>
+            <Density>7600.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Stainless steel 17-5PH</Name>
+            <Density>7800.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Stainless steel 17-7PH</Name>
+            <Density>7800.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Steel</Name>
+            <Density>7850.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Steel 4130</Name>
+            <Density>7850.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Steel 4340</Name>
+            <Density>7850.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Sycamore</Name>
+            <Density>560.6462190000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Titanium</Name>
+            <Density>4500.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Urethane</Name>
+            <Density>847.0563445920002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Vulcanized Fiber</Name>
+            <Density>1250.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>lite ply</Name>
+            <Density>352.406186</Density>
+            <Type>BULK</Type>
+        </Material>
+    </Materials>
+    <Components>
+        <Transition>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>30101</PartNumber>
+            <Description>BULL PUB BT-55 Tail cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.0040</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0337</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.032100000000000004</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.022</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.025</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.029</Length>
+            <Thickness Unit="m">0.0022</Thickness>
+        </Transition>
+        <EngineBlock>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>30162-2</PartNumber>
+            <Description>Eng. Block BT-20 / .2in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0165</InsideDiameter>
+            <OutsideDiameter Unit="m">0.018000000000000002</OutsideDiameter>
+            <Length Unit="m">0.0050</Length>
+        </EngineBlock>
+        <Parachute>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>302260</PartNumber>
+            <Description>18 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.010480000000000001</Mass>
+            <Diameter Unit="m">0.4572</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.6096</LineLength>
+            <LineMaterial Type="LINE">1/16 in. Braided Nylon</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>302260</PartNumber>
+            <Description>18 in. Nylon Chute</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.010480000000000001</Mass>
+            <Diameter Unit="m">0.4572</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.6095999999999999</LineLength>
+            <LineMaterial Type="LINE">Carpet String</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>302262</PartNumber>
+            <Description>6 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Diameter Unit="m">0.1524</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.1524</LineLength>
+            <LineMaterial Type="LINE">Carpet String</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>302264</PartNumber>
+            <Description>12 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Mass Unit="kg">0.0020411656632</Mass>
+            <Diameter Unit="m">0.30479999999999996</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.30479999999999996</LineLength>
+            <LineMaterial Type="LINE">Carpet String</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>302267</PartNumber>
+            <Description>18 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Mass Unit="kg">0.0058967008048</Mass>
+            <Diameter Unit="m">0.4572</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.4572</LineLength>
+            <LineMaterial Type="LINE">Carpet String</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>302271</PartNumber>
+            <Description>24 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Mass Unit="kg">0.0077677693294</Mass>
+            <Diameter Unit="m">0.6095999999999999</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.6095999999999999</LineLength>
+            <LineMaterial Type="LINE">Carpet String</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>82426-30</PartNumber>
+            <Description>24 in. Nylon Chute</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.023100000000000002</Mass>
+            <Diameter Unit="m">0.6095999999999999</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.7493</LineLength>
+            <LineMaterial Type="LINE">Carpet String</LineMaterial>
+        </Parachute>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-20AM</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-20B</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-20R</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-20Y</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.02413</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-50J</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.034798</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-50K</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-50KA</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.06946899999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-50Y</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11048999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-5E</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.013817600000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0131826</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.03505199999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-5S</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">4.535923696E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.013817600000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0131826</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-5V</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">3.685438003E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.013817600000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0131826</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-5W</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0011056314009</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013817600000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0131826</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-70AJ</PartNumber>
+            <Description>Balsa Nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.024097094635</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055372000000000005</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.11176</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>BNC-80K [R]</PartNumber>
+            <Description>Custom Tail Cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.067056</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.064973</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.03175</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.1524</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>DART</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.073152</Length>
+            <Thickness Unit="m">0.0015875</Thickness>
+        </NoseCone>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30174</PartNumber>
+            <Description>RT-99D Body Tube/.391in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0931672</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09626599999999999</OutsideDiameter>
+            <Length Unit="m">0.0099314</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30338</PartNumber>
+            <Description>BT-30 Body Tube/9in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30351</PartNumber>
+            <Description>BT-48BE Body Tube/2.5in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0229108</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0235712</OutsideDiameter>
+            <Length Unit="m">0.0635</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30376</PartNumber>
+            <Description>BT-51N Body Tube/12.42in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.024993599999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.025679399999999998</OutsideDiameter>
+            <Length Unit="m">0.31546799999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30380</PartNumber>
+            <Description>BT-52S Body Tube/3.938in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.025095199999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0282956</OutsideDiameter>
+            <Length Unit="m">0.1000252</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30394</PartNumber>
+            <Description>BT-58 Body Tube/12.75in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0380492</InsideDiameter>
+            <OutsideDiameter Unit="m">0.039116</OutsideDiameter>
+            <Length Unit="m">0.32384999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30420</PartNumber>
+            <Description>BT-63CJ Body Tube/3in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0416306</InsideDiameter>
+            <OutsideDiameter Unit="m">0.042697399999999996</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30424</PartNumber>
+            <Description>BT-70 Body Tube/17.5in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.055372000000000005</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.4445</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30436</PartNumber>
+            <Description>BT-100Z Body Tube/10.89in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0940308</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0950976</OutsideDiameter>
+            <Length Unit="m">0.276606</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 30449</PartNumber>
+            <Description>BT-101SV Body Tube/24.7in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.09895839999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1000252</OutsideDiameter>
+            <Length Unit="m">0.6273799999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 3084</PartNumber>
+            <Description>BT-5 Body Tube/18in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 3085</PartNumber>
+            <Description>BT-20 Body Tube/18in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 3086</PartNumber>
+            <Description>BT-50 Body Tube/18in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 3087</PartNumber>
+            <Description>BT-55 Body Tube/18in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 3088</PartNumber>
+            <Description>BT-56 Body Tube/18in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0331216</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0341884</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 3089</PartNumber>
+            <Description>BT-60 Body Tube/18in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>EST 3090</PartNumber>
+            <Description>BT-80 Body Tube/14.25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0657352</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <Length Unit="m">0.36195</Length>
+        </BodyTube>
+        <LaunchLug>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>ESTES 1/4</PartNumber>
+            <Description>1/4 in x 2in Launch lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.00635</InsideDiameter>
+            <OutsideDiameter Unit="m">0.007112</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>ESTES 1/8</PartNumber>
+            <Description>1/8 in x 1.25in Launch lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.003556</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004064</OutsideDiameter>
+            <Length Unit="m">0.03175</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>ESTES 3/16</PartNumber>
+            <Description>3/16 in x 2in Launch lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0055626</InsideDiameter>
+            <OutsideDiameter Unit="m">0.006096</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>JT-101SV</PartNumber>
+            <Description>Tube Coupler/3.9 x 1.375in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.096774</InsideDiameter>
+            <OutsideDiameter Unit="m">0.098806</OutsideDiameter>
+            <Length Unit="m">0.034925</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>JT-20C</PartNumber>
+            <Description>Tube Coupler/.71 x .75in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.016382999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017907</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>JT-50C</PartNumber>
+            <Description>Tube Coupler/.95 x 1in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.022479</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024002999999999997</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>JT-55C</PartNumber>
+            <Description>Tube Coupler/1.28 x 1.25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.030886399999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0324104</OutsideDiameter>
+            <Length Unit="m">0.03175</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>JT-5C</PartNumber>
+            <Description>Tube Coupler/.51 x .75in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.01143</InsideDiameter>
+            <OutsideDiameter Unit="m">0.012954</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>JT-60C</PartNumber>
+            <Description>Tube Coupler/1.59 x 1.5in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.038862</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>JT-70A</PartNumber>
+            <Description>Tube Coupler/2.17 x 2in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.053085999999999994</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05511799999999999</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>JT-80C</PartNumber>
+            <Description>Tube Coupler/2.55 x 3in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.062738</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06477</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>NB-20</PartNumber>
+            <Description>Balsa Tube Coupler/.71 x .75in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <InsideDiameter Unit="m">0.0</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017907</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>NB-50</PartNumber>
+            <Description>Balsa Tube Coupler/.95 x 1in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <InsideDiameter Unit="m">0.0</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024002999999999997</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-20</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.00335</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06731</Length>
+            <Thickness Unit="m">0.0015875</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-20Y</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.02413</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-50YR</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.104775</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-55</PartNumber>
+            <Description>Plastic Sentinal Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.024805800000000003</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.212725</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-55AC</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.01133980924</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.13723619999999997</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-55AO</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.01219</Mass>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.033655000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.032588</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01524</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+            <Thickness Unit="m">0.0023876</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-55BB</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.01417476155</Mass>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.03175</ShoulderLength>
+            <Length Unit="m">0.1651</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-56</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0341884</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.16192499999999999</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-5A</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.013817600000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0131826</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.053974999999999995</Length>
+            <Thickness Unit="m">0.0015875</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-60A</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.024380600000000002</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041580000000000006</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04051300000000001</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01905</ShoulderLength>
+            <Length Unit="m">0.12065000000000001</Length>
+            <Thickness Unit="m">0.0023876</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-60AH</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.17145</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-60L</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.011056</Mass>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-60MS</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.01417476155</Mass>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-60NA</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.12065</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-80BB</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.044449999999999996</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-80FB</PartNumber>
+            <Description>Estes PNC-80 Fat Boy profile cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.035892</Mass>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.064922</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0381</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>PNC-80K</PartNumber>
+            <Description>Plastic Nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.047627198807999996</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.20701</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+    </Components>
+</OpenRocketComponent>
diff --git a/core/resources/datafiles/presets/Quest.orc b/core/resources/datafiles/presets/Quest.orc
new file mode 100644 (file)
index 0000000..849a889
--- /dev/null
@@ -0,0 +1,1406 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<OpenRocketComponent>
+    <Version>0.1</Version>
+    <Materials>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name></Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>.060 Carbon Fiber</Name>
+            <Density>1400.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>.125 in Fiberglass/Honeycomb</Name>
+            <Density>461.33174592000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>.25 in Fiberglass/Honeycomb</Name>
+            <Density>235.47141198</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1 in. Flat Elastic</Name>
+            <Density>0.015514109144</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1 in. Tubular Nylon</Name>
+            <Density>0.044644918400000004</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1.1 Ounce Rip Stop Nylon</Name>
+            <Density>0.05983056264534001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.1 oz. Rip Stop Nylon</Name>
+            <Density>0.037350571446</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.3 oz. Ripstop Nylon (SkyAngle)</Name>
+            <Density>0.04407367430628</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.7 oz. Ripstop Nylon</Name>
+            <Density>0.057638523018492004</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.9 oz. Ripstop Nylon</Name>
+            <Density>0.06441875028216</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.9 oz. Ripstop Nylon (PML)</Name>
+            <Density>0.08788369752</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>1.9 oz. Ripstop Nylon (SkyAngle)</Name>
+            <Density>0.06441875028216</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/16 in. Aircraft Plywood</Name>
+            <Density>361.3765253</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/16 in. Braided Nylon</Name>
+            <Density>0.00102</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/16 in. Round Elastic</Name>
+            <Density>0.00183</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/2 in. Flat Elastic</Name>
+            <Density>0.003125144288</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/2 in. Tubular Kevlar</Name>
+            <Density>0.044644918400000004</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/2 in. Tubular Nylon</Name>
+            <Density>0.060870160920000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/32 in. Kevlar</Name>
+            <Density>6.590000000000001E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/4 Aircraft Plywood</Name>
+            <Density>344.269</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/4 In. Flat Elastic</Name>
+            <Density>0.00402</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/4 in. Aircraft Plywood</Name>
+            <Density>344.2688068</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/4 in. Braided Nylon</Name>
+            <Density>0.06535533067200001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/4 in. Tubular Kevlar</Name>
+            <Density>0.022322459200000002</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/8 Aircraft Plywood</Name>
+            <Density>337.541</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/8 in Birch Plywood (Revell)</Name>
+            <Density>640.7385360000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/8 in. Aircraft Plywood</Name>
+            <Density>672.7754628</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1/8 in. Braided Nylon</Name>
+            <Density>0.03267766533600001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/8 in. Flat Elastic</Name>
+            <Density>0.00205</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/8 in. Flat Rubber</Name>
+            <Density>0.00231</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/8 in. Tubular Kevlar</Name>
+            <Density>0.011161229600000001</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>100 lb Kevlar (Apogee 29505)</Name>
+            <Density>0.006359329969800001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>100 lb. Kevlar</Name>
+            <Density>0.032837849970000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>100lb Kevlar (Apogee 29505)</Name>
+            <Density>0.006359329969800001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1500 lb. Kevlar</Name>
+            <Density>0.0959105496075</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>1500lb Kevlar (Apogee 29507)</Name>
+            <Density>0.0959105496075</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>260 lb. Elastic</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/16 Aircraft Plywood</Name>
+            <Density>344.2688068</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/16 in. Aircraft Plywood</Name>
+            <Density>344.2688068</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>3/4 in. Flat Elastic</Name>
+            <Density>0.01227735256</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/8 in. Flat Elastic</Name>
+            <Density>0.060870160920000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>3/8 in. Tubular Nylon</Name>
+            <Density>0.018602086537432</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>3/8 in. Tubular Nylon (SkyAngle)</Name>
+            <Density>0.018602086537432</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/8 inch Flat Elastic</Name>
+            <Density>0.060870160920000006</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>3/8 tubular nylon (SkyAngle)</Name>
+            <Density>2.9797705801314</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>30 Lb. Kevlar</Name>
+            <Density>1.78E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>300 lb. Kevlar</Name>
+            <Density>0.01807843779324</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>300 lb. Kevlar (Apogee 29506)</Name>
+            <Density>0.01807843779324</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>300lb Kevlar (Apogee 29506)</Name>
+            <Density>0.01807843779324</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>4000 lb. nylon</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>5/64 in. Round Elastic</Name>
+            <Density>0.0024200000000000003</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>5/8 in. Tubular Nylon</Name>
+            <Density>0.022322459200000002</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>5/8 in. Tubular Nylon (SkyAngle)</Name>
+            <Density>0.022322459200000002</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>6000 lb. nylon</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>6oz &amp; 2oz FG &amp; Poster board</Name>
+            <Density>798.85</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>7/16 in. Flat Braided Kevlar</Name>
+            <Density>0.0502255332</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>70 Lb. Kevlar</Name>
+            <Density>3.3E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>750 Lb. Kevlar</Name>
+            <Density>0.0030135319920000002</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>9/16 in. Tubular Nylon</Name>
+            <Density>0.0167418444</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Acrylic (Cast)</Name>
+            <Density>1185.3662916</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aircraft plywood (Birch)</Name>
+            <Density>724.9956534840001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aircraft plywood (LOC)</Name>
+            <Density>724.9956534840001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aluminum</Name>
+            <Density>2698.9</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aluminum (Al)</Name>
+            <Density>2698.9</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aluminum 2024</Name>
+            <Density>2780.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aluminum 7075</Name>
+            <Density>2810.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Ash</Name>
+            <Density>680.7846945000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Balsa</Name>
+            <Density>128.1477072</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Basswood</Name>
+            <Density>424.48928010000003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Beech</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Birch</Name>
+            <Density>680.7846945000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Birch Plywood (Revell)</Name>
+            <Density>656.7569994</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Blue Tube</Name>
+            <Density>1237.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Blue Tube 2</Name>
+            <Density>1250.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Brass</Name>
+            <Density>8553.8594556</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Carbon Fiber</Name>
+            <Density>1400.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cardboard</Name>
+            <Density>688.7939262000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>Carpet String</Name>
+            <Density>3.2972000000000003E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>Carpet String (Apogee 29500)</Name>
+            <Density>3.2972000000000003E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cellulose Acetate Propionate</Name>
+            <Density>1199.7829086600002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Chalk (Fine)</Name>
+            <Density>1121.2924380000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Composite Fin Material</Name>
+            <Density>634.3311506400001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Copper (cast)</Name>
+            <Density>8682.0071628</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Copper (rolled)</Name>
+            <Density>8906.2656504</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cork (Solid)</Name>
+            <Density>240.27695100000003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cottonwood</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Custom</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Dyna-Wind Tubing</Name>
+            <Density>1210.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fiber</Name>
+            <Density>656.7569994</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fiberglass</Name>
+            <Density>1905.2360367960002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fir (Douglas)</Name>
+            <Density>560.6462190000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fir (White)</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.062)</Name>
+            <Density>3.137448001464</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 (PML 0.062)</Name>
+            <Density>0.07059977558916</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.093)</Name>
+            <Density>5.022553313268</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.125)</Name>
+            <Density>6.169435565904</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Fiberglass</Name>
+            <Density>2175.3073297200003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Fiberglass (LOC)</Name>
+            <Density>1905.2360367960002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Fiberglass Filament Wound</Name>
+            <Density>1934.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Fiberglass Filament Wound Tube</Name>
+            <Density>1820.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 Phenolic</Name>
+            <Density>1905.2360367960002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G12 Fiberglass</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Glassed Phenolic</Name>
+            <Density>1900.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Gold (24 kt.)</Name>
+            <Density>19286.229933600003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>Kevlar Thread (Apogee 29502)</Name>
+            <Density>8.858E-5</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Kraft phenolic</Name>
+            <Density>943.4874942600001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Kraft phenolic (Glassed)</Name>
+            <Density>1153.329336</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lead (cast)</Name>
+            <Density>11341.072087200002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lead (rolled)</Name>
+            <Density>11389.127477400001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lead Shot</Name>
+            <Density>6727.75</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Leather</Name>
+            <Density>945.0893406000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lexan</Name>
+            <Density>1218.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lite Plywood</Name>
+            <Density>352.40619480000004</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Magna Phenolic</Name>
+            <Density>1100.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Mail Tube Paper</Name>
+            <Density>800.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Maple (Hard)</Name>
+            <Density>632.7293043000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Mat Board 4-Ply</Name>
+            <Density>710.579</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Mylar</Name>
+            <Density>1309.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 200</Name>
+            <Density>8890.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 400</Name>
+            <Density>8800.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 600</Name>
+            <Density>8410.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 625</Name>
+            <Density>8440.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel 718</Name>
+            <Density>8230.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nickel C276</Name>
+            <Density>8890.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nylon</Name>
+            <Density>1140.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (Brown)</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (Red)</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (White)</Name>
+            <Density>752.8677798000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>PVC</Name>
+            <Density>1300.6992280800002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Paper</Name>
+            <Density>608.7016092000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Paper/2layers 8 oz.  glass</Name>
+            <Density>1681.94</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Pine (White Northern)</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Pine (White Western)</Name>
+            <Density>432.4985118000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Plastic</Name>
+            <Density>920.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polycarbonate</Name>
+            <Density>1199.7829086600002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polyethylene</Name>
+            <Density>920.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polyethylene LDPE</Name>
+            <Density>924.2653381800002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Polyethylene LDPE(0.025)</Name>
+            <Density>0.023476339589772004</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Polyethylene LDPE(0.051)</Name>
+            <Density>0.04695267917954401</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polystyrene PS</Name>
+            <Density>1049.2093527000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Poplar (Yellow)</Name>
+            <Density>480.55390200000005</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Quantum Tubing</Name>
+            <Density>1100.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Rip stop nylon</Name>
+            <Density>0.06684999999999999</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Rocketwood</Name>
+            <Density>529.089846102</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Russian 1/8 in. Plywood</Name>
+            <Density>685.1</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Silver</Name>
+            <Density>10460.056600200001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spiral/Glassine</Name>
+            <Density>848.9785602000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spiral/Glassine-Thick</Name>
+            <Density>768.886</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spruce</Name>
+            <Density>448.51697520000005</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Stainless steel 17-4PH</Name>
+            <Density>7600.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Stainless steel 17-5PH</Name>
+            <Density>7800.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Stainless steel 17-7PH</Name>
+            <Density>7800.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Steel</Name>
+            <Density>7850.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Steel 4130</Name>
+            <Density>7850.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Steel 4340</Name>
+            <Density>7850.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Sycamore</Name>
+            <Density>560.6462190000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Titanium</Name>
+            <Density>4500.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Urethane</Name>
+            <Density>847.0563445920002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Vulcanized Fiber</Name>
+            <Density>1250.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>lite ply</Name>
+            <Density>352.406186</Density>
+            <Type>BULK</Type>
+        </Material>
+    </Materials>
+    <Components>
+        <TubeCoupler>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>10100</PartNumber>
+            <Description>.98in Tube coupler/2in</Description>
+            <Material Type="BULK">Kraft Phenolic</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <InsideDiameter Unit="m">0.0234188</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024993599999999998</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>10104</PartNumber>
+            <Description>1.34in Tube coupler/2.5in</Description>
+            <Material Type="BULK">Kraft Phenolic</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.0635</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>10311</PartNumber>
+            <Description>MMX Engine Tube/1in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.0064008</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0070104</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>10315</PartNumber>
+            <Description>D5 Motor Mount Tube/3.65in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <InsideDiameter Unit="m">0.020193</InsideDiameter>
+            <OutsideDiameter Unit="m">0.021209</OutsideDiameter>
+            <Length Unit="m">0.09271</Length>
+        </BodyTube>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>14007</PartNumber>
+            <Description>MMX Centering Ring .278 x .37 x .5in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0070612</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009398</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>19990</PartNumber>
+            <Description>MMX</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.01417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0099568</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0094488</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>2520</PartNumber>
+            <Description>Ribbed Plastic Reducer 25mm/20mm</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024993599999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.023977599999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0200152</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.019100799999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>2520 -R</PartNumber>
+            <Description>Ribbed Plastic Reducer 20mm/25mm -Rev</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0200152</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.019100799999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024993599999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.023977599999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>3025</PartNumber>
+            <Description>Ribbed Plastic Reducer 30mm/25mm</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0299974</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0289814</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024993599999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.023977599999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>3025 -R</PartNumber>
+            <Description>Ribbed Plastic Reducer 25mm/30mm -Rev</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024993599999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.023875999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0299974</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0289814</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>3525</PartNumber>
+            <Description>Ribbed Plastic Reducer 35mm/25mm</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.03505199999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.034036000000000004</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024993599999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.023977599999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.009524999999999999</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>3525 -R</PartNumber>
+            <Description>Ribbed Plastic Reducer 25mm/35mm -Rev</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024993599999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.023875999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.009524999999999999</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.03505199999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.034036000000000004</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>3530</PartNumber>
+            <Description>Ribbed Plastic Reducer 35mm/30mm</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.03505199999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.034036000000000004</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0299974</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028955999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.009524999999999999</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>3530 -R</PartNumber>
+            <Description>Ribbed Plastic Reducer 30mm/35mm -Rev</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0299974</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0289814</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.009524999999999999</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.03505199999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.034036000000000004</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </Transition>
+        <TubeCoupler>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>3535</PartNumber>
+            <Description>1.34in Plastic tube coupler 1in shoulder</Description>
+            <Material Type="BULK">Plastic</Material>
+            <Mass Unit="kg">0.009922333084999999</Mass>
+            <InsideDiameter Unit="m">0.030861</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.053974999999999995</Length>
+        </TubeCoupler>
+        <Parachute>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>7810</PartNumber>
+            <Description>14 in Plastic Parachute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <Diameter Unit="m">0.35559999999999997</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.35559999999999997</LineLength>
+            <LineMaterial Type="LINE">Carpet String</LineMaterial>
+        </Parachute>
+        <Streamer>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>7811</PartNumber>
+            <Description>Streamer 3in x 36in (2mil Plastic)</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Length Unit="m">0.9144</Length>
+            <Width Unit="m">0.07619999999999999</Width>
+            <Thickness Unit="m">2.54E-5</Thickness>
+        </Streamer>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>9527</PartNumber>
+            <Description>MMX Body Tube/6in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.0065278</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0070358</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>9528</PartNumber>
+            <Description>MMX Body Tube/6in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.0094488</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0099568</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR2125</PartNumber>
+            <Description>Paper Center Ring D5(20mm) to T25 x.045</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.021209</InsideDiameter>
+            <OutsideDiameter Unit="m">0.023977599999999998</OutsideDiameter>
+            <Length Unit="m">0.001143</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR2130</PartNumber>
+            <Description>Paper Center Ring D5(20mm) to T30 x.045</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.021209</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0289814</OutsideDiameter>
+            <Length Unit="m">0.001143</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR2135</PartNumber>
+            <Description>Paper Center Ring D5(20mm) to T35 x.045</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.021209</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.001143</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR2140</PartNumber>
+            <Description>Paper Center Ring D5(20mm) to T40 x.045</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.021209</InsideDiameter>
+            <OutsideDiameter Unit="m">0.038862</OutsideDiameter>
+            <Length Unit="m">0.001143</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR2150</PartNumber>
+            <Description>Paper Center Ring D5(20mm) to T50 x.07</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.021209</InsideDiameter>
+            <OutsideDiameter Unit="m">0.048768</OutsideDiameter>
+            <Length Unit="m">0.001778</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR24</PartNumber>
+            <Description>Paper Center Ring .75 x .942 x .25</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.019049999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.023926799999999998</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR2534</PartNumber>
+            <Description>Paper Center Ring T25(24mm) to T35 x .05</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.024993599999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR29</PartNumber>
+            <Description>Paper Center Ring 10303(18mm) to T30 x .045</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0289814</OutsideDiameter>
+            <Length Unit="m">0.001143</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR2924</PartNumber>
+            <Description>Paper Center Ring .994(25mm)x 1.134(29mm) x .5</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0252476</InsideDiameter>
+            <OutsideDiameter Unit="m">0.028803599999999995</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR34</PartNumber>
+            <Description>Paper Center Ring 10303(18mm) to T35 x .045</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.001143</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR39</PartNumber>
+            <Description>Paper Center Ring 10303(18mm) to T40 x .045</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.038862</OutsideDiameter>
+            <Length Unit="m">0.001143</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR4924</PartNumber>
+            <Description>Paper Center Ring T25(24mm) to T50 x .07</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.024993599999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.048768</OutsideDiameter>
+            <Length Unit="m">0.001778</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>CR4929</PartNumber>
+            <Description>Paper Center Ring T29(29mm) to T50 x .07</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.030861</InsideDiameter>
+            <OutsideDiameter Unit="m">0.048768</OutsideDiameter>
+            <Length Unit="m">0.001778</Length>
+        </CenteringRing>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC15</PartNumber>
+            <Description>15mm Plastic Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.014986</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013716</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0254</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC20</PartNumber>
+            <Description>20mm Plastic Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0199898</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.019049999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06426199999999999</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC25</PartNumber>
+            <Description>25mm Plastic Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024993599999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0237236</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08001</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC30</PartNumber>
+            <Description>30mm Plastic Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.01417476155</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.029972</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028701999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.08255</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC35</PartNumber>
+            <Description>35mm Plastic Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.03505199999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.033782</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.104648</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC35B2</PartNumber>
+            <Description>35mm Plastic X-15 Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.012190294933</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.03505199999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.033782</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC35N</PartNumber>
+            <Description>35mm Plastic Nike Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.02551457079</Mass>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.03505199999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.033782</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.2032</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC40</PartNumber>
+            <Description>40mm Plastic Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.01133980924</Mass>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.039878</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.038099999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>PNC50</PartNumber>
+            <Description>50mm Plastic Nose Cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.042524</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.050038000000000006</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.048260000000000004</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.057150000000000006</ShoulderLength>
+            <Length Unit="m">0.1524</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>Red tint payload tube</PartNumber>
+            <Description>Clear Red Body Tube/4in</Description>
+            <Material Type="BULK">Plastic</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <InsideDiameter Unit="m">0.023977599999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024993599999999998</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>T153000</PartNumber>
+            <Description>Body Tube/30in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <InsideDiameter Unit="m">0.01397</InsideDiameter>
+            <OutsideDiameter Unit="m">0.014986</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>T203000</PartNumber>
+            <Description>Body Tube/30in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.019844666169999997</Mass>
+            <InsideDiameter Unit="m">0.019100799999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0200152</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>T253000</PartNumber>
+            <Description>Body Tube/30in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.026932046945</Mass>
+            <InsideDiameter Unit="m">0.023977599999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024993599999999998</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>T303000</PartNumber>
+            <Description>Body Tube/30in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.034019427719999995</Mass>
+            <InsideDiameter Unit="m">0.0289814</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0299974</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>T353000</PartNumber>
+            <Description>Body Tube/30in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.035436903875</Mass>
+            <InsideDiameter Unit="m">0.034036000000000004</InsideDiameter>
+            <OutsideDiameter Unit="m">0.03505199999999999</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>T403000</PartNumber>
+            <Description>Body Tube/30in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.038271856185</Mass>
+            <InsideDiameter Unit="m">0.038862</InsideDiameter>
+            <OutsideDiameter Unit="m">0.039878</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Quest</Manufacturer>
+            <PartNumber>T502400</PartNumber>
+            <Description>Body Tube/24in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0566990462</Mass>
+            <InsideDiameter Unit="m">0.048768</InsideDiameter>
+            <OutsideDiameter Unit="m">0.050038</OutsideDiameter>
+            <Length Unit="m">0.6095999999999999</Length>
+        </BodyTube>
+        <EngineBlock>
+            <Manufacturer>Quest Aerospace</Manufacturer>
+            <PartNumber>14000</PartNumber>
+            <Description>Thrust Ring for 10303 Eng. Tube/ .25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.012954</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>Quest Aerospace</Manufacturer>
+            <PartNumber>14005</PartNumber>
+            <Description>MMX Thrust Ring/.25 x .25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <InsideDiameter Unit="m">0.0037592</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0062992</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>Quest Aerospace</Manufacturer>
+            <PartNumber>14101</PartNumber>
+            <Description>D5 Thrust Ring/ .25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">1.0E-5</Mass>
+            <InsideDiameter Unit="m">0.013843000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.020193</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>Quest Aerospace</Manufacturer>
+            <PartNumber>14103</PartNumber>
+            <Description>Engine Block 29mm/ .25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02286</InsideDiameter>
+            <OutsideDiameter Unit="m">0.028854399999999995</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+    </Components>
+</OpenRocketComponent>
diff --git a/core/resources/datafiles/presets/bluetube.orc b/core/resources/datafiles/presets/bluetube.orc
new file mode 100644 (file)
index 0000000..e5ca86c
--- /dev/null
@@ -0,0 +1,202 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<OpenRocketComponent>
+    <Version>0.1</Version>
+    <Materials>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Vulcanized Fiber</Name>
+            <Density>1250.0</Density>
+            <Type>BULK</Type>
+        </Material>
+    </Materials>
+    <Components>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-139A</PartNumber>
+            <Description>5.5 in Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.135763</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1397762</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-139C</PartNumber>
+            <Description>BT20-139C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.131826</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1355852</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-139C</PartNumber>
+            <Description>BT20-139C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.131826</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1355852</OutsideDiameter>
+            <Length Unit="m">0.4064</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-152A</PartNumber>
+            <Description>6 in Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.15239999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.156464</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-152C</PartNumber>
+            <Description>BT20-152C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.14820899999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1517904</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-152CL</PartNumber>
+            <Description>BT20-152CL</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.14820899999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1517904</OutsideDiameter>
+            <Length Unit="m">0.4064</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-191A</PartNumber>
+            <Description>7.5 in Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.19075399999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.194818</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-191C</PartNumber>
+            <Description>BT20-191C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.18669</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1900682</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-191CL</PartNumber>
+            <Description>BT20-191CL</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.18669</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1900682</OutsideDiameter>
+            <Length Unit="m">0.4064</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-29A</PartNumber>
+            <Description>29mm Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.0289814</InsideDiameter>
+            <OutsideDiameter Unit="m">0.03213099999999999</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-29C</PartNumber>
+            <Description>BT20-29C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.025831799999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0289814</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-38A</PartNumber>
+            <Description>38mm Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0418846</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-38C</PartNumber>
+            <Description>BT20-38C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.0354076</InsideDiameter>
+            <OutsideDiameter Unit="m">0.038480999999999994</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-54A</PartNumber>
+            <Description>54mm Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.054356</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05750559999999999</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-54C</PartNumber>
+            <Description>BT20-54C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0539496</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-63A</PartNumber>
+            <Description>2.56 in Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.06477</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0679196</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-63C</PartNumber>
+            <Description>BT20-63C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.0614172</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0645668</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-75A</PartNumber>
+            <Description>3 in Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.07619999999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0793496</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-75C</PartNumber>
+            <Description>BT20-75C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.0729742</InsideDiameter>
+            <OutsideDiameter Unit="m">0.07612379999999999</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </TubeCoupler>
+        <BodyTube>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-98A</PartNumber>
+            <Description>4 in Blue Tube 2.0 Airframe</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.099314</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1022096</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>Always Ready Rocketry</Manufacturer>
+            <PartNumber>BT20-98C</PartNumber>
+            <Description>BT20-98C</Description>
+            <Material Type="BULK">Vulcanized Fiber</Material>
+            <InsideDiameter Unit="m">0.09560559999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09875519999999999</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </TubeCoupler>
+    </Components>
+</OpenRocketComponent>
diff --git a/core/resources/datafiles/presets/bms.orc b/core/resources/datafiles/presets/bms.orc
new file mode 100644 (file)
index 0000000..5d233a3
--- /dev/null
@@ -0,0 +1,1721 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<OpenRocketComponent>
+    <Version>0.1</Version>
+    <Materials>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Balsa</Name>
+            <Density>128.1477072</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fiber</Name>
+            <Density>656.7569994</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Paper</Name>
+            <Density>1121.2924380000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>lite ply</Name>
+            <Density>352.40619480000004</Density>
+            <Type>BULK</Type>
+        </Material>
+    </Materials>
+    <Components>
+        <BulkHead>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BHC70-F</PartNumber>
+            <Description>2.104x.05thk fiber bulkhead</Description>
+            <Material Type="BULK">Fiber</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.055321199999999994</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BHC70-W</PartNumber>
+            <Description>2.104x.125thk lite-ply bulkhead</Description>
+            <Material Type="BULK">lite ply</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.055321199999999994</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BHC80-F</PartNumber>
+            <Description>2.474x.05thk fiber bulkhead</Description>
+            <Material Type="BULK">Fiber</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0649224</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BHC80-W</PartNumber>
+            <Description>2.474x.125thk lite-ply bulkhead</Description>
+            <Material Type="BULK">lite ply</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0649224</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BHT70-F</PartNumber>
+            <Description>2.175x.05thk fiber bulkhead</Description>
+            <Material Type="BULK">Fiber</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BHT70-W</PartNumber>
+            <Description>2.175x.125thk lite-ply bulkhead</Description>
+            <Material Type="BULK">lite ply</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BHT80-F</PartNumber>
+            <Description>2.558x.05thk fiber bulkhead</Description>
+            <Material Type="BULK">Fiber</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0649732</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BHT80-W</PartNumber>
+            <Description>2.558x.125 lite-ply bulkhead</Description>
+            <Material Type="BULK">lite ply</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0649732</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </BulkHead>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BMS20V2B</PartNumber>
+            <Description>V2 Boat-tail with 10mm bored hole</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.018542</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013208</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.041148000000000004</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BMS20V2C</PartNumber>
+            <Description>V2 Nose Cone w/bored hole</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.018542</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05715</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BMS50V2B</PartNumber>
+            <Description>V2 Boat-tail with bored BT5 hole</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.024637999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.017272</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BMS60V2B</PartNumber>
+            <Description>V2 Boat-tail with bored BT20 hole</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040386</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.02667</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.09398</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BMS60V2C</PartNumber>
+            <Description>V2 cone with 4 inch deep bored hole</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041401999999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040386</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.13335</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BMSV2BT1</PartNumber>
+            <Description>V2 Boat-tail with bored BT50 hole</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040386</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.028194</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.09398</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC20L</PartNumber>
+            <Description>Estes CYL-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.018542</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.035559999999999994</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC20N</PartNumber>
+            <Description>Estes Classic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.018542</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06858</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC20R</PartNumber>
+            <Description>Estes Classic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.018542</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC20Y</PartNumber>
+            <Description>Estes Classic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.018542</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.02667</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC30E</PartNumber>
+            <Description>Estes-CYL-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.019303999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018288</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.055625999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC30N</PartNumber>
+            <Description>BT30 Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.019303999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018288</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC55F</PartNumber>
+            <Description>V2 nose cone</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033528</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.032512</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.10668</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC55O61</PartNumber>
+            <Description>BT55 6:1 Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033528</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.032512</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.15239999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC5AW</PartNumber>
+            <Description>Estes Classic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013716</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.012954</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05715</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC5AX</PartNumber>
+            <Description>Estes-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013716</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.012954</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05511799999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC5E</PartNumber>
+            <Description>Estes Classic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013716</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.012954</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.03505199999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC5O51</PartNumber>
+            <Description>BT5 5:1 Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013716</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.012954</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.069088</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC5S</PartNumber>
+            <Description>Estes Classic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013716</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.012954</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BNC5W</PartNumber>
+            <Description>Estes Classic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013716</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.012954</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BOMARC</PartNumber>
+            <Description>Estes Citation BOMARC (bored hole)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033528</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.032512</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02286</ShoulderLength>
+            <Length Unit="m">0.10541</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>BTC55Z</PartNumber>
+            <Description>V2 Boat-tail with bored BT20 hole</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.033528</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.032512</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024637999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </Transition>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C188-34</PartNumber>
+            <Description>1.796x1.728x34 inch long T188 coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0438912</InsideDiameter>
+            <OutsideDiameter Unit="m">0.045618399999999996</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C188-4</PartNumber>
+            <Description>1.796x1.728x4 inch long T188 coupler</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0438912</InsideDiameter>
+            <OutsideDiameter Unit="m">0.045618399999999996</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C20-3</PartNumber>
+            <Description>.708x.666x3 inch long T20 coupler</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0169164</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C20-34</PartNumber>
+            <Description>.708x.666x34 inch long T20 coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0169164</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C204-34</PartNumber>
+            <Description>1.997x1.929x34 inch long T204 coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0489966</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0507238</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C204-4</PartNumber>
+            <Description>1.997x1.929x4 inch long T204 coupler</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0489966</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0507238</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C5-2</PartNumber>
+            <Description>.516x.474x2inch long T5 coupler</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0120396</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0131064</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C5-34</PartNumber>
+            <Description>.516x.474x34inch long T5 coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0120396</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0131064</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C50-1</PartNumber>
+            <Description>.948x.88x.034x1in long T50 coupler.</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.022352</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C50-34</PartNumber>
+            <Description>.948x.88x.034x34 T50 coupler stk.</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.022352</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C50-4</PartNumber>
+            <Description>.948x.88x.034x4in long T50 coupler.</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.022352</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C52H-34</PartNumber>
+            <Description>1.137x.977x34inch T52H coupler stock .080thk</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0248158</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0288798</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C52H-4</PartNumber>
+            <Description>1.137x.977x4 inch T52H coupler  .080thk</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0248158</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0288798</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C55-34</PartNumber>
+            <Description>1.280x1.212x34 inch long T55 coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.030784799999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.032512</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C55-4</PartNumber>
+            <Description>1.280x1.212x4 inch long T55 coupler</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.030784799999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.032512</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C60-34</PartNumber>
+            <Description>1.592x1.524x34 inch long T60 coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0387096</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404368</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C60-4</PartNumber>
+            <Description>1.592x1.524x4 inch long T60 coupler</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0387096</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404368</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C70-34</PartNumber>
+            <Description>2.172x2.104x34in T70 or T70H coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0534416</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055168800000000004</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C70-4</PartNumber>
+            <Description>2.172x2.104x4 in long T70 or T70H coupler</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0534416</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055168800000000004</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C80-34</PartNumber>
+            <Description>2.554x2.474x34in T80 or T80H coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.06283960000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06487159999999999</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C80-4</PartNumber>
+            <Description>2.554x2.474x4in long T80 or T80H coupler</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.06283960000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06487159999999999</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>C80-6</PartNumber>
+            <Description>2.554x2.474x6in T80 or T80H coupler stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.06283960000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06487159999999999</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </TubeCoupler>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CENBC107</PartNumber>
+            <Description>Centuri Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.13335</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CENBC79</PartNumber>
+            <Description>Centuri Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.020066</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018288</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06604</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CENBC89</PartNumber>
+            <Description>Centuri Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.02286</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021589999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.1397</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CENV2NC</PartNumber>
+            <Description>Centuri V2 nose cone w/ bored hole</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.042418</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040386</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.1397</Length>
+        </NoseCone>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR0550-F</PartNumber>
+            <Description>.946x.546x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013868400000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240284</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR0550-W</PartNumber>
+            <Description>.946x.546x.125thk lite ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.013868400000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240284</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR0555-F</PartNumber>
+            <Description>1.283x.546x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013868400000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR0560-F</PartNumber>
+            <Description>1.595x.546x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013868400000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040513</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2+3-F</PartNumber>
+            <Description>.348x.281x.05thk fiber</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0071374</InsideDiameter>
+            <OutsideDiameter Unit="m">0.008839199999999998</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2+4-F</PartNumber>
+            <Description>.420x.281x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0071374</InsideDiameter>
+            <OutsideDiameter Unit="m">0.010667999999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2+5-F</PartNumber>
+            <Description>.518x.281x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0071374</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013157199999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR20101-F</PartNumber>
+            <Description>3.896x.736x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09895839999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR20204-F</PartNumber>
+            <Description>2.042x.736x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0514096</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2050-F</PartNumber>
+            <Description>.946x.736x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240284</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2050-P</PartNumber>
+            <Description>.946x.736x.25thk paper</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240284</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2050-TW</PartNumber>
+            <Description>.946x.736x.250thk lite ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240284</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2050-W</PartNumber>
+            <Description>.946x.736x.125thk lite ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240284</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2055-F</PartNumber>
+            <Description>1.283x.736x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2055-W</PartNumber>
+            <Description>1.283x.736x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2060-F</PartNumber>
+            <Description>1.593x.736x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2060-W</PartNumber>
+            <Description>1.593x.736x.125thk lite ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2070-F</PartNumber>
+            <Description>2.178x.736x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055321199999999994</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR2080-F</PartNumber>
+            <Description>2.558x.736x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0649732</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR220-F</PartNumber>
+            <Description>.708x.250x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.00635</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR23-F</PartNumber>
+            <Description>.348x.250x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.00635</InsideDiameter>
+            <OutsideDiameter Unit="m">0.008839199999999998</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR24-F</PartNumber>
+            <Description>.420x.250x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.00635</InsideDiameter>
+            <OutsideDiameter Unit="m">0.010667999999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR25-F</PartNumber>
+            <Description>.516x.250x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.00635</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0131064</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR320-F</PartNumber>
+            <Description>.708x.376x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.009550399999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR34-F</PartNumber>
+            <Description>.420x.376x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.009550399999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.010667999999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR35-F</PartNumber>
+            <Description>.516x.376x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.009550399999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0131064</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR35-P</PartNumber>
+            <Description>.516x.376x.25thk paper (mini eng thrust ring)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.009550399999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0131064</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR420-F</PartNumber>
+            <Description>.708x.450x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.01143</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR45-F</PartNumber>
+            <Description>.516x.450x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.01143</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0131064</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR450-F</PartNumber>
+            <Description>.95x.450x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.01143</InsideDiameter>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR50101-F</PartNumber>
+            <Description>3.896x.978x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09895839999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5052H-F</PartNumber>
+            <Description>1.14x.980x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024891999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.028955999999999996</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5052H-P</PartNumber>
+            <Description>1.137x.977x.25thk paper</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0248158</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0288798</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5052H-P1</PartNumber>
+            <Description>1.137x.977x.50thk paper</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0248158</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0288798</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5055-F</PartNumber>
+            <Description>1.283x.978x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5055-W</PartNumber>
+            <Description>1.283x.978x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5060-F</PartNumber>
+            <Description>1.593x.978x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5060-W</PartNumber>
+            <Description>1.593x.978x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5070-F</PartNumber>
+            <Description>2.178x.978x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055321199999999994</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5070-W</PartNumber>
+            <Description>2.178x.978x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055321199999999994</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5080-F</PartNumber>
+            <Description>2.556x.978x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0649224</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5080-W</PartNumber>
+            <Description>2.556x.978x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0649224</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR50H55-W</PartNumber>
+            <Description>1.283x.990x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.025145999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR50H60-F</PartNumber>
+            <Description>1.593x.990x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.025145999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR50H70-W</PartNumber>
+            <Description>2.178x.990x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.025145999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055321199999999994</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR520-F</PartNumber>
+            <Description>.703x.546x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013868400000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0178562</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR520-P</PartNumber>
+            <Description>.708x.542x.25thk paper</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.013868400000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR520-W</PartNumber>
+            <Description>.703x.546x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.013868400000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0178562</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR52H55-F</PartNumber>
+            <Description>1.283x1.215x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.030861</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR52H60-F</PartNumber>
+            <Description>1.592x1.215x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.030861</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404368</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR52H80-W</PartNumber>
+            <Description>2.558x1.215x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.030861</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0649732</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR55101-F</PartNumber>
+            <Description>3.896x1.283x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09895839999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5560-F</PartNumber>
+            <Description>1.592x1.283x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404368</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5570-F</PartNumber>
+            <Description>2.217x1.283x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5570-W</PartNumber>
+            <Description>2.178x1.325x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.033655</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055321199999999994</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR5580-F</PartNumber>
+            <Description>2.558x1.283x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0649732</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR60101-F</PartNumber>
+            <Description>3.896x1.595x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09895839999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR6070-F</PartNumber>
+            <Description>2.217x1.595x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR6070-W</PartNumber>
+            <Description>2.175x1.637x.125thk lite-ply</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.041528999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055321199999999994</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>CR6080-F</PartNumber>
+            <Description>2.558x1.595x.05thk fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0649732</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <EngineBlock>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>EB13-P</PartNumber>
+            <Description>.516x.376x.25thk paper (mini eng thrust ring)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.009550399999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0131064</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>EB18-P</PartNumber>
+            <Description>.708x.542x.25thk paper (fits T20 tube)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.013868400000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>EB24-P</PartNumber>
+            <Description>.946x.736x.25thk paper (fits T50 tube)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240284</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>EB29-P</PartNumber>
+            <Description>1.137x.977x.50thk paper (fits T52H)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0248158</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0288798</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </EngineBlock>
+        <LaunchLug>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>LL14-300</PartNumber>
+            <Description>0.316x0.280x.018x34  1/4 inch Launch lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.007112</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0080264</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>LL14-3400</PartNumber>
+            <Description>0.316x0.280x.018x34  1/4 inch Launch lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.007112</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0080264</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>LL18-125</PartNumber>
+            <Description>1/8  x 1.25 inch LL</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.004064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0042926</OutsideDiameter>
+            <Length Unit="m">0.03175</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>LL316-1200</PartNumber>
+            <Description>3/16 x 12 inch LL</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0054356</InsideDiameter>
+            <OutsideDiameter Unit="m">0.006096</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>LL316-200</PartNumber>
+            <Description>3/16 x 2 inch LL</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0055626</InsideDiameter>
+            <OutsideDiameter Unit="m">0.006096</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T104-34</PartNumber>
+            <Description>1.040x1.00x.020 x 34 Centuri ST-10</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T14LL-34</PartNumber>
+            <Description>0.316x0.280x.018x34  1/4 inch Launch lug stock</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.007112</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0080264</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T188-34</PartNumber>
+            <Description>1.880x1.800x.040x34inch long  (Aerotech size)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.04572</InsideDiameter>
+            <OutsideDiameter Unit="m">0.047751999999999996</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T2-34</PartNumber>
+            <Description>0.246x0.220x.013x34</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.005588</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0062483999999999994</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T20-34</PartNumber>
+            <Description>.736x.710x.013x34 Estes 18mm</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T20-EMT</PartNumber>
+            <Description>.736x.710x.013x2.75 Motor Tube</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T204-34</PartNumber>
+            <Description>2.024x2.0x.021x34 Centuri ST-20</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0514096</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T20Q-34</PartNumber>
+            <Description>.787x.748x.039x34 MPC/Quest T20</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0189992</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0199898</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T2PLUS-34</PartNumber>
+            <Description>0.281x0.255x.013x34 (fits over T2)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.006477</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0071374</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T38-34</PartNumber>
+            <Description>1.635x1.525x.055x34 38mm Motor Mount size</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041528999999999996</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T4+34</PartNumber>
+            <Description>.478x.452x.013x34 slips over T4</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0114808</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0121412</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T4-34</PartNumber>
+            <Description>.448x.432x.013x34 Apogee micro</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0109728</InsideDiameter>
+            <OutsideDiameter Unit="m">0.011379199999999999</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T5-34</PartNumber>
+            <Description>.544x.518x.013x34 Estes mini A</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.013157199999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013817600000000001</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T5-9</PartNumber>
+            <Description>.544x.518 x.013 x9  Plain Kraft</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.013157199999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013817600000000001</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T50-34</PartNumber>
+            <Description>.976x.950x.013x34  24mm</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T50-EMT</PartNumber>
+            <Description>.976x.950x.013x2.75 Motor Tube</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T50F-MT</PartNumber>
+            <Description>1.000x.950x.025x2.75  Foil Motor Tube</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0254</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T50FE-MT</PartNumber>
+            <Description>1.000x.950x.025x3.75 Foil  Tube (E motors)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0254</OutsideDiameter>
+            <Length Unit="m">0.09525</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T50H-34</PartNumber>
+            <Description>. 990 x.950 x.020 x34  Heavy Wall</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.025145999999999998</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T50H-EMT</PartNumber>
+            <Description>.990x.950x.020x2.75 Motor Tube</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.025145999999999998</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T50HE-MT</PartNumber>
+            <Description>.990x.950x.020x3.75 Motor Tube (E motors)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.025145999999999998</OutsideDiameter>
+            <Length Unit="m">0.09525</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T50MF-34</PartNumber>
+            <Description>1.000x0.950x.025x34 metal foil lined</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0254</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T52H-34</PartNumber>
+            <Description>1.210x1.140x.035x34  29mm Motor Mount size</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030733999999999997</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T55-34</PartNumber>
+            <Description>1.325x1.283x.021</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T60-34</PartNumber>
+            <Description>1.637x1.595x.021</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T70-34</PartNumber>
+            <Description>2.217x2.175x.021x34</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T70H-34</PartNumber>
+            <Description>2.245x2.175x.035x34in long (white Heavy wall)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.057023</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T80-34</PartNumber>
+            <Description>2.600x2.558x.021x34in long</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0649732</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T80H-34</PartNumber>
+            <Description>2.640x2.558x.041x34in long (white Heavy wall)</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0649732</InsideDiameter>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>T908-34</PartNumber>
+            <Description>.908x.865x.022x34 Centuri ST-8</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.8635999999999999</Length>
+        </BodyTube>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA2050</PartNumber>
+            <Description>Transition   T20 to T50  2 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.018542</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024637999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA2050A</PartNumber>
+            <Description>Transition   T20 to T50  1 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.018542</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024637999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA2055</PartNumber>
+            <Description>Transition   T20 to T55  1.5 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.018542</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.032512</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA2060</PartNumber>
+            <Description>Transition   T20 to T80  0.84 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.018542</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.06604</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.06477</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.021335999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA5055</PartNumber>
+            <Description>Transition   T50 to T55  1 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024637999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.032512</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA5055L</PartNumber>
+            <Description>Transiition  T50 to T55   1.5 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024637999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.032512</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA5060</PartNumber>
+            <Description>Transition   T50 to T60  2 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024637999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040386</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA520</PartNumber>
+            <Description>Transition   T5 to T20  0.78 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013716</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.012954</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.018542</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019812</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA550</PartNumber>
+            <Description>Transition   T5 to T50  1 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013716</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.012954</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024637999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA555</PartNumber>
+            <Description>Transiition   T5 to T55  2.75 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013716</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.012954</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.032512</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA5560</PartNumber>
+            <Description>Transition   T55 to T60  1 long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.032512</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040386</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA5560A</PartNumber>
+            <Description>Transition    T55 to T60  1.3 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.032512</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.019049999999999997</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040386</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.019049999999999997</AftShoulderLength>
+            <Length Unit="m">0.03302</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA6070</PartNumber>
+            <Description>Transition   T60 to T70  1.75 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040386</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.015239999999999998</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.056133999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05511799999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.015239999999999998</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA6080</PartNumber>
+            <Description>Transition   T60 to T80   2.25 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040386</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.03175</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.06604</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.06477</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.038099999999999995</AftShoulderLength>
+            <Length Unit="m">0.05715</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>BalsaMachining.com</Manufacturer>
+            <PartNumber>TA7080</PartNumber>
+            <Description>Transition T70 to T80 2 in long</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.056133999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05511799999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.035559999999999994</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.06604</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.06477</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.035559999999999994</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+    </Components>
+</OpenRocketComponent>
diff --git a/core/resources/datafiles/presets/fliskits.orc b/core/resources/datafiles/presets/fliskits.orc
new file mode 100644 (file)
index 0000000..3d85d48
--- /dev/null
@@ -0,0 +1,1799 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<OpenRocketComponent>
+    <Version>0.1</Version>
+    <Materials>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Balsa</Name>
+            <Density>128.1477072</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fiber</Name>
+            <Density>656.7569994</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Light Ply</Name>
+            <Density>0.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Paper</Name>
+            <Density>90</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Paper</Name>
+            <Density>671.1787601020637</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spiral-Wound Paper/Glassine</Name>
+            <Density>1047.6648350683759</Density>
+            <Type>BULK</Type>
+        </Material>
+    </Materials>
+    <Components>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-101-0125</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.09895839999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1000252</OutsideDiameter>
+            <Length Unit="m">0.03175</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-2-1475</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0024097094635</Mass>
+            <InsideDiameter Unit="m">0.005588</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0062483999999999994</OutsideDiameter>
+            <Length Unit="m">0.37465</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-2.5-0112</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.006477</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0071374</OutsideDiameter>
+            <Length Unit="m">0.028575</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-2.5-0195</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.006477</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0071374</OutsideDiameter>
+            <Length Unit="m">0.04953</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-2.5-0518</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.006477</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0071374</OutsideDiameter>
+            <Length Unit="m">0.131572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-2.5-1475</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.006477</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0071374</OutsideDiameter>
+            <Length Unit="m">0.37465</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-20-0275</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0012473790164</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-20-0862</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0039122341878</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.21894799999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-20-12</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0054431084352</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-20-18</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0081646626528</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-3-0195</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.008864599999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <Length Unit="m">0.04953</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-3-0240</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.008864599999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <Length Unit="m">0.06095999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-3-06</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.008864599999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-3-1475</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.008864599999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <Length Unit="m">0.37465</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-4-06</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.010718799999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.011379199999999999</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-4-1475</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <InsideDiameter Unit="m">0.010718799999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.011379199999999999</OutsideDiameter>
+            <Length Unit="m">0.37465</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-5-0175</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">5.953399851E-4</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-5-0529</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">5.953399851E-4</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.13436599999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-5-08</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0028633018331</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-5-0944</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.239776</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-5-18</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0062085455589</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-50-0275</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0016442723398</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-50-04</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0023813599404</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-50-09</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0053580598659</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-50-18</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0107161197318</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-55-0275</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0029200008793</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-55-0850</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.008986798822699999</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.21589999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-55-18</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0190508795232</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-60-004</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">5.953399851E-4</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.01016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-60-0375</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.09525</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-60-0850</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.013607771087999999</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.21589999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-60-1150</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0173782576603</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.29209999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-60-18</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.027215542175999998</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-69-04</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.0080796140835</Mass>
+            <InsideDiameter Unit="m">0.054076599999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055143399999999995</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-70-09</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>BT-70-175</PartNumber>
+            <Material Type="BULK">Spiral-Wound Paper/Glassine</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.4445</Length>
+        </BodyTube>
+        <TubeCoupler>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CPL-20-0112</PartNumber>
+            <Description>Tube Coupler /.71 x 1.125 in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">7.654371237E-4</Mass>
+            <InsideDiameter Unit="m">0.01651</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.028575</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CPL-50-015</PartNumber>
+            <Description>Tube Coupler/.95 x 1.5 in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0014458256781</Mass>
+            <InsideDiameter Unit="m">0.023368</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024104599999999997</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CPL-55-013</PartNumber>
+            <Description>Tube Coupler /1.28 x 1.3 in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0024947580328</Mass>
+            <InsideDiameter Unit="m">0.03175</InsideDiameter>
+            <OutsideDiameter Unit="m">0.032512</OutsideDiameter>
+            <Length Unit="m">0.03302</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CPL-60-015</PartNumber>
+            <Description>Tube Coupler /1.6 x 1.5 in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0035153408644</Mass>
+            <InsideDiameter Unit="m">0.03937</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CPL-70-0125</PartNumber>
+            <Description>Tube Coupler /2.18 x 1.25 in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.003968933234</Mass>
+            <InsideDiameter Unit="m">0.053721000000000005</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.03175</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CPL-70-4</PartNumber>
+            <Description>Tube Coupler /2.18 x 4.0 in</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.012700586348799999</Mass>
+            <InsideDiameter Unit="m">0.053721000000000005</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-2.5-3</PartNumber>
+            <Description>Centers a BT-2.5 inside a BT-3</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0071374</InsideDiameter>
+            <OutsideDiameter Unit="m">0.008864599999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-2.5-4</PartNumber>
+            <Description>Centers a BT-2.5 inside a BT-4, with a notch for shock line.</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0071374</InsideDiameter>
+            <OutsideDiameter Unit="m">0.010718799999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-2.5-5</PartNumber>
+            <Description>Centers a BT-2.5 inside a BT-5, with a notch for shock line.</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0071374</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013081</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-20-55</PartNumber>
+            <Description>BT20 - BT55 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-20-60</PartNumber>
+            <Description>BT20 - BT60 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040513</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-20-70</PartNumber>
+            <Description>BT20 - BT70 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-3-4</PartNumber>
+            <Description>Centers a BT-3 inside a BT-4</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.009524999999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.010718799999999999</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-3-5</PartNumber>
+            <Description>Centers a BT-3 inside a BT-5, with a notch for shock line.</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.009524999999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013081</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-4-5</PartNumber>
+            <Description>Centers a BT-4 inside a BT-5</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.011379199999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013081</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-5-50</PartNumber>
+            <Description>BT5 - BT50 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0137414</InsideDiameter>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-5-55</PartNumber>
+            <Description>BT5 - BT55 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0137414</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-50-55</PartNumber>
+            <Description>BT50 - BT55 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024790399999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-50-60</PartNumber>
+            <Description>BT50 - BT60 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024790399999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040513</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-50-70</PartNumber>
+            <Description>BT50 - BT70 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024790399999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-55-60</PartNumber>
+            <Description>BT55 - BT60 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.033655</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040513</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-55-70</PartNumber>
+            <Description>BT55 - BT70 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.033655</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRF-60-70</PartNumber>
+            <Description>BT60 - BT70 /.05 thk Fiber</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0415798</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRP-20-50</PartNumber>
+            <Description>BT20 - BT50 /.25 thk Paper</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0186944</InsideDiameter>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>CRP-5-20</PartNumber>
+            <Description>BT5 - BT20 /.25 thk Paper</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0137414</InsideDiameter>
+            <OutsideDiameter Unit="m">0.018033999999999998</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <EngineBlock>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>EB-2.5</PartNumber>
+            <Description>MMX Engine Block for BT-2.5</Description>
+            <Material Type="BULK">Light Ply</Material>
+            <InsideDiameter Unit="m">0.00508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.005588</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>EB-20-0025</PartNumber>
+            <Description>Engine Block 18mm for BT20/ .25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.013640000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.018033999999999998</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>EB-5-0025</PartNumber>
+            <Description>Engine Block 13mm for BT5/ .25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.01117</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013157</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>EB-50-0025</PartNumber>
+            <Description>Engine Block 24mm for BT50/ .25in</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.018510000000000002</InsideDiameter>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <LaunchLug>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>LL-0-0025</PartNumber>
+            <Description>MMX .1in x .25in Launch Lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.002286</InsideDiameter>
+            <OutsideDiameter Unit="m">0.00254</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>LL-0-02</PartNumber>
+            <Description>MMX .1in x 2in Launch Lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.002286</InsideDiameter>
+            <OutsideDiameter Unit="m">0.00254</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>LL-1-1</PartNumber>
+            <Description>1/8in x 1in Launch Lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.004318</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004572</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>LL-1-2</PartNumber>
+            <Description>1/8in x 2in Launch Lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.004318</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004572</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>LL-1-6</PartNumber>
+            <Description>1/8in x 6in Launch Lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.004318</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004572</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>LL-2-0050</PartNumber>
+            <Description>MMX .1in x .5in Launch Lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.002286</InsideDiameter>
+            <OutsideDiameter Unit="m">0.00254</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>LL-2-2</PartNumber>
+            <Description>3/16in x 2in Launch Lug</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.005588</InsideDiameter>
+            <OutsideDiameter Unit="m">0.006096</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-2.5-0075</PartNumber>
+            <Description>Balsa Nose Block BT-2.5</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0063754</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-20-012</PartNumber>
+            <Description>Nose Block Balsa (BT-20/1.25in L)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.018033999999999998</OutsideDiameter>
+            <Length Unit="m">0.03175</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-3-0075</PartNumber>
+            <Description>Balsa Nose Block BT-3</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.008762999999999998</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-4-01</PartNumber>
+            <Description>Balsa Nose Block BT-4</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.010617199999999999</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-5-01</PartNumber>
+            <Description>Nose Block Balsa (BT-5/1in L)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.013081</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-50-015</PartNumber>
+            <Description>Nose Block Balsa (BT-50/1.5in L)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-55-017</PartNumber>
+            <Description>Nose Block Balsa (BT-55/1.75in L)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-60-02</PartNumber>
+            <Description>Nose Block Balsa (BT-60/2in L)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.040513</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NBB-70-4</PartNumber>
+            <Description>Nose Block Balsa (BT-70/4in L)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BulkHead>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-2-005-P</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0062483999999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.005588</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.005588</ShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-2-01-O</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0062483999999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.005588</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.005588</ShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-2.5AD</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0071374</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0063754</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.029159199999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-2.5CC</PartNumber>
+            <Description>Special - Command Capsule? not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0103886</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0063754</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0217424</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-2.5HJ</PartNumber>
+            <Description>Special - Honest John -not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0091694</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0063754</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0438658</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-2.5P</PartNumber>
+            <Description>Special - Blunt -not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0086868</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0063754</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0121158</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-2.5S</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0071374</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0063754</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0223774</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-2.5V</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0071374</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0063754</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0194056</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-20AM</PartNumber>
+            <Description>Rounded Tip -not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.017983199999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-20B</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.017983199999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.007873999999999999</ShoulderLength>
+            <Length Unit="m">0.042671999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-20R</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.017983199999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.072898</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-20SC</PartNumber>
+            <Description>-not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.03175</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.017983199999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015875</ShoulderLength>
+            <Length Unit="m">0.097282</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-3AD</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.008762999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0388366</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-3AM</PartNumber>
+            <Description>Special - conical w/ rounded tip -not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.008762999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.030124399999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-3HJ</PartNumber>
+            <Description>Special - Honest John -not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0122174</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.008762999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.058369199999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-3K</PartNumber>
+            <Description>Downscale of PNC-80K</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.008762999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0300482</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-3S</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.008762999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.0298704</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-3SL</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.008762999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.039878</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-4AD</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.011379199999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.010591799999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.006172199999999999</ShoulderLength>
+            <Length Unit="m">0.0464058</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-4B</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.011379199999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.010591799999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.006172199999999999</ShoulderLength>
+            <Length Unit="m">0.025984199999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-4S</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.011379199999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.010591799999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.006172199999999999</ShoulderLength>
+            <Length Unit="m">0.036169599999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-5-0125-P</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">4.2524284649999997E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0130302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.03175</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-50HJ</PartNumber>
+            <Description>Special - Honest John -not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0240792</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.15239999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-50J</PartNumber>
+            <Description>Special shape -not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0240792</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.034798</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-50X</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0240792</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08255</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-50Y</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0240792</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009398</ShoulderLength>
+            <Length Unit="m">0.110998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-55AD</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.032537399999999994</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009398</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-55DW</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.032537399999999994</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.022098</ShoulderLength>
+            <Length Unit="m">0.065024</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-55NM</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.032537399999999994</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009398</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-5AX</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0130302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.05715</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-5DW</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0130302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.026238199999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-5K</PartNumber>
+            <Description>Downscale of PNC-80K</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0130302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.0433324</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-5ML</PartNumber>
+            <Description>Special shape -not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0130302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009398</ShoulderLength>
+            <Length Unit="m">0.010718799999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-5S</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">4.535923696E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0130302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-5V</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">3.685438003E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0130302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-60AD</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017293209091</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0404622</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.019049999999999997</ShoulderLength>
+            <Length Unit="m">0.156718</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-60DW</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009638837854</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0404622</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015747999999999998</ShoulderLength>
+            <Length Unit="m">0.079248</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-60L</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009638837854</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0404622</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015747999999999998</ShoulderLength>
+            <Length Unit="m">0.079248</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-60RH</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.013324275856999999</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0404622</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015747999999999998</ShoulderLength>
+            <Length Unit="m">0.10033</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-70AD</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.034869913413</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0551942</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.211582</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-70AJ</PartNumber>
+            <Description>Special shape-not properly simulated</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.024097094635</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0551942</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.10794999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>NCB-70DW</PartNumber>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.022963113711000002</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0551942</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+        </NoseCone>
+        <Streamer>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>STC-2-36</PartNumber>
+            <Description>Streamer Crepe Paper</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">0.4572</Length>
+            <Width Unit="m">0.0508</Width>
+            <Thickness Unit="m">2.54E-5</Thickness>
+        </Streamer>
+        <Streamer>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>STD-440</PartNumber>
+            <Description>Competition Streamer 4in x 40in (Draft Paper)</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">1.016</Length>
+            <Width Unit="m">0.1016</Width>
+            <Thickness Unit="m">2.54E-5</Thickness>
+        </Streamer>
+        <Streamer>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>STD-660</PartNumber>
+            <Description>Competition Streamer 6in x 60in (Draft Paper)</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">1.524</Length>
+            <Width Unit="m">0.15239999999999998</Width>
+            <Thickness Unit="m">2.54E-5</Thickness>
+        </Streamer>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-2.5-002 (R)</PartNumber>
+            <Description>Balsa Transition BT-2.5 to BT-3 (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.009524999999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.008864599999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0071374</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.005588</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0055626</AftShoulderLength>
+            <Length Unit="m">0.00508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-2.53-002</PartNumber>
+            <Description>Balsa Transition BT-2.5 to BT-3</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0071374</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.005588</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0055626</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.009524999999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.008864599999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.00508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-2.53-0037</PartNumber>
+            <Description>Balsa Transition BT-2.5 to BT-3</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0071374</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.005588</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0055626</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.009524999999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.008864599999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.01016</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-2.53-0037 (R)</PartNumber>
+            <Description>Balsa Transition BT-2.5 to BT-3(Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.009524999999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.008864599999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0071374</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.005588</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0055626</AftShoulderLength>
+            <Length Unit="m">0.01016</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-2.54-004</PartNumber>
+            <Description>Balsa Transition BT-2.5 to BT-4</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0071374</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.005588</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0055626</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.011379199999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.010718799999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.01016</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-2.54-004 (R)</PartNumber>
+            <Description>Balsa Transition BT-2.5 to BT-4 (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.011379199999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.010718799999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0071374</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.005588</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0055626</AftShoulderLength>
+            <Length Unit="m">0.01016</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-2.55-0037</PartNumber>
+            <Description>Balsa Transition BT-2.5 to BT-5</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0071374</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.005588</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0055626</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0137414</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.009524999999999999</AftShoulderLength>
+            <Length Unit="m">0.009524999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-2.55-0037 (R)</PartNumber>
+            <Description>Balsa Transition BT-2.5 to BT-5(Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0137414</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.009524999999999999</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0071374</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.005588</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0055626</AftShoulderLength>
+            <Length Unit="m">0.009524999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-22.5-0031</PartNumber>
+            <Description>Balsa Transition BT-2 to BT-2.5</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0062483999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.005588</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0055626</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0071374</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.006477</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.0079375</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-22.5-0031 (R)</PartNumber>
+            <Description>Balsa Transition BT-2 to BT-2.5 (Reversed) </Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0071374</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.006477</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0062483999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.005588</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0055626</AftShoulderLength>
+            <Length Unit="m">0.0079375</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-23-002</PartNumber>
+            <Description>Balsa Transition BT-2 to BT-3</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0062483999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.005588</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0055626</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.009524999999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.008864599999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.00508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-23-002 (R)</PartNumber>
+            <Description>Balsa Transition BT-2 to BT-3 (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.009524999999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.008864599999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0062483999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.005588</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0055626</AftShoulderLength>
+            <Length Unit="m">0.00508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-34-0037</PartNumber>
+            <Description>Balsa Transition BT-3 to BT-4</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.009524999999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.008762999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.011379199999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.010718799999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.009524999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-34-0037 (R)</PartNumber>
+            <Description>Balsa Transition BT-3 to BT-4 (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.011379199999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.010718799999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.009524999999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.008762999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.009524999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-35-004</PartNumber>
+            <Description>Balsa Transition BT-3 to BT-5</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.009524999999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.008762999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0137414</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0080264</AftShoulderLength>
+            <Length Unit="m">0.01016</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-35-004 (R)</PartNumber>
+            <Description>Balsa Transition BT-3 to BT-5 (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0137414</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0080264</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.009524999999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.008762999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.01016</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-45-0037</PartNumber>
+            <Description>Balsa Transition BT-4 to BT-5</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.011379199999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.010718799999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0137414</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0080264</AftShoulderLength>
+            <Length Unit="m">0.009524999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-45-0037 (R)</PartNumber>
+            <Description>Balsa Transition BT-4 to BT-5 (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0137414</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0080264</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.011379199999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.010718799999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.00635</AftShoulderLength>
+            <Length Unit="m">0.009524999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5055-015</PartNumber>
+            <Description>Balsa Adapter 1.5in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024637999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033528</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.032512</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5055-015 (R)</PartNumber>
+            <Description>Balsa Adapter 1.5in (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033528</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.032512</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024637999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5060-02</PartNumber>
+            <Description>Balsa Adapter 1.5in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024637999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040386</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5060-02 (R)</PartNumber>
+            <Description>Balsa Adapter 1.5in (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040386</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024637999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5070-015</PartNumber>
+            <Description>Balsa Adapter 1.5in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024637999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.056133999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05511799999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5070-015 (R)</PartNumber>
+            <Description>Balsa Adapter 1.5in (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.056133999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05511799999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024637999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-520-075</PartNumber>
+            <Description>Balsa Adapter .75in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013716</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.012954</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.018542</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-520-075 (R)</PartNumber>
+            <Description>Balsa Adapter .75in (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.018542</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013716</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.012954</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-550-100</PartNumber>
+            <Description>Balsa Adapter 1in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013716</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.012954</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024637999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-550-100 (R)</PartNumber>
+            <Description>Balsa Adapter 1in (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024637999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013716</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.012954</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5560-01</PartNumber>
+            <Description>Balsa Adapter 1in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033528</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.032512</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040386</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5560-01 (R)</PartNumber>
+            <Description>Balsa Adapter 1in (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040386</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033528</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.032512</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5570-03</PartNumber>
+            <Description>Balsa Adapter 3in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033528</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.032512</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.056133999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05511799999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-5570-03 (R)</PartNumber>
+            <Description>Balsa Adapter 3in (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.056133999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05511799999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033528</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.032512</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-6070-02</PartNumber>
+            <Description>Balsa Adapter 2in</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041401999999999994</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040386</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.056133999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05511799999999999</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>FlisKits</Manufacturer>
+            <PartNumber>TAB-6070-02 (R)</PartNumber>
+            <Description>Balsa Adapter 2in (Reversed)</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.056133999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05511799999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0254</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041401999999999994</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040386</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0254</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+    </Components>
+</OpenRocketComponent>
diff --git a/core/resources/datafiles/presets/giantleaprocketry.orc b/core/resources/datafiles/presets/giantleaprocketry.orc
new file mode 100644 (file)
index 0000000..3fe782d
--- /dev/null
@@ -0,0 +1,722 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<OpenRocketComponent>
+    <Version>0.1</Version>
+    <Materials>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Birch</Name>
+            <Density>680.7846945000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cardboard</Name>
+            <Density>688.7939262000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Kraft phenolic</Name>
+            <Density>958.7050344900001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polycarbonate</Name>
+            <Density>1199.7829086600002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Rip stop nylon</Name>
+            <Density>0.06684999999999999</Density>
+            <Type>SURFACE</Type>
+        </Material>
+    </Materials>
+    <Components>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-1.145</PartNumber>
+            <Description>29mm BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.029082999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.032131</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-1.525</PartNumber>
+            <Description>38mm BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0417068</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-1.525-L</PartNumber>
+            <Description>38mm BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041909999999999996</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-2.152</PartNumber>
+            <Description>54mm BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.054661</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0576834</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-2.152-L</PartNumber>
+            <Description>54mm BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.054661</InsideDiameter>
+            <OutsideDiameter Unit="m">0.057658</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-2.56</PartNumber>
+            <Description>2.56 BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.065024</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06807200000000001</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-3.00</PartNumber>
+            <Description>3.00 BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0762</InsideDiameter>
+            <OutsideDiameter Unit="m">0.077851</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-3.00-L</PartNumber>
+            <Description>3.00 BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0762508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.079375</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-3.90</PartNumber>
+            <Description>3.90 BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.09906000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.101854</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-3.90-L</PartNumber>
+            <Description>3.90 BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.09906000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.102108</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-6.00</PartNumber>
+            <Description>6.00 BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.1524</InsideDiameter>
+            <OutsideDiameter Unit="m">0.155575</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>B-7.50</PartNumber>
+            <Description>7.50 BT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.19080000000000003</InsideDiameter>
+            <OutsideDiameter Unit="m">0.19507</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BulkHead>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>BH-2.15</PartNumber>
+            <Description>2.15 in. Bulkhead</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.05461</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>BH-2.56</PartNumber>
+            <Description>2.56 in. Bulkhead</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>BH-3.00</PartNumber>
+            <Description>3.00 in. Bulkhead</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0762</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>BH-3.90</PartNumber>
+            <Description>3.90 in. Bulkhead</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.09906000000000001</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>BH-6.00</PartNumber>
+            <Description>6.00 in. Bulkhead</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.1524</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>BH-7.51</PartNumber>
+            <Description>7.51 in. Bulkhead</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.1908048</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </BulkHead>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-2.15</PartNumber>
+            <Description>2.15 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.051308</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05461</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-2.15-L</PartNumber>
+            <Description>2.15 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.051562</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05461</OutsideDiameter>
+            <Length Unit="m">0.9271</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-2.56</PartNumber>
+            <Description>2.56 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.062738</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-2.56-L</PartNumber>
+            <Description>2.56 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.062738</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.9271</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-3.00</PartNumber>
+            <Description>3.0 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.07366</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0762</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-3.00-L</PartNumber>
+            <Description>3.0 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.07366</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0762</OutsideDiameter>
+            <Length Unit="m">0.9271</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-3.90</PartNumber>
+            <Description>3.9 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.096266</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906000000000001</OutsideDiameter>
+            <Length Unit="m">0.1778</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-3.90-L</PartNumber>
+            <Description>3.9 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.096266</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906000000000001</OutsideDiameter>
+            <Length Unit="m">0.9271</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-6.007-L</PartNumber>
+            <Description>6.0 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.14859</InsideDiameter>
+            <OutsideDiameter Unit="m">0.15257779999999999</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>C-7.512-L</PartNumber>
+            <Description>7.5 CT</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.186182</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1908048</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </TubeCoupler>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-2.56-54</PartNumber>
+            <Description>CR 2.56-54mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.054</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05969</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-2.56/29</PartNumber>
+            <Description>CR 2.56/29mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.029</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.00381</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-2.56/38</PartNumber>
+            <Description>CR 2.56/38mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.038</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.00381</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-2.56/54</PartNumber>
+            <Description>CR 2.56/54mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.054</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.00381</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-3.00/29</PartNumber>
+            <Description>CR 3.00/29mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.029</InsideDiameter>
+            <OutsideDiameter Unit="m">0.07625099999999999</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-3.00/38</PartNumber>
+            <Description>CR 3.00/38mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.038</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0762508</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-3.00/54</PartNumber>
+            <Description>CR 3.00/54mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.054</InsideDiameter>
+            <OutsideDiameter Unit="m">0.07625099999999999</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-3.90/29</PartNumber>
+            <Description>CR 3.90/29mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.029</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906000000000001</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-3.90/38</PartNumber>
+            <Description>CR 3.90/38mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.038</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906000000000001</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-3.90/54</PartNumber>
+            <Description>CR 3.90/54mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.054</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906000000000001</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-3.90/76</PartNumber>
+            <Description>CR 3.90/76mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.076</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906000000000001</OutsideDiameter>
+            <Length Unit="m">0.00508</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-38/29</PartNumber>
+            <Description>CR 38/29mm</Description>
+            <Material Type="BULK">Cardboard</Material>
+            <InsideDiameter Unit="m">0.029</InsideDiameter>
+            <OutsideDiameter Unit="m">0.038</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-54/38</PartNumber>
+            <Description>CR 54/38mm</Description>
+            <Material Type="BULK">Cardboard</Material>
+            <InsideDiameter Unit="m">0.038</InsideDiameter>
+            <OutsideDiameter Unit="m">0.054</OutsideDiameter>
+            <Length Unit="m">0.017779999999999997</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-6.00/38</PartNumber>
+            <Description>CR 6.00/38mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.038</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1524</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-6.00/54</PartNumber>
+            <Description>CR 6.00/54mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.054</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1524</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-6.00/76</PartNumber>
+            <Description>CR 6.00/76mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.076</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1524</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-6.00/98</PartNumber>
+            <Description>CR 6.00/98mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.098</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1524</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-7.50/54</PartNumber>
+            <Description>CR 7.50/54mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.054</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1905</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-7.50/76</PartNumber>
+            <Description>CR 7.50/76mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.076</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1905</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>CR-7.50/98</PartNumber>
+            <Description>CR 7.50/98mm</Description>
+            <Material Type="BULK">Birch</Material>
+            <InsideDiameter Unit="m">0.098</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1905</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>DY/MAG 1.5 x 48</PartNumber>
+            <Description>38mm Dynawind + Magnaframe Airframe</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.042418</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>DY/MAG 2.1 x 48</PartNumber>
+            <Description>54mm Dynawind + Magnaframe Airframe</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.054661</InsideDiameter>
+            <OutsideDiameter Unit="m">0.058674000000000004</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>DY/MAG 2.5 x 48</PartNumber>
+            <Description>2.56 Dynawind + Magnaframe Airframe</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.065024</InsideDiameter>
+            <OutsideDiameter Unit="m">0.069088</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>DY/MAG 3.0 x 48</PartNumber>
+            <Description>75mm Dynawind + Magnaframe Airframe</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0762</InsideDiameter>
+            <OutsideDiameter Unit="m">0.08077200000000001</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>DY/MAG 3.9 x 48</PartNumber>
+            <Description>98mm Dynawind + Magnaframe Airframe</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.09906000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.103632</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>DY/MAG 6.0 x 48</PartNumber>
+            <Description>6.0 Dynawind + Magnaframe Airframe</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.1524</InsideDiameter>
+            <OutsideDiameter Unit="m">0.15747999999999998</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>DY/PH 7.5 x 48</PartNumber>
+            <Description>7.5 Dynawind + Magnaframe Airframe</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.19080000000000003</InsideDiameter>
+            <OutsideDiameter Unit="m">0.19659600000000002</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <LaunchLug>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>LL</PartNumber>
+            <Description>ACME Launch Lug</Description>
+            <InsideDiameter Unit="m">0.01016</InsideDiameter>
+            <OutsideDiameter Unit="m">0.012700000000000001</OutsideDiameter>
+            <Length Unit="m">0.025400000000000002</Length>
+        </LaunchLug>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>MAG 1.5 x 48</PartNumber>
+            <Description>38mm Magnaframe Tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.042164</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>MAG 2.1 x 48</PartNumber>
+            <Description>54mm Magnaframe Tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.054661</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05842</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>MAG 2.5 x 48</PartNumber>
+            <Description>2.56  Magnaframe Tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.065024</InsideDiameter>
+            <OutsideDiameter Unit="m">0.068834</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>MAG 3.0 x 48</PartNumber>
+            <Description>75mm  Magnaframe Tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0762</InsideDiameter>
+            <OutsideDiameter Unit="m">0.08001000000000001</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>MAG 3.9 x 48</PartNumber>
+            <Description>98mm  Magnaframe Tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.09906000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.10287</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>MAG 6.0 x48</PartNumber>
+            <Description>6.0  Magnaframe Tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.1524</InsideDiameter>
+            <OutsideDiameter Unit="m">0.15621000000000002</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <NoseCone>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>NC-2.56</PartNumber>
+            <Description>2.56 in. Nosecone</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0</ShoulderLength>
+            <Length Unit="m">0.22860000000000003</Length>
+            <Thickness Unit="m">0.001778</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>NC-3.00</PartNumber>
+            <Description>3.00 in. Nosecone</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0762</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0</ShoulderLength>
+            <Length Unit="m">0.28575</Length>
+            <Thickness Unit="m">0.001778</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>NC-3.90</PartNumber>
+            <Description>3.90 in. Nosecone</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.09906000000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0</ShoulderLength>
+            <Length Unit="m">0.41910000000000003</Length>
+            <Thickness Unit="m">0.002032</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>NC-38</PartNumber>
+            <Description>38mm Nosecone</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.038</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0</ShoulderLength>
+            <Length Unit="m">0.20320000000000002</Length>
+            <Thickness Unit="m">0.0043180000000000015</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>NC-54</PartNumber>
+            <Description>54mm Nosecone</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.054</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0</ShoulderLength>
+            <Length Unit="m">0.27940000000000004</Length>
+            <Thickness Unit="m">0.0022860000000000003</Thickness>
+        </NoseCone>
+        <BodyTube>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>PH 7.5 x 48</PartNumber>
+            <Description>7.5  Magnaframe Tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.19080000000000003</InsideDiameter>
+            <OutsideDiameter Unit="m">0.19481800000000002</OutsideDiameter>
+            <Length Unit="m">1.2192</Length>
+        </BodyTube>
+        <LaunchLug>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>RG</PartNumber>
+            <Description>ACME Rail Guide</Description>
+            <InsideDiameter Unit="m">0.01016</InsideDiameter>
+            <OutsideDiameter Unit="m">0.012700000000000001</OutsideDiameter>
+            <Length Unit="m">0.025400000000000002</Length>
+        </LaunchLug>
+        <Parachute>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>TAC-24</PartNumber>
+            <Description>TAC-1 24 in. Parachute</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.153087</Mass>
+            <Diameter Unit="m">0.6096</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.0</LineLength>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>TAC-36</PartNumber>
+            <Description>TAC-1 36 in. Parachute</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.229631</Mass>
+            <Diameter Unit="m">0.9144</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.0</LineLength>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>TAC-48</PartNumber>
+            <Description>TAC-1 48 in. Parachute</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.30617500000000003</Mass>
+            <Diameter Unit="m">1.2192</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.0</LineLength>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>TAC-60</PartNumber>
+            <Description>TAC-1 60 in. Parachute</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.40539800000000004</Mass>
+            <Diameter Unit="m">1.524</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.0</LineLength>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Giant Leap</Manufacturer>
+            <PartNumber>TAC-72</PartNumber>
+            <Description>TAC-1 72 in. Parachute</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.510291</Mass>
+            <Diameter Unit="m">1.8288</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.0</LineLength>
+        </Parachute>
+    </Components>
+</OpenRocketComponent>
diff --git a/core/resources/datafiles/presets/publicmissiles.orc b/core/resources/datafiles/presets/publicmissiles.orc
new file mode 100644 (file)
index 0000000..2a9a79e
--- /dev/null
@@ -0,0 +1,1526 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<OpenRocketComponent>
+    <Version>0.1</Version>
+    <Materials>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/16 In. braided nylon</Name>
+            <Density>0.00102</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/16 In. round elastic</Name>
+            <Density>0.00183</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/32 In. kevlar</Name>
+            <Density>6.590000000000001E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/4 In. flat elastic</Name>
+            <Density>0.00402</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/8 In. flat elastic</Name>
+            <Density>0.00205</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/8 In. flat rubber</Name>
+            <Density>0.00231</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>3/8 inch Flat Elastic</Name>
+            <Density>0.0038</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>30 Lb. kevlar</Name>
+            <Density>1.78E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>5/64 In. round elastic</Name>
+            <Density>0.0024200000000000003</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>70 Lb. kevlar</Name>
+            <Density>3.3E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Acrylic (Cast)</Name>
+            <Density>1185.3662916</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Aircraft plywood (Birch)</Name>
+            <Density>724.9956534840001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Ash</Name>
+            <Density>680.7846945000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Balsa</Name>
+            <Density>128.1477072</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Basswood</Name>
+            <Density>424.48928010000003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Beech</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Birch</Name>
+            <Density>680.7846945000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Brass</Name>
+            <Density>8553.8594556</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cardboard</Name>
+            <Density>688.7939262000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Chalk (Fine)</Name>
+            <Density>1121.2924380000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Copper (cast)</Name>
+            <Density>8682.0071628</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Copper (rolled)</Name>
+            <Density>8906.2656504</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cork (Solid)</Name>
+            <Density>240.27695100000003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Cottonwood</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Epoxy</Name>
+            <Density>1254.2456842200002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fiberglass</Name>
+            <Density>128.147704</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fir (Douglas)</Name>
+            <Density>560.6462190000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fir (White)</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.062)</Name>
+            <Density>3.137448001464</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.093)</Name>
+            <Density>5.022553313268</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>G10 (PML 0.125)</Name>
+            <Density>6.169435565904</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 fiberglass</Name>
+            <Density>1905.2360367960002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>G10 phenolic</Name>
+            <Density>1905.2360367960002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Gold (24 kt.)</Name>
+            <Density>19286.229933600003</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Iron (cast</Name>
+            <Density>7208.308530000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Iron (wrought)</Name>
+            <Density>7768.954749</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Kraft phenolic</Name>
+            <Density>958.7050344900001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lead (cast)</Name>
+            <Density>11341.072087200002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lead (rolled)</Name>
+            <Density>11389.127477400001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Leather</Name>
+            <Density>945.0893406000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Lexan</Name>
+            <Density>1218.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Maple (Hard)</Name>
+            <Density>632.7293043000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Mylar</Name>
+            <Density>1309.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Nylon</Name>
+            <Density>1140.0</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (Brown)</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (Red)</Name>
+            <Density>720.830853</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Oak (White)</Name>
+            <Density>752.8677798000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>PVC</Name>
+            <Density>1300.6992280800002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Paper</Name>
+            <Density>1121.2924380000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Pine (White Northern)</Name>
+            <Density>400.461585</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Pine (White Western)</Name>
+            <Density>432.4985118000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polycarbonate</Name>
+            <Density>1199.7829086600002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polyethylene LDPE</Name>
+            <Density>924.2653381800002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Polyethylene LDPE(0.051)</Name>
+            <Density>0.04695267917954401</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polystyrene PS</Name>
+            <Density>1049.2093527000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Poplar (Yellow)</Name>
+            <Density>480.55390200000005</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Rip stop nylon</Name>
+            <Density>0.06684999999999999</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Rocketwood</Name>
+            <Density>529.089846102</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Silver</Name>
+            <Density>10460.056600200001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spruce</Name>
+            <Density>448.51697520000005</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Sycamore</Name>
+            <Density>560.6462190000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Urethane</Name>
+            <Density>847.0563445920002</Density>
+            <Type>BULK</Type>
+        </Material>
+    </Materials>
+    <Components>
+        <EngineBlock>
+            <Manufacturer>Apogee</Manufacturer>
+            <PartNumber>EB-50</PartNumber>
+            <Description>Eng. block BT-50</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.018796</InsideDiameter>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>Estes</Manufacturer>
+            <PartNumber>30162-2</PartNumber>
+            <Description>Eng. block BT-20</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.016530000000000003</InsideDiameter>
+            <OutsideDiameter Unit="m">0.018033999999999998</OutsideDiameter>
+            <Length Unit="m">0.0050</Length>
+        </EngineBlock>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>Eclipse B</PartNumber>
+            <Description>Custom 38mm MMT rings</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.0418846</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09855199999999999</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>Large Lunar</PartNumber>
+            <Description>Boattail</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.566990462</Mass>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.156337</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.1520698</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.156337</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.05781039999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0541528</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">2.54E-5</AftShoulderLength>
+            <Length Unit="m">0.508</Length>
+            <Thickness Unit="m">0.0022224999999999996</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>Little Lunar</PartNumber>
+            <Description>Boatail</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.1022096</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.09855199999999999</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.1022096</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0418846</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.038227</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">2.54E-5</AftShoulderLength>
+            <Length Unit="m">0.30479999999999996</Length>
+            <Thickness Unit="m">0.0016002</Thickness>
+        </Transition>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML 29/38ADPTR</PartNumber>
+            <Description>29&gt;38mm Adapter</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.029082999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.038607999999999996</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML 54/29 ADPTR</PartNumber>
+            <Description>54&gt;29mm Adapter</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.029082999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05461</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML 54/38 ADPTR</PartNumber>
+            <Description>54&gt;38mm Adapter</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05461</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-01</PartNumber>
+            <Description>Fits PT-1.145</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.029082999999999998</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-02</PartNumber>
+            <Description>Fits PT-1.525</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.038735</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-03</PartNumber>
+            <Description>Fits PT-2.152</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0546608</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-04</PartNumber>
+            <Description>Fits PT-2.560</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-05</PartNumber>
+            <Description>Fits PT-3.002</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0762508</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-06</PartNumber>
+            <Description>Fits PT-3.900</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.09906</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-15</PartNumber>
+            <Description>Fits PT-6.007</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.15257779999999999</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-20</PartNumber>
+            <Description>Fits PT-7.512</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.19080479999999997</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML BP-90</PartNumber>
+            <Description>Fits PT-11.41</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.289814</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CBP-02</PartNumber>
+            <Description>Fits CT-1.52</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.036829999999999995</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CBP-03</PartNumber>
+            <Description>Fits CT-2.15</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0530352</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CBP-04</PartNumber>
+            <Description>Fits CT-2.56</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0634492</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CBP-05</PartNumber>
+            <Description>Fits CT-3.00</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0746252</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CBP-06</PartNumber>
+            <Description>Fits CT-3.90</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.097282</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CBP-15</PartNumber>
+            <Description>Fits CT-6.00</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.1505204</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CBP-20</PartNumber>
+            <Description>Fits CT-7.51</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.18872199999999997</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CBP-90</PartNumber>
+            <Description>Fits CT-11.4</Description>
+            <Material Type="BULK">Birch</Material>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.286512</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </BulkHead>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-00</PartNumber>
+            <Description>1.5&gt;29mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.03223259999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.038735</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-01</PartNumber>
+            <Description>2.1&gt;29mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.03223259999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0546608</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-02</PartNumber>
+            <Description>2.1&gt;38mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.0418846</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0546608</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-06</PartNumber>
+            <Description>2.5&gt;29mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.03223259999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-07</PartNumber>
+            <Description>2.5&gt;38mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.0418846</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-08</PartNumber>
+            <Description>2.5&gt;54mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.05781039999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-09</PartNumber>
+            <Description>3.0&gt;29mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.03223259999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0762508</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-10</PartNumber>
+            <Description>3.0&gt;38mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.0418846</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0762508</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-11</PartNumber>
+            <Description>3.0&gt;54mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.05781039999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0762508</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-12</PartNumber>
+            <Description>3.9&gt;29mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.03223259999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-13</PartNumber>
+            <Description>3.9&gt;38mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.0418846</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-14</PartNumber>
+            <Description>3.9&gt;54mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.05781039999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906</OutsideDiameter>
+            <Length Unit="m">0.004762499999999999</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-16</PartNumber>
+            <Description>6.0&gt;38mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.0418846</InsideDiameter>
+            <OutsideDiameter Unit="m">0.15257779999999999</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-17</PartNumber>
+            <Description>6.0&gt;54mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.05781039999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.15257779999999999</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-18</PartNumber>
+            <Description>6.0&gt;98mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.1022096</InsideDiameter>
+            <OutsideDiameter Unit="m">0.15257779999999999</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-20</PartNumber>
+            <Description>7.5&gt;54mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.05781039999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.19080479999999997</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-21</PartNumber>
+            <Description>7.5&gt;98mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.1022096</InsideDiameter>
+            <OutsideDiameter Unit="m">0.19080479999999997</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-90</PartNumber>
+            <Description>11.4&gt;54mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.05781039999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.289814</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-91</PartNumber>
+            <Description>11.4&gt;98mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.1022096</InsideDiameter>
+            <OutsideDiameter Unit="m">0.289814</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CR-92</PartNumber>
+            <Description>11.4&gt;76mm</Description>
+            <Material Type="BULK">Aircraft plywood (Birch)</Material>
+            <InsideDiameter Unit="m">0.0794004</InsideDiameter>
+            <OutsideDiameter Unit="m">0.289306</OutsideDiameter>
+            <Length Unit="m">0.0127</Length>
+        </CenteringRing>
+        <TubeCoupler>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CT-1.52</PartNumber>
+            <Description>Coupler tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <InsideDiameter Unit="m">0.035585399999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.038735</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CT-11.4</PartNumber>
+            <Description>Coupler tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <Mass Unit="kg">0.85899054993</Mass>
+            <InsideDiameter Unit="m">0.283464</InsideDiameter>
+            <OutsideDiameter Unit="m">0.289814</OutsideDiameter>
+            <Length Unit="m">0.4064</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CT-2.15</PartNumber>
+            <Description>Coupler tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <Mass Unit="kg">0.019844666169999997</Mass>
+            <InsideDiameter Unit="m">0.0515112</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0546608</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CT-2.56</PartNumber>
+            <Description>Coupler tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <Mass Unit="kg">0.031184475410000002</Mass>
+            <InsideDiameter Unit="m">0.061874399999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CT-3.00</PartNumber>
+            <Description>Coupler tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <InsideDiameter Unit="m">0.0731012</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0762508</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CT-3.90</PartNumber>
+            <Description>Coupler tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <Mass Unit="kg">0.07370876006</Mass>
+            <InsideDiameter Unit="m">0.09591039999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906</OutsideDiameter>
+            <Length Unit="m">0.17779999999999999</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CT-6.00</PartNumber>
+            <Description>Coupler tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <Mass Unit="kg">0.15308742474</Mass>
+            <InsideDiameter Unit="m">0.1488186</InsideDiameter>
+            <OutsideDiameter Unit="m">0.15257779999999999</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML CT-7.51</PartNumber>
+            <Description>Coupler tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <Mass Unit="kg">0.43658265574</Mass>
+            <InsideDiameter Unit="m">0.1867408</InsideDiameter>
+            <OutsideDiameter Unit="m">0.19080479999999997</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </TubeCoupler>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML FNC-11.41</PartNumber>
+            <Description>Fiberglass nose cone</Description>
+            <Material Type="BULK">Fiberglass</Material>
+            <Mass Unit="kg">2.267961848</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.29717999999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.29400499999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.15239999999999998</ShoulderLength>
+            <Length Unit="m">1.0668</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML FNC-11.4HRPN</PartNumber>
+            <Description>Fiberglass nose cone</Description>
+            <Material Type="BULK">Fiberglass</Material>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.296164</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.289306</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.15239999999999998</ShoulderLength>
+            <Length Unit="m">0.557276</Length>
+            <Thickness Unit="m">0.0022224999999999996</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML FNC-6.00</PartNumber>
+            <Description>Fiberglass nose cone</Description>
+            <Material Type="BULK">Fiberglass</Material>
+            <Mass Unit="kg">0.7937866468</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.15494</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.15176499999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.1397</ShoulderLength>
+            <Length Unit="m">0.6095999999999999</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML FNC-7.51</PartNumber>
+            <Description>Fiberglass nose cone</Description>
+            <Material Type="BULK">Fiberglass</Material>
+            <Mass Unit="kg">1.2473790164</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.19558</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.192405</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.15239999999999998</ShoulderLength>
+            <Length Unit="m">0.7365999999999999</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML IC-2.1-1.1</PartNumber>
+            <Description>Intellicone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.13324275857</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.05841999999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.07619999999999999</ShoulderLength>
+            <Length Unit="m">0.2413</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML IC-2.6-1.5</PartNumber>
+            <Description>Intellicone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.20411656632</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06858</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.065405</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0508</ShoulderLength>
+            <Length Unit="m">0.28575</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML IC-3.0-2.1</PartNumber>
+            <Description>Intellicone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.24664085096999996</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.07874</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.075565</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0635</ShoulderLength>
+            <Length Unit="m">0.33654999999999996</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML IC-3.9-2.1</PartNumber>
+            <Description>Intellicone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.40823313264</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.1016</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.098425</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.07619999999999999</ShoulderLength>
+            <Length Unit="m">0.42545</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML KS-1.145</PartNumber>
+            <Description>KS2000 29mm</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.029082999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.03223259999999999</OutsideDiameter>
+            <Length Unit="m">0.36829999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML KS-1.525</PartNumber>
+            <Description>KS2000 38mm</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0418846</OutsideDiameter>
+            <Length Unit="m">0.36829999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML KS-2.152</PartNumber>
+            <Description>KS2000 54mm</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0546608</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05781039999999999</OutsideDiameter>
+            <Length Unit="m">0.36829999999999996</Length>
+        </BodyTube>
+        <LaunchLug>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML LL-25</PartNumber>
+            <Description>1/4 brass launch lug</Description>
+            <Material Type="BULK">Brass</Material>
+            <InsideDiameter Unit="m">0.005715</InsideDiameter>
+            <OutsideDiameter Unit="m">0.00635</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML LL-38</PartNumber>
+            <Description>3/8 brass launch lug</Description>
+            <Material Type="BULK">Brass</Material>
+            <InsideDiameter Unit="m">0.0085725</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML LL-50</PartNumber>
+            <Description>1/2 brass launch lug</Description>
+            <Material Type="BULK">Brass</Material>
+            <InsideDiameter Unit="m">0.01143</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0127</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML LL-75</PartNumber>
+            <Description>3/4 copper launch lug</Description>
+            <Material Type="BULK">Copper (rolled)</Material>
+            <InsideDiameter Unit="m">0.017145</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019049999999999997</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </LaunchLug>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-18-F111</PartNumber>
+            <Description>18 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <Diameter Unit="m">0.4572</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.3302</LineLength>
+            <LineMaterial Type="LINE">Thin poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-24R</PartNumber>
+            <Description>24 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.04535923696</Mass>
+            <Diameter Unit="m">0.6095999999999999</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.508</LineLength>
+            <LineMaterial Type="LINE">Thin poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-30R</PartNumber>
+            <Description>30 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.06803885543999999</Mass>
+            <Diameter Unit="m">0.762</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.6095999999999999</LineLength>
+            <LineMaterial Type="LINE">Thin poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-34R</PartNumber>
+            <Description>34 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.08221361699</Mass>
+            <Diameter Unit="m">0.8635999999999999</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.635</LineLength>
+            <LineMaterial Type="LINE">Thin poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-36R</PartNumber>
+            <Description>36 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.08788352161</Mass>
+            <Diameter Unit="m">0.9144</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.6858</LineLength>
+            <LineMaterial Type="LINE">Thin poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-44R</PartNumber>
+            <Description>44 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.11623304470999998</Mass>
+            <Diameter Unit="m">1.1176</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.8128</LineLength>
+            <LineMaterial Type="LINE">Thin poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-48R</PartNumber>
+            <Description>48 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.12473790164000001</Mass>
+            <Diameter Unit="m">1.2191999999999998</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.9144</LineLength>
+            <LineMaterial Type="LINE">Thin poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-54R</PartNumber>
+            <Description>54 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.13607771087999998</Mass>
+            <Diameter Unit="m">1.3716</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">1.0413999999999999</LineLength>
+            <LineMaterial Type="LINE">Medium poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-60R</PartNumber>
+            <Description>60 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.22396123249</Mass>
+            <Diameter Unit="m">1.524</Diameter>
+            <Sides>8</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">1.0668</LineLength>
+            <LineMaterial Type="LINE">Heavy poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-62R</PartNumber>
+            <Description>62 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.23530104173000002</Mass>
+            <Diameter Unit="m">1.5748</Diameter>
+            <Sides>8</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">1.1176</LineLength>
+            <LineMaterial Type="LINE">Heavy poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-72R</PartNumber>
+            <Description>72 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.2551457079</Mass>
+            <Diameter Unit="m">1.8288</Diameter>
+            <Sides>8</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">1.143</LineLength>
+            <LineMaterial Type="LINE">Heavy poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-74R</PartNumber>
+            <Description>74 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.26932046945</Mass>
+            <Diameter Unit="m">1.8796</Diameter>
+            <Sides>8</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">1.1938</LineLength>
+            <LineMaterial Type="LINE">Heavy poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-84R</PartNumber>
+            <Description>84 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.33735932489</Mass>
+            <Diameter Unit="m">2.1336</Diameter>
+            <Sides>8</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">1.524</LineLength>
+            <LineMaterial Type="LINE">Heavy poly</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PAR-96R</PartNumber>
+            <Description>96 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.72291283905</Mass>
+            <Diameter Unit="m">2.4383999999999997</Diameter>
+            <Sides>8</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">1.8288</LineLength>
+            <LineMaterial Type="LINE">Heavy poly</LineMaterial>
+        </Parachute>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PIS 1.5</PartNumber>
+            <Description>Piston</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.035585399999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.038735</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PIS 2.1</PartNumber>
+            <Description>Piston</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0515112</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0546608</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PIS 2.5</PartNumber>
+            <Description>Piston</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.061874399999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.065024</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PIS 3.0</PartNumber>
+            <Description>Piston</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0731012</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0762508</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PIS 3.9</PartNumber>
+            <Description>Piston</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.09591039999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09906</OutsideDiameter>
+            <Length Unit="m">0.0635</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PIS 6.0</PartNumber>
+            <Description>Piston</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.1488186</InsideDiameter>
+            <OutsideDiameter Unit="m">0.15257779999999999</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PIS 7.5</PartNumber>
+            <Description>Piston</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.1867408</InsideDiameter>
+            <OutsideDiameter Unit="m">0.19080479999999997</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PNC-2.15</PartNumber>
+            <Description>Plastic nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.09922333085</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.05841999999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.044449999999999996</ShoulderLength>
+            <Length Unit="m">0.2413</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PNC-2.56</PartNumber>
+            <Description>Plastic nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.15308742474</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06858</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.065405</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0508</ShoulderLength>
+            <Length Unit="m">0.28575</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PNC-3.00</PartNumber>
+            <Description>Plastic nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.15875732935999998</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.07874</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.075565</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0635</ShoulderLength>
+            <Length Unit="m">0.33654999999999996</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PNC-3.90</PartNumber>
+            <Description>Plastic nose cone</Description>
+            <Material Type="BULK">Polystyrene PS</Material>
+            <Mass Unit="kg">0.283495231</Mass>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.1016</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.098425</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.07619999999999999</ShoulderLength>
+            <Length Unit="m">0.42545</Length>
+            <Thickness Unit="m">0.003175</Thickness>
+        </NoseCone>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-1.145</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.029082999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.03223259999999999</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-1.525</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.038735</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0418846</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-11.41</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.289814</InsideDiameter>
+            <OutsideDiameter Unit="m">0.296164</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-2.152</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0546608</InsideDiameter>
+            <OutsideDiameter Unit="m">0.05781039999999999</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-2.560</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.065024</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0681736</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-3.002</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.0762508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0794004</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-3.900</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.09906</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1022096</OutsideDiameter>
+            <Length Unit="m">0.9144</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-6.007</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.15257779999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.156337</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML PT-7.512</PartNumber>
+            <Description>Airframe tube</Description>
+            <Material Type="BULK">Kraft phenolic</Material>
+            <InsideDiameter Unit="m">0.19080479999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.19486879999999998</OutsideDiameter>
+            <Length Unit="m">1.2191999999999998</Length>
+        </BodyTube>
+        <Streamer>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML TBD123</PartNumber>
+            <Description>Streamer</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Length Unit="m">3.048</Length>
+            <Width Unit="m">0.07619999999999999</Width>
+            <Thickness Unit="m">5.08E-5</Thickness>
+        </Streamer>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML TC-2.1-1.1</PartNumber>
+            <Description>Transition (or tailcone) from 2.152 to 1.145</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.04252428465</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.05781039999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0546608</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.03223259999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+            <Thickness Unit="m">0.00556006</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML TC-2.5-1.1</PartNumber>
+            <Description>Transition (or tailcone) from 2.560 to 1.145</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.07654371237</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0681736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.065024</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.03223259999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+            <Thickness Unit="m">0.0084836</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML TC-2.5-1.5</PartNumber>
+            <Description>Transition (or tailcone) from 2.560 to 1.525</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.04252428465</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0681736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.065024</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.004775199999999999</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0418846</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+            <Thickness Unit="m">0.004318</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML TC-3.0-1.5</PartNumber>
+            <Description>Transition (or tailcone) from 3.002 to 1.525</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.07937866467999999</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0794004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0762508</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0418846</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+            <Thickness Unit="m">0.0066802</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML TC-3.0-2.1</PartNumber>
+            <Description>Transition (or tailcone) from 3.002 to 2.152</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.05102914158</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0794004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0762508</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.05781039999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+            <Thickness Unit="m">0.0039369999999999995</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML TC-3.9-2.1</PartNumber>
+            <Description>Transition (or tailcone) from 3.900 to 2.152</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.10205828316</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.1022096</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.09906</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.05781039999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+            <Thickness Unit="m">0.005715</Thickness>
+        </Transition>
+        <Transition>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML TC-3.9-3.0</PartNumber>
+            <Description>Transition (or tailcone) from 3.900 to 3.002</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.09638837854</Mass>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.1022096</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.09906</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.00635</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0794004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+            <Thickness Unit="m">0.005207</Thickness>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML UNC-1.145</PartNumber>
+            <Description>Urethane nose cone</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.0566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.032258</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.029082999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.038099999999999995</ShoulderLength>
+            <Length Unit="m">0.15239999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML UNC-1.525</PartNumber>
+            <Description>Urethane nose cone</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Mass Unit="kg">0.1133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.04064</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.037465</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.038099999999999995</ShoulderLength>
+            <Length Unit="m">0.2032</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML UNC-OG-1.5</PartNumber>
+            <Description>Stratus nose cone</Description>
+            <Material Type="BULK">Urethane</Material>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0418846</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.038227</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.022224999999999998</ShoulderLength>
+            <Length Unit="m">0.111125</Length>
+        </NoseCone>
+        <Parachute>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>PML Xform</PartNumber>
+            <Description>12 in. nylon</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Diameter Unit="m">0.30479999999999996</Diameter>
+            <Sides>4</Sides>
+            <LineCount>4</LineCount>
+            <LineLength Unit="m">0.30479999999999996</LineLength>
+            <LineMaterial Type="LINE">Thin poly</LineMaterial>
+        </Parachute>
+        <Streamer>
+            <Manufacturer>Public Missiles</Manufacturer>
+            <PartNumber>STREAMER</PartNumber>
+            <Description>F111 streamer</Description>
+            <Material Type="SURFACE">Rip stop nylon</Material>
+            <Length Unit="m">3.6576</Length>
+            <Width Unit="m">0.1016</Width>
+            <Thickness Unit="m">1.27E-5</Thickness>
+        </Streamer>
+    </Components>
+</OpenRocketComponent>
diff --git a/core/resources/datafiles/presets/semroc.orc b/core/resources/datafiles/presets/semroc.orc
new file mode 100644 (file)
index 0000000..378754d
--- /dev/null
@@ -0,0 +1,10597 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<OpenRocketComponent>
+    <Version>0.1</Version>
+    <Materials>
+        <Material UnitsOfMeasure="g/m">
+            <Name>1/16 In. braided nylon</Name>
+            <Density>0.00102</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m">
+            <Name>30 Lb. kevlar</Name>
+            <Density>1.78E-4</Density>
+            <Type>LINE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Balsa</Name>
+            <Density>128.1477072</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Fiber</Name>
+            <Density>656.7569994</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Paper</Name>
+            <Density>1121.2924380000002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Paper(0.051)</Name>
+            <Density>0.05696165585040001</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polycarbonate</Name>
+            <Density>1199.7829086600002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Polyethylene LDPE</Name>
+            <Density>924.2653381800002</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Polyethylene LDPE(0.025)</Name>
+            <Density>0.023476339589772004</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/m2">
+            <Name>Rip stop nylon</Name>
+            <Density>0.06684999999999999</Density>
+            <Type>SURFACE</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>Spiral/Glassine</Name>
+            <Density>848.9785602000001</Density>
+            <Type>BULK</Type>
+        </Material>
+        <Material UnitsOfMeasure="g/cm3">
+            <Name>lite ply</Name>
+            <Density>352.40619480000004</Density>
+            <Type>BULK</Type>
+        </Material>
+    </Materials>
+    <Components>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>AR-2050</PartNumber>
+            <Description>Centering Ring BT-20 to BT-50</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>AR-2050S</PartNumber>
+            <Description>Centering Ring BT-20 to BT-50 Split</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>AR-520</PartNumber>
+            <Description>Centering Ring BT-5 to BT-20</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013792200000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-08542</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.023875999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021589999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.10668</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-08542 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.0</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021589999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.10668</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1016</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.04064</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1016 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.04064</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1019</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.04826</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1019 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.04826</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1020E</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1020E [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1022</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05588</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1022 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.05588</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1024</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06095999999999999</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1024 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.06095999999999999</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1031</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07874</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1031 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.07874</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1032</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08128</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1032 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.08128</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1037</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09398</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1037 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.09398</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1039</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09906</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1039 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.09906</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1041</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.10413999999999998</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1041 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.10413999999999998</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1041G</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.10413999999999998</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1041G [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.10413999999999998</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1041P</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.10413999999999998</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1041P [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.10413999999999998</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1045</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1045 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1045P</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1045P [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1048</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.12191999999999999</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1048 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.12191999999999999</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1050</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1050 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.030900980179</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1051</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.12954</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1051 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.12954</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1052</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0254</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.13208</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1052 [R]</PartNumber>
+            <Description>Balsa Nose Cone \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">2.54E-6</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0</AftShoulderLength>
+            <Length Unit="m">0.13208</Length>
+        </Transition>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1135</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.029717999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028701999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08889999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-11518</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.08889999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-11524</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.06095999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-11535</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.08889999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-11544</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.11176</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-11546</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.11683999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-11549</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.12446</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-11554</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.13716</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-11560</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.15239999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-12525</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03175</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-12536</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.09144</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-12545</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0068038855439999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-12548</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.12191999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-12555</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009638837854</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1397</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-12561</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010489323547</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.028955999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.15494</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1319</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.04826</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1321</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1327</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06858</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1329</PartNumber>
+            <Description>Rounded-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0068038855439999995</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07365999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1330</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1331</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07874</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1336</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09144</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1339</PartNumber>
+            <Description>Rounded-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09906</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1344</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11176</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1345</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11176</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1353</PartNumber>
+            <Description>Secant Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.013891266319</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.136398</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1353F</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.013324275856999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.13462</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1354</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.015592237705000001</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.13716</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1354C</PartNumber>
+            <Description>Parabolic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.016442723397999997</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.13716</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1364</PartNumber>
+            <Description>Rounded-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017576704321999998</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.03302</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.16256</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-15044</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.038099999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.11176</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-15066</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009922333084999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.038099999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.16763999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-15070</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.011056314009</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.038099999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.17779999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-15080</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.012757285395</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.038099999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.2032</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-15081</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.012190294933</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.038099999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.20573999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-16100</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0129273825336</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.254</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1625</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1625P</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1631</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07874</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1634</PartNumber>
+            <Description>Rounded-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008788352160999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08635999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1636</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009922333084999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09144</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1646</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.011056314009</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11683999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1647</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.01133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11938</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1648</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.011623304470999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.12191999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1650</PartNumber>
+            <Description>Parabolic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.012190294933</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1655</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.013040780626</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.1397</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1660</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.013607771087999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.15239999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1667</PartNumber>
+            <Description>Parabolic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.014458256781</Mass>
+            <Filled>true</Filled>
+            <Shape>PARABOLIC</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.17018</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1672</PartNumber>
+            <Description>Conical-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.016442723397999997</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.18288</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1674</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017576704321999998</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04064</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.18796</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-17535</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.013607771087999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.08889999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-17541</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.015025247243</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.10413999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-17560</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.019561170939</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.15239999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-17561</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.020411656631999998</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.15494</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-17567</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.021545637556</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.17018</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-17585</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.026081561252</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.21589999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-17590</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.032034961103</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.2286</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-17592</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.053580598658999994</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.23367999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1828</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.019844666169999997</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1835</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.08889999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1837</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.09398</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1842</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.10668</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1853</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.13462</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1856</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.031184475410000002</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.14223999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1861</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.034019427719999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.15494</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1869</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.034019427719999995</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.17526</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-1869C</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.034019427719999995</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.04572</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.17526</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-20045</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017860199553</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-20107</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.050462151118</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.27177999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2025</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.011906799701999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2026</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.012190294933</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.06604</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2033</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017293209091</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.08381999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2039</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.019561170939</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.09906</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2045</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.043658265574</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2050</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.038555351416</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2057</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.047627198807999996</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.14478</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2065</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.050178655887</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.1651</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-2080</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.055848560506999996</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0508</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.017779999999999997</ShoulderLength>
+            <Length Unit="m">0.2032</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-225103</PartNumber>
+            <Description>Fat Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.08221361699</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.26162</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22530</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.02551457079</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22545</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.029766999255</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22563</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.041957294188</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.16002</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22567</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.043941760805</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.17018</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22567E</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.042807779881</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.17018</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22569</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.047343703577</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.17526</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22578</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.05102914158</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.19812</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22579</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.04819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.20066</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22588</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.062368950820000005</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.22352</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22595</PartNumber>
+            <Description>Secant-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.07087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>HAACK</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.2413</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-22597</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.07370876006</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.05715</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.24637999999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-27540</PartNumber>
+            <Description>Blunt Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.034869913413</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.07213599999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.06985</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-27554</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.043941760805</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.07213599999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.06985</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.13716</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-27555</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.045642732191</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.07213599999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.06985</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1397</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-505</PartNumber>
+            <Description>Spherical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-508</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.02032</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-510</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-510P</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-512</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.030479999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-514</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.035559999999999994</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-515</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-515E</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-516</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.04064</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-517</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-518</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.04572</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-522</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.05588</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-522P</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.05588</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-523</PartNumber>
+            <Description>Taper-Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>POWER</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.05841999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-524</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.06095999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-526</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.06604</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-528</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-529</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.07365999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-708</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.02032</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-710</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-711</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.02794</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-714</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.035559999999999994</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-715</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-716</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.04064</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-719</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.04826</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-720</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-721</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-722</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05588</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-723</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05841999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-723P</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05841999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-727</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06858</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-728</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-728F</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-730</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-730P</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-731</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07874</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-731F</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07874</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-733</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08381999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-734P</PartNumber>
+            <Description>Pointed Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08635999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-735</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08889999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-736</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09144</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-737</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09398</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-739</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09906</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-739O</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09906</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-744</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018161</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11176</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-812</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.030479999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-813</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.03302</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-814</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.035559999999999994</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-815</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-817</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-818</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.04572</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-818L</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.04572</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-819</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.04826</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-820</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-821</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0025514570789999997</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-823</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05841999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-823E</PartNumber>
+            <Description>Fat Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.05841999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-826</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06604</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-830</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-832</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08128</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-832C</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08128</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-833</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08381999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-834C</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08635999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-836</PartNumber>
+            <Description>Secant-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>HAACK</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09144</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-837</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.09398</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-840</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-845</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-845P</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-846</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11683999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-847</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11938</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-847W</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.11938</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-848</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.12191999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-853</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.13462</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-8F28</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0233934</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.021970999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-927</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.06858</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-932</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.08128</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-940</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BC-944</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.11176</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-10A</PartNumber>
+            <Description>Blunt Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.018288</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.020574000000000002</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-10B</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.018288</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20A</PartNumber>
+            <Description>Blunt Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.020574000000000002</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20AZ</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20B</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20CB</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20H</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.02032</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20L</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.035559999999999994</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20N</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20R</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20SP</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.00635</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-20Y</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018033999999999998</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-30C</PartNumber>
+            <Description>Blunt Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018414999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-30D</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018414999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-30DE</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018414999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.03505199999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-30E</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.018414999999999997</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.009524999999999999</ShoulderLength>
+            <Length Unit="m">0.05841999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-3A</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.008864599999999999</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-40D</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.020954999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.019431</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-40F</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.020954999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.019431</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.04826</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-40G</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.020954999999999998</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.019431</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.01016</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50C</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.032258</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50G</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.14478</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50J</PartNumber>
+            <Description>Blunt Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.034925</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50K</PartNumber>
+            <Description>Fat Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50KP</PartNumber>
+            <Description>Parabolic</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50V</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.14604999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50X</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.08255</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50Y</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.111125</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-50YP</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.02413</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0127</ShoulderLength>
+            <Length Unit="m">0.108712</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55AA</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.079375</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55AC</PartNumber>
+            <Description>Secant-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>HAACK</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.136525</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55ACP</PartNumber>
+            <Description>Secant-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009355342623</Mass>
+            <Filled>true</Filled>
+            <Shape>HAACK</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.14604999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55AO</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.012190294933</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55CT</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0068038855439999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.07365999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55EX</PartNumber>
+            <Description>Fat Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008221361698999998</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.08635999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55F</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.10668</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55FD</PartNumber>
+            <Description>Base-Drilled Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.10668</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55PT</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.015875732936</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.15621000000000002</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55X</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010489323547</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.10413999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-55Z</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-5AW</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.05715</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-5AX</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.05715</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-5E</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.03505199999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-5S</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">4.535923696E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-5V</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">3.685438003E-4</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-5W</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.013081</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.00635</ShoulderLength>
+            <Length Unit="m">0.072898</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60AH</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.02267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.16827499999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60L</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009638837854</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.079375</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60LP</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0068038855439999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.06985</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60MS</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.06604</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60NA</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010489323547</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.12191999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60NS</PartNumber>
+            <Description>Conical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0129273825336</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.254</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60RL</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.022963113711000002</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.212725</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60X</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017576704321999998</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.138684</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-60Y</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.020695151863</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.040513</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.18414999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-65AF</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.014741752012</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.045618399999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-65L</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.011623304470999999</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.045618399999999996</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.044449999999999996</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.08255</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70AJ</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.024097094635</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.10794999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70CT</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.02551457079</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70D</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.02551457079</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.10794999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70HAC</PartNumber>
+            <Description>Secant-Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>HAACK</Shape>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.23266399999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70HAJ</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.024097094635</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.10794999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70HB</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.032034961103</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.17779999999999999</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70HCT</PartNumber>
+            <Description>Bezier</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.02551457079</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70HD</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.024947580328</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.109982</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70MS</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.089916</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-70NH</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.041957294188</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.055244999999999995</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.02032</ShoulderLength>
+            <Length Unit="m">0.24764999999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80AH</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.079662159911</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.2667</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80AO</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.037988360954</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.25146</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80BB</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.031184475410000002</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80D</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.027782532638</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80HAH</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.079662159911</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.2667</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80HAO</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.037988360954</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.25146</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80HBB</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.031184475410000002</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.1016</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80HD</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.027782532638</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80HK</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.034869913413</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.20827999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80HKA</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.032034961103</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.186182</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80HKP</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.031751465872</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.17602199999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80HL</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80K</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.034869913413</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.20827999999999997</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80KA</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.032034961103</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.186182</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80KP</PartNumber>
+            <Description>Rounded Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.031751465872</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.17602199999999998</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80L</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.127</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC-80VE</PartNumber>
+            <Description>Ogive</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>OGIVE</Shape>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0649732</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.0254</ShoulderLength>
+            <Length Unit="m">0.12446</Length>
+        </NoseCone>
+        <NoseCone>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BNC55B</PartNumber>
+            <Description>Elliptical</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <ShoulderDiameter Unit="m">0.0325882</ShoulderDiameter>
+            <ShoulderLength Unit="m">0.015239999999999998</ShoulderLength>
+            <Length Unit="m">0.07619999999999999</Length>
+        </NoseCone>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-085225</PartNumber>
+            <Description>Balsa Reducer 085 to 225</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.022112628018</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024002999999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.059435999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05715</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-085225 [R]</PartNumber>
+            <Description>Balsa Reducer 085 to 225 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.022112628018</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.059435999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05715</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024002999999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1013</PartNumber>
+            <Description>Balsa Reducer 10 to 13</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1013 [R]</PartNumber>
+            <Description>Balsa Reducer 10 to 13 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.026416</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0254</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1016</PartNumber>
+            <Description>Balsa Reducer 10 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1016 [R]</PartNumber>
+            <Description>Balsa Reducer 10 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.026416</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0254</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1016S</PartNumber>
+            <Description>Balsa Reducer 10 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008221361698999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.030479999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1016S [R]</PartNumber>
+            <Description>Balsa Reducer 10 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008221361698999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.026416</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0254</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.030479999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1116</PartNumber>
+            <Description>Balsa Reducer 11 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009355342623</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.029717999999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.028701999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1116 [R]</PartNumber>
+            <Description>Balsa Reducer 11 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009355342623</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.029717999999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028701999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1118</PartNumber>
+            <Description>Balsa Reducer 11 to 18</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.029717999999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.028701999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1118 [R]</PartNumber>
+            <Description>Balsa Reducer 11 to 18 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.029717999999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028701999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-11516</PartNumber>
+            <Description>Balsa Reducer 115 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.029766999255</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.030987999999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.028955999999999996</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.085725</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-11516 [R]</PartNumber>
+            <Description>Balsa Reducer 115 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.029766999255</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.030987999999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028955999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.085725</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-11518</PartNumber>
+            <Description>Balsa Reducer 115 to 18</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.031184475410000002</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.030987999999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.028955999999999996</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.085725</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-11518 [R]</PartNumber>
+            <Description>Balsa Reducer 115 to 18 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.031184475410000002</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.030987999999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028955999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.085725</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-125-175</PartNumber>
+            <Description>Balsa Reducer 125 to 175</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.01417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03175</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.044449999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-125-175 [R]</PartNumber>
+            <Description>Balsa Reducer 125 to 175 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.01417476155</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.044449999999999996</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03175</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-125-175L</PartNumber>
+            <Description>Balsa Reducer 125 to 175</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03175</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.044449999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-125-175L [R]</PartNumber>
+            <Description>Balsa Reducer 125 to 175 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.044449999999999996</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03175</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-125-225</PartNumber>
+            <Description>Balsa Reducer 125 to 225</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03175</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.059435999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05715</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-125-225 [R]</PartNumber>
+            <Description>Balsa Reducer 125 to 225 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.059435999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05715</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03175</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.07111999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1316</PartNumber>
+            <Description>Balsa Reducer 13 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0068038855439999995</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1316 [R]</PartNumber>
+            <Description>Balsa Reducer 13 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0068038855439999995</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1316F</PartNumber>
+            <Description>Balsa Reducer 13 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1316F [R]</PartNumber>
+            <Description>Balsa Reducer 13 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.044449999999999996</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1316L</PartNumber>
+            <Description>Balsa Reducer 13 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1316L [R]</PartNumber>
+            <Description>Balsa Reducer 13 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1316M</PartNumber>
+            <Description>Balsa Reducer 13 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1316M [R]</PartNumber>
+            <Description>Balsa Reducer 13 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1320</PartNumber>
+            <Description>Balsa Reducer 13 to 20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.051816</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0508</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1320 [R]</PartNumber>
+            <Description>Balsa Reducer 13 to 20 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.051816</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0508</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1320L</PartNumber>
+            <Description>Balsa Reducer 13 to 20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.015875732936</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.051816</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0508</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1320L [R]</PartNumber>
+            <Description>Balsa Reducer 13 to 20 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.015875732936</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.051816</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0508</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.1143</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-150-225</PartNumber>
+            <Description>Balsa Reducer 150 to 225</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.029766999255</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.040386</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.038099999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.059435999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05715</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.05715</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-150-225 [R]</PartNumber>
+            <Description>Balsa Reducer 150 to 225 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.029766999255</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.059435999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05715</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.040386</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.038099999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.05715</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-150-275</PartNumber>
+            <Description>Balsa Reducer 150 to 275</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.041106808495</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.040386</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.038099999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.07213599999999999</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.06985</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.07365999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-150-275 [R]</PartNumber>
+            <Description>Balsa Reducer 150 to 275 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.041106808495</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.07213599999999999</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.06985</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.040386</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.038099999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.07365999999999999</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1618</PartNumber>
+            <Description>Balsa Reducer 16 to 18</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1618 [R]</PartNumber>
+            <Description>Balsa Reducer 16 to 18 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1618F</PartNumber>
+            <Description>Balsa Reducer 16 to 18</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.04572</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1618F [R]</PartNumber>
+            <Description>Balsa Reducer 16 to 18 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.04572</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1620</PartNumber>
+            <Description>Balsa Reducer 16 to 20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.051816</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0508</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1620 [R]</PartNumber>
+            <Description>Balsa Reducer 16 to 20 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.051816</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0508</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1620F</PartNumber>
+            <Description>Balsa Reducer 16 to 20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.051816</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0508</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.030479999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1620F [R]</PartNumber>
+            <Description>Balsa Reducer 16 to 20 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.051816</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0508</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.030479999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-16225F</PartNumber>
+            <Description>Balsa Reducer 16 to 225</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009355342623</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.059435999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05715</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.03937</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-16225F [R]</PartNumber>
+            <Description>Balsa Reducer 16 to 225 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009355342623</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.059435999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05715</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.03937</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-175-225</PartNumber>
+            <Description>Balsa Reducer 175 to 225</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.02267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.044449999999999996</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.059435999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05715</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-175-225 [R]</PartNumber>
+            <Description>Balsa Reducer 175 to 225 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.02267961848</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.059435999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05715</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.044449999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1820</PartNumber>
+            <Description>Balsa Reducer 18 to 20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.051816</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0508</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-1820 [R]</PartNumber>
+            <Description>Balsa Reducer 18 to 20 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.051816</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0508</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-18225</PartNumber>
+            <Description>Balsa Reducer 18 to 225</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008788352160999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.059435999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05715</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-18225 [R]</PartNumber>
+            <Description>Balsa Reducer 18 to 225 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008788352160999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.059435999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05715</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-225-80H</PartNumber>
+            <Description>Balsa Reducer 225 to BT-80H</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.059435999999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.05715</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.067056</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0649732</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-225-80H [R]</PartNumber>
+            <Description>Balsa Reducer 225 to BT-80H \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.03685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.067056</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0649732</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.059435999999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.05715</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.05334</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-510</PartNumber>
+            <Description>Balsa Reducer 5 to 10</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013792200000000001</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.026416</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0254</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-510 [R]</PartNumber>
+            <Description>Balsa Reducer 5 to 10 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013792200000000001</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-511</PartNumber>
+            <Description>Balsa Reducer 5 to 11</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013792200000000001</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.029717999999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028701999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-511 [R]</PartNumber>
+            <Description>Balsa Reducer 5 to 11 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.029717999999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.028701999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013792200000000001</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-513</PartNumber>
+            <Description>Balsa Reducer 5 to 13</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013792200000000001</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-513 [R]</PartNumber>
+            <Description>Balsa Reducer 5 to 13 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013792200000000001</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-57</PartNumber>
+            <Description>Balsa Reducer 5 to 7</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013792200000000001</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-57 [R]</PartNumber>
+            <Description>Balsa Reducer 5 to 7 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013792200000000001</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-58</PartNumber>
+            <Description>Balsa Reducer 5 to 8</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013792200000000001</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0230632</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-58 [R]</PartNumber>
+            <Description>Balsa Reducer 5 to 8 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0230632</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013792200000000001</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-58F</PartNumber>
+            <Description>Balsa Reducer 5 to 8F</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013792200000000001</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0233934</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.022479</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-58F [R]</PartNumber>
+            <Description>Balsa Reducer 5 to 8F \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0233934</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.022479</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013792200000000001</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-59</PartNumber>
+            <Description>Balsa Reducer 5 to 9</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.013792200000000001</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0253492</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-59 [R]</PartNumber>
+            <Description>Balsa Reducer 5 to 9 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0253492</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.013792200000000001</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-60-18</PartNumber>
+            <Description>Balsa Reducer BT-60 to ST-18</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008221361698999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-60-18 [R]</PartNumber>
+            <Description>Balsa Reducer BT-60 to ST-18 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008221361698999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-710</PartNumber>
+            <Description>Balsa Reducer 7 to 10</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.026416</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0254</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-710 [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 10 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-711</PartNumber>
+            <Description>Balsa Reducer 7 to 11</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.029717999999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028701999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-711 [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 11 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.029717999999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.028701999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-713</PartNumber>
+            <Description>Balsa Reducer 7 to 13</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-713 [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 13 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-716</PartNumber>
+            <Description>Balsa Reducer 7 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-716 [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-718</PartNumber>
+            <Description>Balsa Reducer 7 to 18</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.011906799701999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-718 [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 18 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.011906799701999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-78</PartNumber>
+            <Description>Balsa Reducer 7 to 8</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0230632</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.022224999999999998</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-78 [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 8 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0230632</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.022224999999999998</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-78F</PartNumber>
+            <Description>Balsa Reducer 7 to 8F</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0233934</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.022479</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-78F [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 8F \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0233934</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.022479</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-78S</PartNumber>
+            <Description>Balsa Reducer 7 to 8</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0230632</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-78S [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 8 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0230632</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-79</PartNumber>
+            <Description>Balsa Reducer 7 to 9</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0253492</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-79 [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 9 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0253492</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-79L</PartNumber>
+            <Description>Balsa Reducer 7 to 9</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0192786</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018161</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0253492</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-79L [R]</PartNumber>
+            <Description>Balsa Reducer 7 to 9 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0253492</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0192786</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018161</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-810</PartNumber>
+            <Description>Balsa Reducer 8 to 10</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003968933234</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0230632</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.026416</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0254</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-810 [R]</PartNumber>
+            <Description>Balsa Reducer 8 to 10 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003968933234</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.026416</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0254</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0230632</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-813</PartNumber>
+            <Description>Balsa Reducer 8 to 13</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007370876006</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0230632</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-813 [R]</PartNumber>
+            <Description>Balsa Reducer 8 to 13 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007370876006</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0230632</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-813P</PartNumber>
+            <Description>Balsa Reducer 8 to 13</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007370876006</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0230632</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.034036000000000004</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.03302</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-813P [R]</PartNumber>
+            <Description>Balsa Reducer 8 to 13 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007370876006</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.034036000000000004</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.03302</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0230632</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-816</PartNumber>
+            <Description>Balsa Reducer 8 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0230632</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-816 [R]</PartNumber>
+            <Description>Balsa Reducer 8 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0230632</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-816NT</PartNumber>
+            <Description>Balsa Reducer 8 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010772818778</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0230632</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.021970999999999997</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-816NT [R]</PartNumber>
+            <Description>Balsa Reducer 8 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010772818778</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0230632</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.021970999999999997</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.043179999999999996</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-8F11</PartNumber>
+            <Description>Balsa Reducer 8F to 11</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0233934</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.022479</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.029717999999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028701999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-8F11 [R]</PartNumber>
+            <Description>Balsa Reducer 8F to 11 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.029717999999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.028701999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0233934</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.022479</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-8F11L</PartNumber>
+            <Description>Balsa Reducer 8F to 11</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0233934</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.022479</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.029717999999999998</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.028701999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-8F11L [R]</PartNumber>
+            <Description>Balsa Reducer 8F to 11 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.029717999999999998</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.028701999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0233934</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.022479</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-916</PartNumber>
+            <Description>Balsa Reducer 9 to 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0253492</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.041656</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04064</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-916 [R]</PartNumber>
+            <Description>Balsa Reducer 9 to 16 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.041656</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04064</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0253492</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-918</PartNumber>
+            <Description>Balsa Reducer 9 to 18</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0253492</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.046736</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.04572</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-918 [R]</PartNumber>
+            <Description>Balsa Reducer 9 to 18 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.046736</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.04572</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0253492</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-920</PartNumber>
+            <Description>Balsa Reducer 9 to 20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009638837854</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0253492</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.051816</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0508</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BR-920 [R]</PartNumber>
+            <Description>Balsa Reducer 9 to 20 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009638837854</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.051816</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0508</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0253492</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-100CE</PartNumber>
+            <Description>Classic Body Tube BT-100</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.012190294933</Mass>
+            <InsideDiameter Unit="m">0.0940308</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0950976</OutsideDiameter>
+            <Length Unit="m">0.08889999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-100D</PartNumber>
+            <Description>Classic Body Tube BT-100</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.01417476155</Mass>
+            <InsideDiameter Unit="m">0.0940308</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0950976</OutsideDiameter>
+            <Length Unit="m">0.10388599999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-100Z</PartNumber>
+            <Description>Classic Body Tube BT-100</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.037988360954</Mass>
+            <InsideDiameter Unit="m">0.0940308</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0950976</OutsideDiameter>
+            <Length Unit="m">0.276606</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-101</PartNumber>
+            <Description>Classic Body Tube BT-101</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.055848560506999996</Mass>
+            <InsideDiameter Unit="m">0.09895839999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1000252</OutsideDiameter>
+            <Length Unit="m">0.4191</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-101K</PartNumber>
+            <Description>Classic Body Tube BT-101</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.025798066021000002</Mass>
+            <InsideDiameter Unit="m">0.09895839999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1000252</OutsideDiameter>
+            <Length Unit="m">0.19278599999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-101LA</PartNumber>
+            <Description>Classic Body Tube BT-101</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.072574779136</Mass>
+            <InsideDiameter Unit="m">0.09895839999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1000252</OutsideDiameter>
+            <Length Unit="m">0.5435599999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-101SV</PartNumber>
+            <Description>Classic Body Tube BT-101</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.083631093145</Mass>
+            <InsideDiameter Unit="m">0.09895839999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1000252</OutsideDiameter>
+            <Length Unit="m">0.625602</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-101T</PartNumber>
+            <Description>Classic Body Tube BT-101</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <InsideDiameter Unit="m">0.09895839999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.1000252</OutsideDiameter>
+            <Length Unit="m">0.070612</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20AE</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20B</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.21971</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20D</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.1651</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20DJ</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20G</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.08889999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20J</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20L</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-20M</PartNumber>
+            <Description>Classic Body Tube BT-20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <InsideDiameter Unit="m">0.018033999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0186944</OutsideDiameter>
+            <Length Unit="m">0.05715</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-3</PartNumber>
+            <Description>Classic Body Tube BT-3</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <InsideDiameter Unit="m">0.008762999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30-180</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.012473790164</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30A</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0025514570789999997</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.08889999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30B</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.15570199999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30C</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.1397</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30F</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.17779999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30J</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30K</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.059435999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-30XW</PartNumber>
+            <Description>Classic Body Tube BT-30</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <InsideDiameter Unit="m">0.018414999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-3H</PartNumber>
+            <Description>Classic Body Tube BT-3</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <InsideDiameter Unit="m">0.008762999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-3XW</PartNumber>
+            <Description>Classic Body Tube BT-3</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <InsideDiameter Unit="m">0.008762999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.009524999999999999</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-40</PartNumber>
+            <Description>Classic Body Tube BT-40</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <InsideDiameter Unit="m">0.019431</InsideDiameter>
+            <OutsideDiameter Unit="m">0.020954999999999998</OutsideDiameter>
+            <Length Unit="m">0.34925</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-40-185</PartNumber>
+            <Description>Classic Body Tube BT-40</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <InsideDiameter Unit="m">0.019431</InsideDiameter>
+            <OutsideDiameter Unit="m">0.020954999999999998</OutsideDiameter>
+            <Length Unit="m">0.4699</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-40W</PartNumber>
+            <Description>Classic Body Tube BT-40</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <InsideDiameter Unit="m">0.019431</InsideDiameter>
+            <OutsideDiameter Unit="m">0.020954999999999998</OutsideDiameter>
+            <Length Unit="m">0.23495</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-5</PartNumber>
+            <Description>Classic Body Tube BT-5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.009922333084999999</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50A</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.254</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50AE</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">8.504856929999999E-4</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50AH</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.047751999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50B</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.26034999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50EE</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.1397</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50F</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.00283495231</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50FE</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.003685438003</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.1651</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50H</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.19685</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50IJ</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.005102914157999999</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50J</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50KE</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.3937</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50L</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.32258</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50N</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.007937866468</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.35559999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50P</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.2794</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50S</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50SV</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.41275</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50TF</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.4064</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50V</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.009355342623</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.4191</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-50W</PartNumber>
+            <Description>Classic Body Tube BT-50</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.005386409389</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.2413</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-51CI</PartNumber>
+            <Description>Classic Body Tube BT-51</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <InsideDiameter Unit="m">0.024993599999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.025679399999999998</OutsideDiameter>
+            <Length Unit="m">0.09855199999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-51N</PartNumber>
+            <Description>Classic Body Tube BT-51</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <InsideDiameter Unit="m">0.024993599999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.025679399999999998</OutsideDiameter>
+            <Length Unit="m">0.31546799999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-52</PartNumber>
+            <Description>Classic Body Tube BT-52</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.010489323547</Mass>
+            <InsideDiameter Unit="m">0.025095199999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0257556</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-52AG</PartNumber>
+            <Description>Classic Body Tube BT-52</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.025095199999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0257556</OutsideDiameter>
+            <Length Unit="m">0.05334</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-52S</PartNumber>
+            <Description>Classic Body Tube BT-52</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <InsideDiameter Unit="m">0.025095199999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0257556</OutsideDiameter>
+            <Length Unit="m">0.100076</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.021829132787</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55C</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.35559999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55E</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0025514570789999997</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.05334</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55IJ</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.011056314009</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55J</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55KA</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.012757285395</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.2667</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55KG</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.020411656631999998</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.42545</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55S</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55V</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.019844666169999997</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.41529</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-55W</PartNumber>
+            <Description>Classic Body Tube BT-55</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.014741752012</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-58</PartNumber>
+            <Description>Classic Body Tube BT-58</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.017860199553</Mass>
+            <InsideDiameter Unit="m">0.0380492</InsideDiameter>
+            <OutsideDiameter Unit="m">0.039116</OutsideDiameter>
+            <Length Unit="m">0.32384999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-58-180</PartNumber>
+            <Description>Classic Body Tube BT-58</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.025231075559</Mass>
+            <InsideDiameter Unit="m">0.0380492</InsideDiameter>
+            <OutsideDiameter Unit="m">0.039116</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-58LJ</PartNumber>
+            <Description>Classic Body Tube BT-58</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <InsideDiameter Unit="m">0.0380492</InsideDiameter>
+            <OutsideDiameter Unit="m">0.039116</OutsideDiameter>
+            <Length Unit="m">0.136652</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-58SB</PartNumber>
+            <Description>Classic Body Tube BT-58</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.009071847392</Mass>
+            <InsideDiameter Unit="m">0.0380492</InsideDiameter>
+            <OutsideDiameter Unit="m">0.039116</OutsideDiameter>
+            <Length Unit="m">0.162052</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-58SV</PartNumber>
+            <Description>Classic Body Tube BT-58</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <InsideDiameter Unit="m">0.0380492</InsideDiameter>
+            <OutsideDiameter Unit="m">0.039116</OutsideDiameter>
+            <Length Unit="m">0.15570199999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-5BJ</PartNumber>
+            <Description>Classic Body Tube BT-5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-5CJ</PartNumber>
+            <Description>Classic Body Tube BT-5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-5P</PartNumber>
+            <Description>Classic Body Tube BT-5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.12954</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-5T</PartNumber>
+            <Description>Classic Body Tube BT-5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0137414</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.027215542175999998</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60AD</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.021262142325</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.35559999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60AJ</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.015025247243</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.254</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60C</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60D</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.016726218629</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.2794</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60DS</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.018994180477</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.3175</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60FG</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.17018</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60HE</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.012757285395</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.21589999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60J</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004252428464999999</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.06985</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60K</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.010489323547</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.17779999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60KC</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.019277675708</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.326136</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60KF</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.024380589866</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.40894</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60P</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.024097094635</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.4064</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60R</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0076543712370000004</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-60V</PartNumber>
+            <Description>Classic Body Tube BT-60</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <InsideDiameter Unit="m">0.040513</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0415798</OutsideDiameter>
+            <Length Unit="m">0.10947399999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-65</PartNumber>
+            <Description>Classic Body Tube BT-65</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.029625251639499996</Mass>
+            <InsideDiameter Unit="m">0.044449999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.045618399999999996</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-70</PartNumber>
+            <Description>Classic Body Tube BT-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.047910694038999994</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-70H</PartNumber>
+            <Description>Classic Body Tube BT-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.018994180477</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.18161</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-70KD</PartNumber>
+            <Description>Classic Body Tube BT-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.046493217883999995</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.4445</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-70V</PartNumber>
+            <Description>Classic Body Tube BT-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0283495231</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.26924</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-80</PartNumber>
+            <Description>Classic Body Tube BT-80</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.043374770342999996</Mass>
+            <InsideDiameter Unit="m">0.0649732</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-80KD</PartNumber>
+            <Description>Classic Body Tube BT-80</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.034302922951</Mass>
+            <InsideDiameter Unit="m">0.0649732</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <Length Unit="m">0.36067999999999995</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BT-80S</PartNumber>
+            <Description>Classic Body Tube BT-80</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.010772818778</Mass>
+            <InsideDiameter Unit="m">0.0649732</InsideDiameter>
+            <OutsideDiameter Unit="m">0.06604</OutsideDiameter>
+            <Length Unit="m">0.1143</Length>
+        </BodyTube>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-085</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 85</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0016159228167</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.021970999999999997</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-10</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 10</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0018143694784</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0254</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-11</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 11</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0019561170939</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.028701999999999995</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-115</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 115</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0031751465871999998</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.029209999999999996</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-125</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 125</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.03175</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-13</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 13</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0035436903875</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.03302</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-150</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 150</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006662137928499999</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.038099999999999995</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-16</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 16</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004961166542499999</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.04064</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-175</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 175</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0094970902385</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.044449999999999996</OutsideDiameter>
+            <Length Unit="m">0.05715</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-18</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 18</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.04572</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-20</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0075126236215</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0508</OutsideDiameter>
+            <Length Unit="m">0.05334</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-225</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 225</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0180019471685</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.05715</OutsideDiameter>
+            <Length Unit="m">0.0635</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-275</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 275</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0321767087185</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.06985</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-5</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 5</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.013081</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-7</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 7</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">7.370876006E-4</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.018161</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-8</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 8</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0010772818778</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.021970999999999997</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-8F</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 8F</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0010772818778</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.022479</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTC-9</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series 9</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0012757285394999999</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BulkHead>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTH-70-120</PartNumber>
+            <Description>Classic Body Tube BTH-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.041957294188</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTH-70-180</PartNumber>
+            <Description>Classic Body Tube BTH-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.062935941282</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTH-70-286</PartNumber>
+            <Description>Classic Body Tube BTH-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.09922333085</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <Length Unit="m">0.72644</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTH-70-300</PartNumber>
+            <Description>Classic Body Tube BTH-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.10489323547</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTH-70-58</PartNumber>
+            <Description>Classic Body Tube BTH-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.020411656631999998</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.057073799999999994</OutsideDiameter>
+            <Length Unit="m">0.14731999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>BTH-80-300</PartNumber>
+            <Description>Classic Body Tube BTH-80</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.14344858688599998</Mass>
+            <InsideDiameter Unit="m">0.0649732</InsideDiameter>
+            <OutsideDiameter Unit="m">0.067056</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CP-12</PartNumber>
+            <Description>12 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Diameter Unit="m">0.30479999999999996</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.30479999999999996</LineLength>
+            <LineMaterial Type="LINE">30 Lb. kevlar</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CP-16</PartNumber>
+            <Description>16 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Diameter Unit="m">0.4064</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.4064</LineLength>
+            <LineMaterial Type="LINE">30 Lb. kevlar</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CP-20</PartNumber>
+            <Description>20 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Diameter Unit="m">0.508</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.508</LineLength>
+            <LineMaterial Type="LINE">30 Lb. kevlar</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CP-24</PartNumber>
+            <Description>24 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Diameter Unit="m">0.6095999999999999</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.6095999999999999</LineLength>
+            <LineMaterial Type="LINE">30 Lb. kevlar</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CP-32</PartNumber>
+            <Description>32 in. Plastic Chute</Description>
+            <Material Type="SURFACE">Polyethylene LDPE</Material>
+            <Diameter Unit="m">0.8128</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.8128</LineLength>
+            <LineMaterial Type="LINE">30 Lb. kevlar</LineMaterial>
+        </Parachute>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CPT-7180</PartNumber>
+            <Description>Clear Plastic Body Tube - Series 7</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.010772818778</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0188214</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CPT-722</PartNumber>
+            <Description>Clear Plastic Body Tube - Series 7</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0188214</OutsideDiameter>
+            <Length Unit="m">0.05715</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CPT-8180</PartNumber>
+            <Description>Clear Plastic Body Tube - Series 8</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.013324275856999999</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0226314</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CPT-825</PartNumber>
+            <Description>Clear Plastic Body Tube - Series 8</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.001984466617</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0226314</OutsideDiameter>
+            <Length Unit="m">0.0635</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CPT-835</PartNumber>
+            <Description>Clear Plastic Body Tube - Series 8</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.0025514570789999997</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0226314</OutsideDiameter>
+            <Length Unit="m">0.08889999999999999</Length>
+        </BodyTube>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-10-13</PartNumber>
+            <Description>Centering Ring #10 to #13</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0264668</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0329692</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-10-16</PartNumber>
+            <Description>Centering Ring #10 to #16</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0264668</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0405892</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-10-20</PartNumber>
+            <Description>Centering Ring #10 to #20</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0264668</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0507492</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-115-150P</PartNumber>
+            <Description>Centering Ring #115 to #150</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0380492</OutsideDiameter>
+            <Length Unit="m">0.00254</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-115-16P</PartNumber>
+            <Description>Centering Ring #115 to #16</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0405892</OutsideDiameter>
+            <Length Unit="m">0.002794</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-115-175P</PartNumber>
+            <Description>Centering Ring #115 to #175</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0443992</OutsideDiameter>
+            <Length Unit="m">0.00254</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-115-18</PartNumber>
+            <Description>Centering Ring #115 to #18</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0456692</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-115-225P</PartNumber>
+            <Description>Centering Ring #115 to #225</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0570992</OutsideDiameter>
+            <Length Unit="m">0.00254</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-115-275P</PartNumber>
+            <Description>Centering Ring #115 to #275</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0697992</OutsideDiameter>
+            <Length Unit="m">0.00254</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-11516</PartNumber>
+            <Description>Centering Ring #115 to #16</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0405892</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-11520</PartNumber>
+            <Description>Centering Ring #115 to #20</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0507492</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-50-18</PartNumber>
+            <Description>Centering Ring BT-50 to #18</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0456692</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-510</PartNumber>
+            <Description>Centering Ring #5 to #10</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013843000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-513</PartNumber>
+            <Description>Centering Ring #5 to #13</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013843000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0329692</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-57</PartNumber>
+            <Description>Centering Ring #5 to #7</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013843000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0181102</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-58</PartNumber>
+            <Description>Centering Ring #5 to #8</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013843000000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.021920199999999997</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-710</PartNumber>
+            <Description>Centering Ring #7 to #10</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-711</PartNumber>
+            <Description>Centering Ring #7 to #11</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.028194</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-713</PartNumber>
+            <Description>Centering Ring #7 to #13</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0329692</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-716</PartNumber>
+            <Description>Centering Ring #7 to #16</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0405892</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-718</PartNumber>
+            <Description>Centering Ring #7 to #18</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0456692</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-720</PartNumber>
+            <Description>Centering Ring #7 to #20</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0507492</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-78</PartNumber>
+            <Description>Centering Ring #7 to #8</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.021920199999999997</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-78F</PartNumber>
+            <Description>Centering Ring #7 to #8F</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0224282</OutsideDiameter>
+            <Length Unit="m">0.001778</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-78L</PartNumber>
+            <Description>Centering Ring #7 to #8</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.021920199999999997</OutsideDiameter>
+            <Length Unit="m">0.002032</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-79</PartNumber>
+            <Description>Centering Ring #7 to #9</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9-13</PartNumber>
+            <Description>Centering Ring #9 to #13</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0329692</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9-150P</PartNumber>
+            <Description>Centering Ring #9 to #150</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0380492</OutsideDiameter>
+            <Length Unit="m">0.002794</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9-16P</PartNumber>
+            <Description>Centering Ring #9 to #16</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0405892</OutsideDiameter>
+            <Length Unit="m">0.002794</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9-20</PartNumber>
+            <Description>Centering Ring #9 to #20</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0507492</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9-225P</PartNumber>
+            <Description>Centering Ring #9 to #225</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0570992</OutsideDiameter>
+            <Length Unit="m">0.002794</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9-70</PartNumber>
+            <Description>Centering Ring #9 to BT-70</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0551942</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9-80</PartNumber>
+            <Description>Centering Ring #9 to BT-80</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0651764</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9-80P</PartNumber>
+            <Description>Centering Ring #9 to BT-80</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0651764</OutsideDiameter>
+            <Length Unit="m">0.002794</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-9115</PartNumber>
+            <Description>Centering Ring #9 to #115</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.028448</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-916</PartNumber>
+            <Description>Centering Ring #9 to #16</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0405892</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>CR-918</PartNumber>
+            <Description>Centering Ring #9 to #18</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0456692</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>EB-20A</PartNumber>
+            <Description>Engine Block BT-20</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013131799999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>EB-20B</PartNumber>
+            <Description>Engine Block BT-20</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013131799999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.003175</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>EB-30</PartNumber>
+            <Description>Engine Block BT-30</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0135128</InsideDiameter>
+            <OutsideDiameter Unit="m">0.018364199999999997</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </EngineBlock>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-10</PartNumber>
+            <Description>Tube Coupler Series 10</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0018143694784</Mass>
+            <InsideDiameter Unit="m">0.0243332</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0254</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-11</PartNumber>
+            <Description>Tube Coupler Series 11</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0020128161401</Mass>
+            <InsideDiameter Unit="m">0.027635200000000002</InsideDiameter>
+            <OutsideDiameter Unit="m">0.028701999999999995</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-13</PartNumber>
+            <Description>Tube Coupler Series 13</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0035436903875</Mass>
+            <InsideDiameter Unit="m">0.0319532</InsideDiameter>
+            <OutsideDiameter Unit="m">0.03302</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-16</PartNumber>
+            <Description>Tube Coupler Series 16</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.004961166542499999</Mass>
+            <InsideDiameter Unit="m">0.0395732</InsideDiameter>
+            <OutsideDiameter Unit="m">0.04064</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-18</PartNumber>
+            <Description>Tube Coupler Series 18</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <InsideDiameter Unit="m">0.0446532</InsideDiameter>
+            <OutsideDiameter Unit="m">0.04572</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-20</PartNumber>
+            <Description>Tube Coupler Series 20</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0075126236215</Mass>
+            <InsideDiameter Unit="m">0.0497332</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0508</OutsideDiameter>
+            <Length Unit="m">0.05334</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-5</PartNumber>
+            <Description>Tube Coupler Series 5</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <InsideDiameter Unit="m">0.0120142</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013081</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-7</PartNumber>
+            <Description>Tube Coupler Series 7</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">7.370876006E-4</Mass>
+            <InsideDiameter Unit="m">0.0170942</InsideDiameter>
+            <OutsideDiameter Unit="m">0.018161</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-7B</PartNumber>
+            <Description>Tube Coupler Series 7</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">7.370876006E-4</Mass>
+            <InsideDiameter Unit="m">0.018262599999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0193294</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-8</PartNumber>
+            <Description>Tube Coupler Series 8</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0010772818778</Mass>
+            <InsideDiameter Unit="m">0.020904199999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.021970999999999997</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-8F</PartNumber>
+            <Description>Tube Coupler Series 8F</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0011056314009</Mass>
+            <InsideDiameter Unit="m">0.0214122</InsideDiameter>
+            <OutsideDiameter Unit="m">0.022479</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>HTC-9</PartNumber>
+            <Description>Tube Coupler Series 9</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0011623304471</Mass>
+            <InsideDiameter Unit="m">0.0230632</InsideDiameter>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>JT-20C</PartNumber>
+            <Description>Tube Coupler Series BT-20</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">7.370876006E-4</Mass>
+            <InsideDiameter Unit="m">0.0169672</InsideDiameter>
+            <OutsideDiameter Unit="m">0.018033999999999998</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>JT-50C</PartNumber>
+            <Description>Tube Coupler Series BT-50</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0011056314009</Mass>
+            <InsideDiameter Unit="m">0.0230632</InsideDiameter>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>JT-55C</PartNumber>
+            <Description>Tube Coupler Series BT-55</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0013891266319</Mass>
+            <InsideDiameter Unit="m">0.0315214</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>JT-5C</PartNumber>
+            <Description>Tube Coupler Series BT-5</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <InsideDiameter Unit="m">0.0120142</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013081</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>JT-60C</PartNumber>
+            <Description>Tube Coupler Series BT-60</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0015592237705</Mass>
+            <InsideDiameter Unit="m">0.039446199999999994</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040513</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>JT-70D</PartNumber>
+            <Description>Tube Coupler Series BT-70</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0024664085097</Mass>
+            <InsideDiameter Unit="m">0.054178199999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.015875</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>JT-70E</PartNumber>
+            <Description>Tube Coupler Series BT-70</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.0157906843667</Mass>
+            <InsideDiameter Unit="m">0.054178199999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <TubeCoupler>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>JT-80E</PartNumber>
+            <Description>Tube Coupler Series BT-80</Description>
+            <Material Type="BULK">Paper</Material>
+            <Mass Unit="kg">0.020695151863</Mass>
+            <InsideDiameter Unit="m">0.0638556</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0649224</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </TubeCoupler>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-103</PartNumber>
+            <Description>Launch Lug 1/8 x .375</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.009524999999999999</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-110</PartNumber>
+            <Description>Launch Lug 1/8 x 1</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-115</PartNumber>
+            <Description>Launch Lug 1/8 x 1.5</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-117</PartNumber>
+            <Description>Launch Lug 1/8 x 1.75</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-122</PartNumber>
+            <Description>Launch Lug 1/8 x 2.25</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.05715</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-130</PartNumber>
+            <Description>Launch Lug 1/8 x 3</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-180</PartNumber>
+            <Description>Launch Lug 1/8 x 8</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-195</PartNumber>
+            <Description>Launch Lug 1/8 x 9.5</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.2413</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-2A</PartNumber>
+            <Description>Launch Lug 1/8 x 1.25</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.03175</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-2AM</PartNumber>
+            <Description>Launch Lug 1/8 x .375</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.009524999999999999</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-2B</PartNumber>
+            <Description>Launch Lug 1/8 x 2.375</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.060325</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-2C</PartNumber>
+            <Description>Launch Lug 1/8 x 5</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-2D</PartNumber>
+            <Description>Launch Lug 1/8 x 8</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-2E</PartNumber>
+            <Description>Launch Lug 1/8 x 9.5</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0038099999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.004470399999999999</OutsideDiameter>
+            <Length Unit="m">0.2413</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-310</PartNumber>
+            <Description>Launch Lug 3/16 x 1</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0054356</InsideDiameter>
+            <OutsideDiameter Unit="m">0.006096</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-320</PartNumber>
+            <Description>Launch Lug 3/16 x 2</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0054356</InsideDiameter>
+            <OutsideDiameter Unit="m">0.006096</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-330</PartNumber>
+            <Description>Launch Lug 3/16 x 3</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0054356</InsideDiameter>
+            <OutsideDiameter Unit="m">0.006096</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-3B</PartNumber>
+            <Description>Launch Lug 3/16 x 2</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0054356</InsideDiameter>
+            <OutsideDiameter Unit="m">0.006096</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </LaunchLug>
+        <LaunchLug>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LL-423</PartNumber>
+            <Description>Launch Lug 1/4 x 2.25</Description>
+            <Material Type="BULK">Paper</Material>
+            <InsideDiameter Unit="m">0.0070104</InsideDiameter>
+            <OutsideDiameter Unit="m">0.007670799999999999</OutsideDiameter>
+            <Length Unit="m">0.05715</Length>
+        </LaunchLug>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-085160</PartNumber>
+            <Description>Large Body Tube - Series 085</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.02267961848</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024002999999999997</OutsideDiameter>
+            <Length Unit="m">0.4064</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-085220</PartNumber>
+            <Description>Large Body Tube - Series 085</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.031184475410000002</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024002999999999997</OutsideDiameter>
+            <Length Unit="m">0.5588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-085300</PartNumber>
+            <Description>Large Body Tube - Series 085</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.04252428465</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024002999999999997</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-08580</PartNumber>
+            <Description>Large Body Tube - Series 085</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.01133980924</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024002999999999997</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-115220</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.051596132042000004</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.5588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-11530</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0070306817288</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-115300</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.07030681728799999</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-11535</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.008193012175899999</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.08889999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-11550</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.011708353040299999</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-11555</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.012757285395</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.1397</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-11560</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.01417476155</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-11575</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.017576704321999998</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.1905</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-11580</PartNumber>
+            <Description>Large Body Tube - Series 115</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.018710685246</Mass>
+            <InsideDiameter Unit="m">0.028955999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.030987999999999998</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-125122</PartNumber>
+            <Description>Large Body Tube - Series 125</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.026365056483000002</Mass>
+            <InsideDiameter Unit="m">0.03175</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.31115</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-125157</PartNumber>
+            <Description>Large Body Tube - Series 125</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.034019427719999995</Mass>
+            <InsideDiameter Unit="m">0.03175</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.40004999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-125220</PartNumber>
+            <Description>Large Body Tube - Series 125</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.063786426975</Mass>
+            <InsideDiameter Unit="m">0.03175</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.5588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-125300</PartNumber>
+            <Description>Large Body Tube - Series 125</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.08646604545499999</Mass>
+            <InsideDiameter Unit="m">0.03175</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-12580</PartNumber>
+            <Description>Large Body Tube - Series 125</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.022963113711000002</Mass>
+            <InsideDiameter Unit="m">0.03175</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-150220</PartNumber>
+            <Description>Large Body Tube - Series 150</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.063786426975</Mass>
+            <InsideDiameter Unit="m">0.038099999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <Length Unit="m">0.5588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-150300</PartNumber>
+            <Description>Large Body Tube - Series 150</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.08646604545499999</Mass>
+            <InsideDiameter Unit="m">0.038099999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-15080</PartNumber>
+            <Description>Large Body Tube - Series 150</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.027499037407</Mass>
+            <InsideDiameter Unit="m">0.038099999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.040386</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-175220</PartNumber>
+            <Description>Large Body Tube - Series 175</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.08788352161</Mass>
+            <InsideDiameter Unit="m">0.044449999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.5588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-175300</PartNumber>
+            <Description>Large Body Tube - Series 175</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.11991848271300001</Mass>
+            <InsideDiameter Unit="m">0.044449999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-17580</PartNumber>
+            <Description>Large Body Tube - Series 175</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.032034961103</Mass>
+            <InsideDiameter Unit="m">0.044449999999999996</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-200220</PartNumber>
+            <Description>Large Body Tube - Series 200</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.099790321312</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.052832</OutsideDiameter>
+            <Length Unit="m">0.5588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-200300</PartNumber>
+            <Description>Large Body Tube - Series 200</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.13607771087999998</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.052832</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-20080</PartNumber>
+            <Description>Large Body Tube - Series 200</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0217724337408</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.052832</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-225140</PartNumber>
+            <Description>Large Body Tube - Series 225</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.071440798212</Mass>
+            <InsideDiameter Unit="m">0.05715</InsideDiameter>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <Length Unit="m">0.35559999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-225220</PartNumber>
+            <Description>Large Body Tube - Series 225</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.11254760670700001</Mass>
+            <InsideDiameter Unit="m">0.05715</InsideDiameter>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <Length Unit="m">0.5588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-225300</PartNumber>
+            <Description>Large Body Tube - Series 225</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.153370919971</Mass>
+            <InsideDiameter Unit="m">0.05715</InsideDiameter>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-22580</PartNumber>
+            <Description>Large Body Tube - Series 225</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.040823313263999995</Mass>
+            <InsideDiameter Unit="m">0.05715</InsideDiameter>
+            <OutsideDiameter Unit="m">0.059435999999999996</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-275220</PartNumber>
+            <Description>Large Body Tube - Series 275</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.136928196573</Mass>
+            <InsideDiameter Unit="m">0.06985</InsideDiameter>
+            <OutsideDiameter Unit="m">0.07213599999999999</OutsideDiameter>
+            <Length Unit="m">0.5588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-275300</PartNumber>
+            <Description>Large Body Tube - Series 275</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.18682335722899998</Mass>
+            <InsideDiameter Unit="m">0.06985</InsideDiameter>
+            <OutsideDiameter Unit="m">0.07213599999999999</OutsideDiameter>
+            <Length Unit="m">0.762</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>LT-27580</PartNumber>
+            <Description>Large Body Tube - Series 275</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.049895160656</Mass>
+            <InsideDiameter Unit="m">0.06985</InsideDiameter>
+            <OutsideDiameter Unit="m">0.07213599999999999</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-20</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.018033999999999998</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-3</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-3</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">1.9844666169999999E-4</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.008864599999999999</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-30</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-30</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">5.66990462E-4</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.018414999999999997</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-40</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-40</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">7.937866467999999E-4</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.019431</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-5</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-5</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">2.83495231E-4</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.013081</OutsideDiameter>
+            <Length Unit="m">0.019049999999999997</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-50</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-50</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-50L</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-50</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0021829132787</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.02413</OutsideDiameter>
+            <Length Unit="m">0.030225999999999996</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-55</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-55</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0032601951565</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0325882</OutsideDiameter>
+            <Length Unit="m">0.03175</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-60</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.040513</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-65</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-65</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.044449999999999996</OutsideDiameter>
+            <Length Unit="m">0.044449999999999996</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-70</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-70</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.055244999999999995</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BulkHead>
+        <BulkHead>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>NB-80</PartNumber>
+            <Description>Semroc Solid Balsa Tube Adapter - Series BT-80</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010489323547</Mass>
+            <Filled>true</Filled>
+            <OutsideDiameter Unit="m">0.0649732</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BulkHead>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PN-14</PartNumber>
+            <Description>14 in. Nylon Chute</Description>
+            <Material Type="SURFACE">Rip Stop Nylon</Material>
+            <Diameter Unit="m">0.35559999999999997</Diameter>
+            <Sides>6</Sides>
+            <LineCount>6</LineCount>
+            <LineLength Unit="m">0.4064</LineLength>
+            <LineMaterial Type="LINE">1/16 In. braided nylon</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PN-18</PartNumber>
+            <Description>18 In. Nylon Chute</Description>
+            <Material Type="SURFACE">Rip Stop Nylon</Material>
+            <Diameter Unit="m">0.4572</Diameter>
+            <Sides>8</Sides>
+            <LineCount>8</LineCount>
+            <LineLength Unit="m">0.508</LineLength>
+            <LineMaterial Type="LINE">1/16 In. braided nylon</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PN-24</PartNumber>
+            <Description>24 In. Nylon Chute</Description>
+            <Material Type="SURFACE">Rip Stop Nylon</Material>
+            <Diameter Unit="m">0.6095999999999999</Diameter>
+            <Sides>0</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">0.6095999999999999</LineLength>
+            <LineMaterial Type="LINE">1/16 In. braided nylon</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PN-30</PartNumber>
+            <Description>30 In. Nylon Chute</Description>
+            <Material Type="SURFACE">Rip Stop Nylon</Material>
+            <Diameter Unit="m">0.762</Diameter>
+            <Sides>0</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">0.762</LineLength>
+            <LineMaterial Type="LINE">1/16 In. braided nylon</LineMaterial>
+        </Parachute>
+        <Parachute>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PN-36</PartNumber>
+            <Description>36 In. Nylon Chute</Description>
+            <Material Type="SURFACE">Rip Stop Nylon</Material>
+            <Diameter Unit="m">0.9144</Diameter>
+            <Sides>0</Sides>
+            <LineCount>10</LineCount>
+            <LineLength Unit="m">0.9144</LineLength>
+            <LineMaterial Type="LINE">1/16 In. braided nylon</LineMaterial>
+        </Parachute>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PST-50MJ</PartNumber>
+            <Description>Clear Plastic Body Tube - BT50</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PST-50S</PartNumber>
+            <Description>Clear Plastic Body Tube - BT50</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.024790399999999997</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PST-55</PartNumber>
+            <Description>Clear Plastic Body Tube - BT55</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.012757285395</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>PST-55-180</PartNumber>
+            <Description>Clear Plastic Body Tube - BT55</Description>
+            <Material Type="BULK">Polycarbonate</Material>
+            <Mass Unit="kg">0.018994180477</Mass>
+            <InsideDiameter Unit="m">0.0325882</InsideDiameter>
+            <OutsideDiameter Unit="m">0.033655</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-115-70P</PartNumber>
+            <Description>Centering Ring #115 to BT-70</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0551942</OutsideDiameter>
+            <Length Unit="m">0.002794</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-115-80P</PartNumber>
+            <Description>Centering Ring #115 to BT-80</Description>
+            <Material Type="BULK">lite ply</Material>
+            <InsideDiameter Unit="m">0.0310388</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0651764</OutsideDiameter>
+            <Length Unit="m">0.002794</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-2050</PartNumber>
+            <Description>Centering Ring BT-20 to BT-50</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-2055</PartNumber>
+            <Description>Centering Ring BT-20 to BT-55</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.032537399999999994</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-2060</PartNumber>
+            <Description>Centering Ring BT-20 to BT-60</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-2070</PartNumber>
+            <Description>Centering Ring BT-20 to BT-70</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0551942</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-2080</PartNumber>
+            <Description>Centering Ring BT-20 to BT-80</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0187452</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0651764</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-5055</PartNumber>
+            <Description>Centering Ring BT-50 to BT-55</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.032537399999999994</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-5060</PartNumber>
+            <Description>Centering Ring BT-50 to BT-60</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-5070</PartNumber>
+            <Description>Centering Ring BT-50 to BT-70</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0551942</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-5080</PartNumber>
+            <Description>Centering Ring BT-50 to BT-80</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0651764</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-520</PartNumber>
+            <Description>Centering Ring BT-5 to BT-20</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013792200000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.017983199999999998</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-550</PartNumber>
+            <Description>Centering Ring BT-5 to BT-50</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013792200000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-555</PartNumber>
+            <Description>Centering Ring BT-5 to BT-55</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013792200000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.032537399999999994</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-5560</PartNumber>
+            <Description>Centering Ring BT-55 to BT-60</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.025730199999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-560</PartNumber>
+            <Description>Centering Ring BT-5 to BT-60</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.013792200000000001</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RA-7080</PartNumber>
+            <Description>Centering Ring BT-70 to BT-80</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.05636259999999999</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0651764</OutsideDiameter>
+            <Length Unit="m">0.00127</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RAH-5055</PartNumber>
+            <Description>Centering Ring BT-50 to BT-55</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.032537399999999994</OutsideDiameter>
+            <Length Unit="m">0.001778</Length>
+        </CenteringRing>
+        <CenteringRing>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RAH-5060</PartNumber>
+            <Description>Centering Ring BT-50 to BT-60</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.024841199999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0404622</OutsideDiameter>
+            <Length Unit="m">0.001778</Length>
+        </CenteringRing>
+        <Streamer>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RS-118</PartNumber>
+            <Description>Streamer 1 x 18</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">0.4572</Length>
+            <Width Unit="m">0.0254</Width>
+            <Thickness Unit="m">5.08E-5</Thickness>
+        </Streamer>
+        <Streamer>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RS-124</PartNumber>
+            <Description>Streamer 1 x 24</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">0.6095999999999999</Length>
+            <Width Unit="m">0.0254</Width>
+            <Thickness Unit="m">5.08E-5</Thickness>
+        </Streamer>
+        <Streamer>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RS-136</PartNumber>
+            <Description>Streamer 1 x 36</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">0.9144</Length>
+            <Width Unit="m">0.0254</Width>
+            <Thickness Unit="m">5.08E-5</Thickness>
+        </Streamer>
+        <Streamer>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RS-224</PartNumber>
+            <Description>Streamer 1.75 x 24</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">0.6095999999999999</Length>
+            <Width Unit="m">0.044449999999999996</Width>
+            <Thickness Unit="m">5.08E-5</Thickness>
+        </Streamer>
+        <Streamer>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RS-236</PartNumber>
+            <Description>Streamer 1.75 x 36</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">0.9144</Length>
+            <Width Unit="m">0.044449999999999996</Width>
+            <Thickness Unit="m">5.08E-5</Thickness>
+        </Streamer>
+        <Streamer>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RSW-36</PartNumber>
+            <Description>Streamer 3 x 36</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">0.9144</Length>
+            <Width Unit="m">0.07619999999999999</Width>
+            <Thickness Unit="m">5.08E-5</Thickness>
+        </Streamer>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RT-70</PartNumber>
+            <Description>Classic Body Tube BT-70</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0025514570789999997</Mass>
+            <InsideDiameter Unit="m">0.055244999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0563118</OutsideDiameter>
+            <Length Unit="m">0.017272</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>RT-99D</PartNumber>
+            <Description>Classic Body Tube BT-99</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.040256322802</Mass>
+            <InsideDiameter Unit="m">0.0931672</InsideDiameter>
+            <OutsideDiameter Unit="m">0.09398</OutsideDiameter>
+            <Length Unit="m">0.009906</Length>
+        </BodyTube>
+        <Streamer>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>SM-1A</PartNumber>
+            <Description>Streamer 1 x 8</Description>
+            <Material Type="SURFACE">Paper</Material>
+            <Length Unit="m">0.2032</Length>
+            <Width Unit="m">0.0254</Width>
+            <Thickness Unit="m">5.08E-5</Thickness>
+        </Streamer>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-10100</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.008703303591699999</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.254</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-10105</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0091568959613</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.2667</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-10120</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0104609740239</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-10180</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0156772862743</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1020</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0017293209090999998</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1030</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0026081561252</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1040</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0034869913413</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1050</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0043658265574</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1060</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0052163122504</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1080</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0069739826826</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1095</PartNumber>
+            <Description>Standard Body Tube - Series 10</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0082780607452</Mass>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.026416</OutsideDiameter>
+            <Length Unit="m">0.2413</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-11120</PartNumber>
+            <Description>Standard Body Tube - Series 11</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0122469939792</Mass>
+            <InsideDiameter Unit="m">0.028701999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.029717999999999998</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-11180</PartNumber>
+            <Description>Standard Body Tube - Series 11</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.018370490968800002</Mass>
+            <InsideDiameter Unit="m">0.028701999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.029717999999999998</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1160</PartNumber>
+            <Description>Standard Body Tube - Series 11</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0061234969896</Mass>
+            <InsideDiameter Unit="m">0.028701999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.029717999999999998</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1180</PartNumber>
+            <Description>Standard Body Tube - Series 11</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0081646626528</Mass>
+            <InsideDiameter Unit="m">0.028701999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.029717999999999998</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1190</PartNumber>
+            <Description>Standard Body Tube - Series 11</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.009185245484400001</Mass>
+            <InsideDiameter Unit="m">0.028701999999999995</InsideDiameter>
+            <OutsideDiameter Unit="m">0.029717999999999998</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-13105</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0123603920716</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.2667</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-13130</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.015308742474000001</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.3302</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-13135</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.015875732936</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.3429</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-13180</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0211770937557</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1322</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0025798066020999997</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.05588</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1330</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0035436903875</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1340</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0047060208346</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1363</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.007370876006</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.15875</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1380</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0094120416692</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1383</PartNumber>
+            <Description>Standard Body Tube - Series 13</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0096955369002</Mass>
+            <InsideDiameter Unit="m">0.03302</InsideDiameter>
+            <OutsideDiameter Unit="m">0.034036000000000004</OutsideDiameter>
+            <Length Unit="m">0.20955</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16100</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0144299072579</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.254</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16109</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0157339853205</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.27686</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16110</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.015875732936</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.2794</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16120</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.017293209091</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16128</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0184555395381</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.32512</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16130</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.018767384292200002</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.3302</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16132</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0190508795232</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.33527999999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16151</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.021829132787</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.38404799999999994</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16160</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.023076511803399997</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.4064</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16161</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0232749584651</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.40957499999999997</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16163</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0234450556037</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.41275</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-16180</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0259681631596</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1620</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0028916513562</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1622</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0032318456334</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.05715</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1630</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0043374770343</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1650</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0072007788674</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1652</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0075693226677</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.13335</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1660</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0086466045455</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1667</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.009667187377100001</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.17018</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1675</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0108295178242</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.1905</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1685</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0122469939792</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.21589999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1690</PartNumber>
+            <Description>Standard Body Tube - Series 16</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0129840815798</Mass>
+            <InsideDiameter Unit="m">0.04064</InsideDiameter>
+            <OutsideDiameter Unit="m">0.041656</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-18120</PartNumber>
+            <Description>Standard Body Tube - Series 18</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0194477728466</Mass>
+            <InsideDiameter Unit="m">0.04572</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-18180</PartNumber>
+            <Description>Standard Body Tube - Series 18</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.029171659269899997</Mass>
+            <InsideDiameter Unit="m">0.04572</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1830</PartNumber>
+            <Description>Standard Body Tube - Series 18</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0048477684501</Mass>
+            <InsideDiameter Unit="m">0.04572</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1844</PartNumber>
+            <Description>Standard Body Tube - Series 18</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0068322350671</Mass>
+            <InsideDiameter Unit="m">0.04572</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.111125</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1860</PartNumber>
+            <Description>Standard Body Tube - Series 18</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0097238864233</Mass>
+            <InsideDiameter Unit="m">0.04572</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-1890</PartNumber>
+            <Description>Standard Body Tube - Series 18</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0145716548734</Mass>
+            <InsideDiameter Unit="m">0.04572</InsideDiameter>
+            <OutsideDiameter Unit="m">0.046736</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-20120</PartNumber>
+            <Description>Standard Body Tube - Series 20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0216023366022</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-20128</PartNumber>
+            <Description>Standard Body Tube - Series 20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.023076511803399997</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <Length Unit="m">0.32512</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-20180</PartNumber>
+            <Description>Standard Body Tube - Series 20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0324602039495</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-2030</PartNumber>
+            <Description>Standard Body Tube - Series 20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0054147589121</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-2050</PartNumber>
+            <Description>Standard Body Tube - Series 20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0090151483458</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-2060</PartNumber>
+            <Description>Standard Body Tube - Series 20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0108011683011</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-2098</PartNumber>
+            <Description>Standard Body Tube - Series 20</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0176617528913</Mass>
+            <InsideDiameter Unit="m">0.0508</InsideDiameter>
+            <OutsideDiameter Unit="m">0.051816</OutsideDiameter>
+            <Length Unit="m">0.24892</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-5120</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004535923696</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-515</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">5.953399851E-4</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.038099999999999995</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-5180</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0068038855439999995</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-520</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">7.654371237E-4</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-520E</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">7.654371237E-4</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-525</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">9.355342623E-4</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.0635</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-530</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-540</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0015308742474</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-545</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.1143</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-560</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-590</PartNumber>
+            <Description>Standard Body Tube - Series 5</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0034019427719999998</Mass>
+            <InsideDiameter Unit="m">0.013081</InsideDiameter>
+            <OutsideDiameter Unit="m">0.013792200000000001</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-7100</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0044792246498</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.254</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-7120</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0054431084352</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-7180</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0081646626528</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-720</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0010205828316</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-720H</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0010205828316</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-723</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0011056314009</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.05715</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-730</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0013607771088</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-730E</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0013607771088</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-740</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-749</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.002267961848</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.12446</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-753</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0024097094635</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.13335</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-755</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0024664085097</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.1397</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-758</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0026081561252</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.14731999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-760</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0027215542176</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-765</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0029483504024</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.1651</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-770</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0031751465871999998</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.17779999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-790</PartNumber>
+            <Description>Standard Body Tube - Series 7</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0040823313264</Mass>
+            <InsideDiameter Unit="m">0.018161</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0192786</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8100</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.254</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8103</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0073141769598</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.26162</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8113</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.008022915037299998</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.28702</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8120</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.010205828315999999</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8150</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0106310711625</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.381</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8180</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.012757285395</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-820</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.001417476155</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.0508</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-823</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0015592237705</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.05715</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-825</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0017860199553</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.0635</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-830</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0021262142324999997</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-845</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0032034961103</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.1143</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-855</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0039122341878</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.1397</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-857</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004053981803299999</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.14478</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-873</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0051879627273</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.18542</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-880</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-890</PartNumber>
+            <Description>Standard Body Tube - Series 8</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0063786426975</Mass>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0230632</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8F120</PartNumber>
+            <Description>Standard Body Tube - Series 8F</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.008504856929999999</Mass>
+            <InsideDiameter Unit="m">0.022479</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0233934</OutsideDiameter>
+            <Length Unit="m">0.30479999999999996</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8F180</PartNumber>
+            <Description>Standard Body Tube - Series 8F</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.012757285395</Mass>
+            <InsideDiameter Unit="m">0.022479</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0233934</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8F60</PartNumber>
+            <Description>Standard Body Tube - Series 8F</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0042240789419</Mass>
+            <InsideDiameter Unit="m">0.022479</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0233934</OutsideDiameter>
+            <Length Unit="m">0.15239999999999998</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-8F90</PartNumber>
+            <Description>Standard Body Tube - Series 8F</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0063786426975</Mass>
+            <InsideDiameter Unit="m">0.022479</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0233934</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-9180</PartNumber>
+            <Description>Standard Body Tube - Series 9</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.014798451058200001</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.4572</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-930</PartNumber>
+            <Description>Standard Body Tube - Series 9</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0024664085097</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.07619999999999999</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-940</PartNumber>
+            <Description>Standard Body Tube - Series 9</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0032885446796</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-940E</PartNumber>
+            <Description>Standard Body Tube - Series 9</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0032885446796</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.1016</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-950</PartNumber>
+            <Description>Standard Body Tube - Series 9</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004110680849499999</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-950E</PartNumber>
+            <Description>Standard Body Tube - Series 9</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.004110680849499999</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.127</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-980</PartNumber>
+            <Description>Standard Body Tube - Series 9</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0065770893592</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.2032</Length>
+        </BodyTube>
+        <BodyTube>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>ST-990</PartNumber>
+            <Description>Standard Body Tube - Series 9</Description>
+            <Material Type="BULK">Spiral/Glassine</Material>
+            <Mass Unit="kg">0.0073992255291000005</Mass>
+            <InsideDiameter Unit="m">0.02413</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0253492</OutsideDiameter>
+            <Length Unit="m">0.2286</Length>
+        </BodyTube>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2050</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-50</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0186944</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2050 [R]</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-50 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.004819418927</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0186944</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2050A</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-50</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0186944</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2050A [R]</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-50 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003118447541</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0186944</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2050B</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-50</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0186944</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2050B [R]</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-50 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0186944</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0635</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2055</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-55</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0186944</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033655</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0325882</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2055 [R]</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-55 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006236895082</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033655</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0325882</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0186944</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2060</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0186944</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-2060 [R]</PartNumber>
+            <Description>Balsa Reducer BT-20 to BT-60 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.00566990462</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0186944</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5055</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-55</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033655</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0325882</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5055 [R]</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-55 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.017009713859999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033655</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0325882</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5055L</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-55</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.020128161401</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033655</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0325882</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5055L [R]</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-55 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.020128161401</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033655</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0325882</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5060</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5060 [R]</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-60 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5060C</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003968933234</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5060C [R]</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-60 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.003968933234</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5060E</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5060E [R]</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-60 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0059533998509999995</Mass>
+            <Filled>true</Filled>
+            <Shape>ELLIPSOID</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5065</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-65</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007370876006</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.045618399999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.044449999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5065 [R]</PartNumber>
+            <Description>Balsa Reducer BT-50 to BT-65 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007370876006</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.045618399999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.044449999999999996</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0508</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-520</PartNumber>
+            <Description>Balsa Reducer BT-5 to BT-20</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0137414</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0186944</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.018033999999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-520 [R]</PartNumber>
+            <Description>Balsa Reducer BT-5 to BT-20 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.001133980924</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0186944</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.018033999999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0137414</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.019049999999999997</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5260A</PartNumber>
+            <Description>Balsa Reducer BT-52 to BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0257556</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.025095199999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5260A [R]</PartNumber>
+            <Description>Balsa Reducer BT-52 to BT-60 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0257556</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.025095199999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5260C</PartNumber>
+            <Description>Balsa Reducer BT-52 to BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009355342623</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0257556</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.025095199999999998</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.09652</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5260C [R]</PartNumber>
+            <Description>Balsa Reducer BT-52 to BT-60 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.009355342623</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0257556</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.025095199999999998</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.09652</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-550</PartNumber>
+            <Description>Balsa Reducer BT-5 to BT-50</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0137414</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.013081</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.024790399999999997</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.02413</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-550 [R]</PartNumber>
+            <Description>Balsa Reducer BT-5 to BT-50 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.0017009713859999999</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.024790399999999997</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.02413</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0137414</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.013081</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5560</PartNumber>
+            <Description>Balsa Reducer BT-55 to BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033655</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0325882</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5560 [R]</PartNumber>
+            <Description>Balsa Reducer BT-55 to BT-60 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.007087380775</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033655</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0325882</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0254</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5560A</PartNumber>
+            <Description>Balsa Reducer BT-55 to BT-60</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008221361698999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033655</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0325882</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.03175</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5560A [R]</PartNumber>
+            <Description>Balsa Reducer BT-55 to BT-60 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.008221361698999998</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033655</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0325882</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.03175</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5565</PartNumber>
+            <Description>Balsa Reducer BT-55 to BT-65</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010772818778</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.033655</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0325882</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.045618399999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.044449999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-5565 [R]</PartNumber>
+            <Description>Balsa Reducer BT-55 to BT-65 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.010772818778</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.045618399999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.044449999999999996</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.033655</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0325882</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-6065</PartNumber>
+            <Description>Balsa Reducer BT-60 to BT-65</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.045618399999999996</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.044449999999999996</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-6065 [R]</PartNumber>
+            <Description>Balsa Reducer BT-60 to BT-65 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.006520390313</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.045618399999999996</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.044449999999999996</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.0127</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-6070</PartNumber>
+            <Description>Balsa Reducer BT-60 to BT-70</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0563118</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.055244999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-6070 [R]</PartNumber>
+            <Description>Balsa Reducer BT-60 to BT-70 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0563118</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.055244999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-6080</PartNumber>
+            <Description>Balsa Reducer BT-60 to BT-80</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0415798</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.040513</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.06604</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0649732</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-6080 [R]</PartNumber>
+            <Description>Balsa Reducer BT-60 to BT-80 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.06604</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0649732</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0415798</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.040513</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-7080</PartNumber>
+            <Description>Balsa Reducer BT-70 to BT-80</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.0563118</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.055244999999999995</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.06604</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.0649732</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <Transition>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TA-7080 [R]</PartNumber>
+            <Description>Balsa Reducer BT-70 to BT-80 \96 Reversed</Description>
+            <Material Type="BULK">Balsa</Material>
+            <Mass Unit="kg">0.018427190015</Mass>
+            <Filled>true</Filled>
+            <Shape>CONICAL</Shape>
+            <ForeOutsideDiameter Unit="m">0.06604</ForeOutsideDiameter>
+            <ForeShoulderDiameter Unit="m">0.0649732</ForeShoulderDiameter>
+            <ForeShoulderLength Unit="m">0.0127</ForeShoulderLength>
+            <AftOutsideDiameter Unit="m">0.0563118</AftOutsideDiameter>
+            <AftShoulderDiameter Unit="m">0.055244999999999995</AftShoulderDiameter>
+            <AftShoulderLength Unit="m">0.0127</AftShoulderLength>
+            <Length Unit="m">0.038099999999999995</Length>
+        </Transition>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TB-115</PartNumber>
+            <Description>Thrust Block #115</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.028955999999999996</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TB-5</PartNumber>
+            <Description>Thrust Block #5</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0104902</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0130302</OutsideDiameter>
+            <Length Unit="m">0.004775199999999999</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TB-7</PartNumber>
+            <Description>Thrust Block #7</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.014604999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0181102</OutsideDiameter>
+            <Length Unit="m">0.004775199999999999</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TR-115</PartNumber>
+            <Description>Thrust Ring #115</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0254</InsideDiameter>
+            <OutsideDiameter Unit="m">0.028955999999999996</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TR-5</PartNumber>
+            <Description>Thrust Ring #5</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0104902</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0130302</OutsideDiameter>
+            <Length Unit="m">0.009524999999999999</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TR-7</PartNumber>
+            <Description>Thrust Ring #7</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.014604999999999998</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0181102</OutsideDiameter>
+            <Length Unit="m">0.009524999999999999</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TR-9</PartNumber>
+            <Description>Thrust Ring #9</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.0193294</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.00635</Length>
+        </EngineBlock>
+        <EngineBlock>
+            <Manufacturer>SEMROC Astronautics</Manufacturer>
+            <PartNumber>TS-9</PartNumber>
+            <Description>Thrust Spacer #9</Description>
+            <Material Type="BULK">Fiber</Material>
+            <InsideDiameter Unit="m">0.021970999999999997</InsideDiameter>
+            <OutsideDiameter Unit="m">0.0240792</OutsideDiameter>
+            <Length Unit="m">0.0254</Length>
+        </EngineBlock>
+    </Components>
+</OpenRocketComponent>
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_H178.eng b/core/resources/datafiles/thrustcurves/AeroTech_H178.eng
new file mode 100644 (file)
index 0000000..c0564ed
--- /dev/null
@@ -0,0 +1,35 @@
+; H178-14 Dark Matter\r
+H178DM 38 191 14 0.177 0.324 AT\r
+   0.016 132.659\r
+   0.099 165.726\r
+   0.146 162.97\r
+   0.201 163.364\r
+   0.256 164.938\r
+   0.301 168.481\r
+   0.358 173.205\r
+   0.401 176.354\r
+   0.457 177.929\r
+   0.498 183.046\r
+   0.6 198.792\r
+   0.635 204.303\r
+   0.703 204.303\r
+   0.799 215.719\r
+   0.901 210.602\r
+   0.999 211.783\r
+   1.049 205.09\r
+   1.098 206.271\r
+   1.202 196.824\r
+   1.297 178.322\r
+   1.351 172.811\r
+   1.404 178.322\r
+   1.434 186.195\r
+   1.499 125.574\r
+   1.539 71.25\r
+   1.566 44.876\r
+   1.582 31.492\r
+   1.601 27.949\r
+   1.606 16.533\r
+   1.617 18.895\r
+   1.644 8.66\r
+   1.684 4.33\r
+   1.735 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_I327.eng b/core/resources/datafiles/thrustcurves/AeroTech_I327.eng
new file mode 100644 (file)
index 0000000..b768e06
--- /dev/null
@@ -0,0 +1,25 @@
+; I327-14 Dark Matter\r
+I327DM 38 337 14 0.354 0.628 AT\r
+   0.0090 393.741\r
+   0.026 432.602\r
+   0.161 387.142\r
+   0.245 382.742\r
+   0.303 371.011\r
+   0.601 372.477\r
+   0.702 371.011\r
+   0.798 375.41\r
+   0.983 371.744\r
+   1.04 370.278\r
+   1.104 371.744\r
+   1.199 343.148\r
+   1.3 335.816\r
+   1.335 357.813\r
+   1.365 327.751\r
+   1.399 265.427\r
+   1.428 185.505\r
+   1.451 156.91\r
+   1.493 112.183\r
+   1.553 68.19\r
+   1.601 32.262\r
+   1.656 11.732\r
+   1.723 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_I350.eng b/core/resources/datafiles/thrustcurves/AeroTech_I350.eng
new file mode 100644 (file)
index 0000000..224051d
--- /dev/null
@@ -0,0 +1,30 @@
+; Aerotech I350-10R single use motor file created using Aerotech instruction\r
+; sheet data and thrust tracer utility.\r
+I350-10R 38 356 P 0.34800000000000003 0.616 AT\r
+   0.0040 2.809\r
+   0.0080 207.896\r
+   0.031 272.512\r
+   0.035 359.603\r
+   0.046 407.363\r
+   0.081 432.648\r
+   0.104 435.457\r
+   0.127 427.029\r
+   0.184 435.457\r
+   0.223 443.886\r
+   0.299 469.17\r
+   0.399 480.408\r
+   0.503 486.027\r
+   0.603 474.789\r
+   0.702 469.17\r
+   0.802 457.933\r
+   0.906 443.886\r
+   1.002 432.648\r
+   1.098 415.792\r
+   1.205 390.507\r
+   1.298 368.032\r
+   1.401 345.556\r
+   1.443 325.891\r
+   1.497 216.324\r
+   1.532 101.138\r
+   1.57 33.713\r
+   1.605 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_K1103.eng b/core/resources/datafiles/thrustcurves/AeroTech_K1103.eng
new file mode 100644 (file)
index 0000000..2a8d8fa
--- /dev/null
@@ -0,0 +1,26 @@
+; K1103X Propellant X\r
+K1103X 54 401 14 0.8300000000000001 1.459 AT\r
+   0.012 1335.712\r
+   0.016 1505.168\r
+   0.028 1619.8\r
+   0.045 1500.184\r
+   0.081 1393.028\r
+   0.151 1330.728\r
+   0.201 1305.808\r
+   0.399 1280.888\r
+   0.602 1243.508\r
+   0.803 1196.16\r
+   1.001 1143.828\r
+   1.203 1074.052\r
+   1.296 1041.656\r
+   1.384 1031.688\r
+   1.408 1004.276\r
+   1.423 961.912\r
+   1.438 839.804\r
+   1.46 737.632\r
+   1.49 510.86\r
+   1.505 446.068\r
+   1.603 176.932\r
+   1.608 209.328\r
+   1.638 97.188\r
+   1.688 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_K456.eng b/core/resources/datafiles/thrustcurves/AeroTech_K456.eng
new file mode 100644 (file)
index 0000000..10d1f29
--- /dev/null
@@ -0,0 +1,32 @@
+; K456 Dark Matter\r
+K456DM-14A 54 401 14 0.866 1.484 AT\r
+   0.027 444.074\r
+   0.038 519.582\r
+   0.066 482.95\r
+   0.129 461.269\r
+   0.302 467.998\r
+   0.389 468.745\r
+   0.499 476.969\r
+   0.655 476.221\r
+   0.798 483.697\r
+   0.946 488.93\r
+   1.096 499.397\r
+   1.401 500.892\r
+   1.603 503.882\r
+   1.801 501.64\r
+   1.905 498.649\r
+   2.1 485.94\r
+   2.302 456.036\r
+   2.404 435.851\r
+   2.505 420.151\r
+   2.574 398.471\r
+   2.607 373.052\r
+   2.645 356.605\r
+   2.703 289.321\r
+   2.768 178.676\r
+   2.804 123.354\r
+   2.837 88.964\r
+   2.875 50.837\r
+   2.908 24.671\r
+   2.957 10.466\r
+   3.037 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_L1040.eng b/core/resources/datafiles/thrustcurves/AeroTech_L1040.eng
new file mode 100644 (file)
index 0000000..77fe97e
--- /dev/null
@@ -0,0 +1,29 @@
+; L1040 Dark Matter\r
+L1040DM-P 75 681 P 2.602 4.7170000000000005 AT\r
+   0.018 1126.167\r
+   0.042 1036.413\r
+   0.053 1002.543\r
+   0.116 988.995\r
+   0.504 1049.961\r
+   0.794 1095.685\r
+   1.002 1146.489\r
+   1.252 1192.213\r
+   1.499 1237.937\r
+   1.753 1261.646\r
+   1.912 1268.42\r
+   2.095 1254.872\r
+   2.511 1134.635\r
+   2.772 1056.734\r
+   3.012 966.98\r
+   3.153 933.11\r
+   3.217 863.677\r
+   3.291 817.953\r
+   3.34 758.681\r
+   3.488 438.613\r
+   3.552 284.505\r
+   3.598 220.153\r
+   3.657 167.655\r
+   3.746 118.544\r
+   3.88 42.337\r
+   3.996 6.774\r
+   4.127 0.0\r
index 12ebe81980381bb56aa3c98694f406dad77e5d02..1fd9aea1b4eec08358107e044a75c7f4d4530506 100644 (file)
@@ -1,6 +1,6 @@
-; Entered by Tim Van Milligan. Used John Coker's ThrustCurve Tracer software and\r
-; data supplied by Aerotech thrust stand data. The total weight is a guess.\r
-L339N 98 309 4 1.796 4.5 Aerotech\r
+;This file is identical to Tim Van Milligan's L339 file except the motor and\r
+; propellant weights have been corrected.  Total weight was about 50% too high.\r
+L339N 98 309 4 1.355 3.15 Aerotech\r
    0.049 2.884\r
    0.074 373.449\r
    0.123 399.403\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_L339_1.eng b/core/resources/datafiles/thrustcurves/AeroTech_L339_1.eng
new file mode 100644 (file)
index 0000000..12ebe81
--- /dev/null
@@ -0,0 +1,69 @@
+; Entered by Tim Van Milligan. Used John Coker's ThrustCurve Tracer software and\r
+; data supplied by Aerotech thrust stand data. The total weight is a guess.\r
+L339N 98 309 4 1.796 4.5 Aerotech\r
+   0.049 2.884\r
+   0.074 373.449\r
+   0.123 399.403\r
+   0.156 408.054\r
+   0.279 415.984\r
+   0.427 417.426\r
+   0.476 421.031\r
+   0.509 416.705\r
+   0.632 415.984\r
+   0.837 414.542\r
+   0.894 418.868\r
+   0.943 405.17\r
+   1.026 400.124\r
+   1.124 402.286\r
+   1.255 397.961\r
+   1.362 392.914\r
+   1.51 391.472\r
+   1.575 394.356\r
+   1.592 385.705\r
+   1.657 387.147\r
+   1.838 384.984\r
+   2.026 382.821\r
+   2.174 379.937\r
+   2.404 377.053\r
+   2.478 378.495\r
+   2.552 377.053\r
+   2.617 378.495\r
+   2.683 366.96\r
+   2.773 359.751\r
+   2.806 363.355\r
+   2.937 359.751\r
+   3.232 351.099\r
+   3.314 355.425\r
+   3.356 351.099\r
+   3.815 345.332\r
+   3.979 340.285\r
+   4.233 336.681\r
+   4.414 333.797\r
+   4.668 330.913\r
+   4.996 329.471\r
+   5.39 323.704\r
+   5.686 320.099\r
+   5.989 314.331\r
+   6.178 310.727\r
+   6.325 306.401\r
+   6.514 302.075\r
+   6.621 302.075\r
+   6.851 297.75\r
+   7.195 290.54\r
+   7.277 293.424\r
+   7.326 287.656\r
+   7.441 283.331\r
+   7.49 286.214\r
+   7.54 283.331\r
+   7.696 275.4\r
+   7.81 273.958\r
+   7.884 276.842\r
+   7.942 278.284\r
+   8.015 276.121\r
+   8.073 270.354\r
+   8.188 155.003\r
+   8.212 118.956\r
+   8.278 54.071\r
+   8.311 26.675\r
+   8.352 7.93\r
+   8.426 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_L400.eng b/core/resources/datafiles/thrustcurves/AeroTech_L400.eng
new file mode 100644 (file)
index 0000000..8a82d78
--- /dev/null
@@ -0,0 +1,35 @@
+; Aerotech L400W-PS created using TCtracer and AT thrustcurve\r
+L400W 98 443.2 P 2.6489656 5.0847439 AT\r
+   0.031 436.662\r
+   0.062 493.929\r
+   0.063 586.988\r
+   0.108 634.711\r
+   0.154 606.077\r
+   0.277 622.78\r
+   0.4 639.483\r
+   0.508 610.85\r
+   0.538 601.305\r
+   0.908 665.731\r
+   1.092 684.82\r
+   1.631 720.612\r
+   1.954 706.295\r
+   2.385 703.909\r
+   2.6 701.523\r
+   2.769 689.592\r
+   3.2 656.186\r
+   3.754 586.988\r
+   4.354 527.335\r
+   5.262 434.276\r
+   5.815 386.553\r
+   6.477 336.445\r
+   7.354 276.791\r
+   8.046 217.138\r
+   8.846 167.029\r
+   9.862 107.376\r
+   10.969 64.426\r
+   11.969 40.564\r
+   12.969 26.247\r
+   13.985 14.317\r
+   14.938 7.158\r
+   15.462 2.386\r
+   15.938 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_L900.eng b/core/resources/datafiles/thrustcurves/AeroTech_L900.eng
new file mode 100644 (file)
index 0000000..d643a68
--- /dev/null
@@ -0,0 +1,30 @@
+; L900 Dark Matter\r
+L900DM 75 665.5 P 2.472 4.724 AT\r
+   0.016 577.998\r
+   0.041 870.377\r
+   0.086 851.787\r
+   0.303 931.219\r
+   0.417 944.74\r
+   0.515 910.939\r
+   0.998 936.289\r
+   1.272 976.851\r
+   1.501 992.061\r
+   1.747 1019.102\r
+   2.0 1029.242\r
+   2.205 1054.593\r
+   2.495 1047.833\r
+   2.77 1034.313\r
+   3.003 998.821\r
+   3.166 981.921\r
+   3.498 909.249\r
+   3.592 880.518\r
+   3.702 890.658\r
+   3.768 856.857\r
+   3.862 672.641\r
+   3.964 442.794\r
+   4.021 353.221\r
+   4.111 285.619\r
+   4.242 104.783\r
+   4.3 50.702\r
+   4.369 21.971\r
+   4.484 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_M1075.eng b/core/resources/datafiles/thrustcurves/AeroTech_M1075.eng
new file mode 100644 (file)
index 0000000..60d04ee
--- /dev/null
@@ -0,0 +1,24 @@
+; M1075 Dark Matter\r
+M1075DM 98 597 P 3.846 6.971 AT\r
+   0.02 927.501\r
+   0.112 988.073\r
+   0.26 1033.501\r
+   0.53 1080.823\r
+   0.897 1124.359\r
+   1.509 1198.18\r
+   1.998 1239.823\r
+   2.355 1260.644\r
+   2.503 1264.43\r
+   2.773 1237.93\r
+   2.997 1222.787\r
+   3.502 1162.216\r
+   4.001 1063.787\r
+   4.501 906.68\r
+   4.741 834.751\r
+   4.878 742.001\r
+   4.96 664.394\r
+   5.062 448.608\r
+   5.164 223.357\r
+   5.26 79.5\r
+   5.352 30.286\r
+   5.5 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_M1305.eng b/core/resources/datafiles/thrustcurves/AeroTech_M1305.eng
new file mode 100644 (file)
index 0000000..f90657f
--- /dev/null
@@ -0,0 +1,31 @@
+; M1305 Metalstorm\r
+M1305M 98 597 P 4.08 7.098 AT\r
+   0.016 1288.076\r
+   0.043 1462.78\r
+   0.08 1370.986\r
+   0.407 1622.679\r
+   0.535 1640.446\r
+   0.787 1705.59\r
+   0.985 1693.745\r
+   1.13 1717.434\r
+   1.328 1693.745\r
+   1.349 1927.672\r
+   1.397 1726.317\r
+   1.751 1711.512\r
+   2.018 1687.823\r
+   2.275 1690.784\r
+   2.297 1892.139\r
+   2.318 1678.94\r
+   2.929 1412.441\r
+   3.748 1113.371\r
+   4.24 906.095\r
+   4.503 802.456\r
+   4.717 663.285\r
+   4.813 538.919\r
+   4.92 387.903\r
+   5.027 245.771\r
+   5.166 145.094\r
+   5.263 79.95\r
+   5.386 32.572\r
+   5.498 23.689\r
+   5.707 0.0\r
index 42b6beb7a730b1a074754bb6cf38dfc85f72beba..6bc79404df0cbd3e837999c612e0efb547687106 100644 (file)
@@ -1,23 +1,42 @@
-M1780 75 665 P 2.56 4.715 AT\r
-   0.028 2204.193\r
-   0.118 2566.025\r
-   0.173 2566.025\r
-   0.341 2214.151\r
-   0.44 2144.44\r
-   0.636 2114.564\r
-   1.34 2134.482\r
-   1.395 2204.193\r
-   1.648 2121.203\r
-   1.841 2041.534\r
-   1.874 1895.473\r
-   2.127 1643.186\r
-   2.353 1517.042\r
-   2.584 1460.61\r
-   2.672 1347.744\r
-   2.763 1068.901\r
-   2.829 723.666\r
-   2.939 438.183\r
-   2.999 292.122\r
-   3.101 172.617\r
-   3.272 36.515\r
-   3.5 0.0\r
+; AT M1780NT 1" Core Revised\r
+M1780NT 75 665 P 2.371 4.606 AT\r
+   0.0090 1337.154\r
+   0.026 2005.731\r
+   0.04 2106.521\r
+   0.046 2163.636\r
+   0.085 2156.916\r
+   0.108 2126.679\r
+   0.134 2113.24\r
+   0.168 2130.039\r
+   0.205 2126.679\r
+   0.259 2197.233\r
+   0.299 2156.916\r
+   0.347 2130.039\r
+   0.399 2123.32\r
+   0.495 2103.161\r
+   0.595 2089.723\r
+   0.697 2079.644\r
+   0.8 2083.003\r
+   0.9 2076.284\r
+   0.999 2069.565\r
+   1.201 2056.126\r
+   1.398 2029.248\r
+   1.603 2002.371\r
+   1.799 1965.414\r
+   1.998 1904.94\r
+   2.2 1817.588\r
+   2.3 1757.114\r
+   2.354 1723.517\r
+   2.405 1713.438\r
+   2.46 1629.446\r
+   2.502 1558.893\r
+   2.571 1333.794\r
+   2.622 1115.415\r
+   2.67 890.316\r
+   2.724 665.217\r
+   2.758 571.146\r
+   2.798 507.312\r
+   2.83 446.838\r
+   2.901 265.415\r
+   3.003 73.913\r
+   3.035 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/AeroTech_M1780_1.eng b/core/resources/datafiles/thrustcurves/AeroTech_M1780_1.eng
new file mode 100644 (file)
index 0000000..42b6beb
--- /dev/null
@@ -0,0 +1,23 @@
+M1780 75 665 P 2.56 4.715 AT\r
+   0.028 2204.193\r
+   0.118 2566.025\r
+   0.173 2566.025\r
+   0.341 2214.151\r
+   0.44 2144.44\r
+   0.636 2114.564\r
+   1.34 2134.482\r
+   1.395 2204.193\r
+   1.648 2121.203\r
+   1.841 2041.534\r
+   1.874 1895.473\r
+   2.127 1643.186\r
+   2.353 1517.042\r
+   2.584 1460.61\r
+   2.672 1347.744\r
+   2.763 1068.901\r
+   2.829 723.666\r
+   2.939 438.183\r
+   2.999 292.122\r
+   3.101 172.617\r
+   3.272 36.515\r
+   3.5 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_E22.rse b/core/resources/datafiles/thrustcurves/Cesaroni_E22.rse
new file mode 100644 (file)
index 0000000..896ad0b
--- /dev/null
@@ -0,0 +1,31 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="24-E22-SS-13A" Type="unspecified" dia="24." len="69."\r
+initWt="56.5" propWt="20.3" delays="13,10,8,6,4" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="22.327" peakThrust="30.792" throatDia="0."\r
+exitDia="0." Itot="24.27" burn-time="1.09" massFrac="35.93" Isp="121.91"\r
+tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
+mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>Smoky Sam 24mm 1G\r
+24-E22-SS-13A\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="20.3" cg="34.5"/>\r
+      <eng-data  t="0.008" f="18.292" m="20.2388" cg="34.5"/>\r
+      <eng-data  t="0.026" f="30." m="19.8753" cg="34.5"/>\r
+      <eng-data  t="0.038" f="30.792" m="19.5702" cg="34.5"/>\r
+      <eng-data  t="0.067" f="18.708" m="18.9698" cg="34.5"/>\r
+      <eng-data  t="0.101" f="21.875" m="18.3927" cg="34.5"/>\r
+      <eng-data  t="0.33" f="26.083" m="13.7997" cg="34.5"/>\r
+      <eng-data  t="0.528" f="28.042" m="9.31773" cg="34.5"/>\r
+      <eng-data  t="0.716" f="27.875" m="4.92123" cg="34.5"/>\r
+      <eng-data  t="0.841" f="23.542" m="2.23328" cg="34.5"/>\r
+      <eng-data  t="0.912" f="17.833" m="1.00471" cg="34.5"/>\r
+      <eng-data  t="0.987" f="7." m="0.225783" cg="34.5"/>\r
+      <eng-data  t="1.016" f="3.333" m="0.100461" cg="34.5"/>\r
+      <eng-data  t="1.065" f="1.083" m="0.00996451" cg="34.5"/>\r
+      <eng-data  t="1.087" f="0." m="0." cg="34.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_E31.rse b/core/resources/datafiles/thrustcurves/Cesaroni_E31.rse
new file mode 100644 (file)
index 0000000..4cb1d8b
--- /dev/null
@@ -0,0 +1,29 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="26-E31-WH-15A" Type="unspecified" dia="24." len="69."\r
+initWt="52." propWt="16.9" delays="15,12,10,8,6" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="29.982" peakThrust="43.824" throatDia="0."\r
+exitDia="0." Itot="26.084" burn-time="0.87" massFrac="32.5" Isp="157.39"\r
+tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
+mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>White 24mm 1G\r
+26-E31-WH-15A\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="16.9" cg="34.5"/>\r
+      <eng-data  t="0.02" f="43.824" m="16.6161" cg="34.5"/>\r
+      <eng-data  t="0.027" f="39.964" m="16.4261" cg="34.5"/>\r
+      <eng-data  t="0.049" f="26.781" m="15.9504" cg="34.5"/>\r
+      <eng-data  t="0.113" f="32.601" m="14.7192" cg="34.5"/>\r
+      <eng-data  t="0.193" f="34.739" m="12.974" cg="34.5"/>\r
+      <eng-data  t="0.282" f="35.808" m="10.94" cg="34.5"/>\r
+      <eng-data  t="0.5" f="34.442" m="5.97881" cg="34.5"/>\r
+      <eng-data  t="0.727" f="29.276" m="1.29315" cg="34.5"/>\r
+      <eng-data  t="0.771" f="22.743" m="0.551669" cg="34.5"/>\r
+      <eng-data  t="0.807" f="9.561" m="0.174929" cg="34.5"/>\r
+      <eng-data  t="0.84" f="3.563" m="0.0346274" cg="34.5"/>\r
+      <eng-data  t="0.87" f="0." m="0." cg="34.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_F50.rse b/core/resources/datafiles/thrustcurves/Cesaroni_F50.rse
new file mode 100644 (file)
index 0000000..0123dca
--- /dev/null
@@ -0,0 +1,29 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="60-F50-SK-13A" Type="unspecified" dia="24." len="133."\r
+initWt="93.9" propWt="38.2" delays="13,10,8,6,4" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="45.996" peakThrust="69.516" throatDia="0."\r
+exitDia="0." Itot="59.702" burn-time="1.3" massFrac="40.68" Isp="159.37"\r
+tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
+mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>Skidmark 24mm 3G\r
+60-F50-SK-13A\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="38.2" cg="66.5"/>\r
+      <eng-data  t="0.015" f="64.982" m="37.8882" cg="66.5"/>\r
+      <eng-data  t="0.022" f="69.516" m="37.587" cg="66.5"/>\r
+      <eng-data  t="0.064" f="55.537" m="35.9067" cg="66.5"/>\r
+      <eng-data  t="0.118" f="62.81" m="33.8621" cg="66.5"/>\r
+      <eng-data  t="0.342" f="62.149" m="24.9073" cg="66.5"/>\r
+      <eng-data  t="0.536" f="59.41" m="17.3628" cg="66.5"/>\r
+      <eng-data  t="0.743" f="53.837" m="9.86315" cg="66.5"/>\r
+      <eng-data  t="0.884" f="46.942" m="5.31712" cg="66.5"/>\r
+      <eng-data  t="0.976" f="40.047" m="2.7568" cg="66.5"/>\r
+      <eng-data  t="1.096" f="12.562" m="0.737116" cg="66.5"/>\r
+      <eng-data  t="1.246" f="2.078" m="0.0345694" cg="66.5"/>\r
+      <eng-data  t="1.298" f="0." m="0." cg="66.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_F51.rse b/core/resources/datafiles/thrustcurves/Cesaroni_F51.rse
new file mode 100644 (file)
index 0000000..737d1a9
--- /dev/null
@@ -0,0 +1,26 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="75-F51-CL-12A" Type="unspecified" dia="24." len="133."\r
+initWt="95." propWt="40." delays="12,9,7,5" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="47.72" peakThrust="84.148" throatDia="0." exitDia="0." Itot="75.254"\r
+burn-time="1.58" massFrac="42.11" Isp="191.85" tDiv="10" tStep="-1." tFix="1"\r
+FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1." mFix="1" cgDiv="10"\r
+cgStep="-1." cgFix="1">\r
+    <comments>Classic 24mm 3G\r
+75-F51-CL-12A\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="40." cg="66.5"/>\r
+      <eng-data  t="0.02" f="75.924" m="39.5964" cg="66.5"/>\r
+      <eng-data  t="0.031" f="84.148" m="39.1285" cg="66.5"/>\r
+      <eng-data  t="0.062" f="70.441" m="37.8549" cg="66.5"/>\r
+      <eng-data  t="0.117" f="73.659" m="35.7485" cg="66.5"/>\r
+      <eng-data  t="1.211" f="38.737" m="3.06972" cg="66.5"/>\r
+      <eng-data  t="1.376" f="14.779" m="0.722981" cg="66.5"/>\r
+      <eng-data  t="1.456" f="7.271" m="0.254171" cg="66.5"/>\r
+      <eng-data  t="1.532" f="3.337" m="0.0399086" cg="66.5"/>\r
+      <eng-data  t="1.577" f="0." m="0." cg="66.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
index 2759237bb5df6bf59aa9e6fde07b1c01c69fbf26..c5d5addc63370555deb61dbd9962e6ef0e97a643 100644 (file)
@@ -1,16 +1,25 @@
-; CTI Pro38 G69 Skidmark\r
-G69SK-14A 38 117 5-7-9-11-14 0.0615 0.197 CTI\r
-   0.025 102.515\r
-   0.058 97.371\r
-   0.069 77.862\r
-   0.088 59.593\r
-   0.22 72.541\r
-   0.359 81.054\r
-   1.036 81.586\r
-   1.289 75.201\r
-   1.384 71.831\r
-   1.488 76.443\r
-   1.551 64.205\r
-   1.613 34.053\r
-   1.696 9.932\r
-   1.814 0.0\r
+; Pro38 G69\r
+G69 38 127 5-7-9-12 0.066500 0.2045 Pro38\r
+   0.079 79.935\r
+   0.103 72.367\r
+   0.136 82.989\r
+   0.217 85.910\r
+   0.247 82.193\r
+   0.311 84.317\r
+   0.352 80.201\r
+   0.387 82.856\r
+   0.840 72.499\r
+   0.944 72.234\r
+   0.978 69.047\r
+   1.017 71.835\r
+   1.082 67.852\r
+   1.227 66.657\r
+   1.237 65.329\r
+   1.493 62.010\r
+   1.530 59.354\r
+   1.591 60.151\r
+   1.714 56.167\r
+   1.769 54.574\r
+   1.848 46.607\r
+   1.887 27.884\r
+   1.958 00.000  \r
index c5d5addc63370555deb61dbd9962e6ef0e97a643..06b0f47fd852841002f00b0543d19d050387de65 100644 (file)
@@ -1,25 +1,14 @@
-; Pro38 G69\r
-G69 38 127 5-7-9-12 0.066500 0.2045 Pro38\r
-   0.079 79.935\r
-   0.103 72.367\r
-   0.136 82.989\r
-   0.217 85.910\r
-   0.247 82.193\r
-   0.311 84.317\r
-   0.352 80.201\r
-   0.387 82.856\r
-   0.840 72.499\r
-   0.944 72.234\r
-   0.978 69.047\r
-   1.017 71.835\r
-   1.082 67.852\r
-   1.227 66.657\r
-   1.237 65.329\r
-   1.493 62.010\r
-   1.530 59.354\r
-   1.591 60.151\r
-   1.714 56.167\r
-   1.769 54.574\r
-   1.848 46.607\r
-   1.887 27.884\r
-   1.958 00.000  \r
+;\r
+133G69  38.0 127.00 3-5-7-9-12 0.08400 0.20510 CTI\r
+   0.06      80.77 \r
+   0.20      84.50 \r
+   0.41      82.74 \r
+   0.59      80.11 \r
+   0.81      76.82 \r
+   1.00      72.87 \r
+   1.20      68.92 \r
+   1.40      64.31 \r
+   1.61      59.48 \r
+   1.82      50.92 \r
+   1.90      21.40 \r
+   1.93       0.00 \r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_G69_3.eng b/core/resources/datafiles/thrustcurves/Cesaroni_G69_3.eng
deleted file mode 100644 (file)
index 06b0f47..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-;\r
-133G69  38.0 127.00 3-5-7-9-12 0.08400 0.20510 CTI\r
-   0.06      80.77 \r
-   0.20      84.50 \r
-   0.41      82.74 \r
-   0.59      80.11 \r
-   0.81      76.82 \r
-   1.00      72.87 \r
-   1.20      68.92 \r
-   1.40      64.31 \r
-   1.61      59.48 \r
-   1.82      50.92 \r
-   1.90      21.40 \r
-   1.93       0.00 \r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_I165.eng b/core/resources/datafiles/thrustcurves/Cesaroni_I165.eng
new file mode 100644 (file)
index 0000000..de68b10
--- /dev/null
@@ -0,0 +1,16 @@
+;Pro-54-1G C-Star 518-I165-17A\r
+;Ejection adjustable from 7 to 17\r
+518-I165-CS-17A 54 69 17-15-13-11-9-7 0.267 0.594 CTI \r
+0.027 133.424\r
+0.056 174.831\r
+0.067 179.973\r
+0.497 188.633\r
+1.018 184.032\r
+1.704 169.959\r
+2.95 129.364\r
+3.05 130.717\r
+3.168 44.655\r
+3.213 17.862\r
+3.271 3.518\r
+3.5 0\r
+;\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_J316.eng b/core/resources/datafiles/thrustcurves/Cesaroni_J316.eng
new file mode 100644 (file)
index 0000000..372d6ae
--- /dev/null
@@ -0,0 +1,16 @@
+; Pink 38mm 5G\r
+; 654-J316-PK-17A\r
+654-J316-PK-17A 38 367 17-14-12-10-8 0.3508 0.6071000000000001 CTI\r
+   0.017 393.07\r
+   0.026 443.25\r
+   0.064 381.123\r
+   0.223 393.07\r
+   0.503 379.331\r
+   1.029 354.241\r
+   1.52 320.789\r
+   1.672 313.023\r
+   1.695 296.296\r
+   1.816 145.759\r
+   1.901 88.411\r
+   2.043 32.855\r
+   2.184 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_J316.rse b/core/resources/datafiles/thrustcurves/Cesaroni_J316.rse
new file mode 100644 (file)
index 0000000..1a0a63f
--- /dev/null
@@ -0,0 +1,30 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="654-J316-PK-17A" Type="unspecified" dia="38." len="367."\r
+initWt="607.1" propWt="350.8" delays="17,14,12,10,8" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="299.405" peakThrust="443.25" throatDia="0."\r
+exitDia="0." Itot="653.901" burn-time="2.18" massFrac="57.78" Isp="190.08"\r
+tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
+mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>Pink 38mm 5G\r
+654-J316-PK-17A\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="350.8" cg="183.5"/>\r
+      <eng-data  t="0.017" f="393.07" m="349.008" cg="183.5"/>\r
+      <eng-data  t="0.026" f="443.25" m="346.989" cg="183.5"/>\r
+      <eng-data  t="0.064" f="381.123" m="338.586" cg="183.5"/>\r
+      <eng-data  t="0.223" f="393.07" m="305.567" cg="183.5"/>\r
+      <eng-data  t="0.503" f="379.331" m="247.555" cg="183.5"/>\r
+      <eng-data  t="1.029" f="354.241" m="144.053" cg="183.5"/>\r
+      <eng-data  t="1.52" f="320.789" m="55.1492" cg="183.5"/>\r
+      <eng-data  t="1.672" f="313.023" m="29.3074" cg="183.5"/>\r
+      <eng-data  t="1.695" f="296.296" m="25.5483" cg="183.5"/>\r
+      <eng-data  t="1.816" f="145.759" m="11.2007" cg="183.5"/>\r
+      <eng-data  t="1.901" f="88.411" m="5.86159" cg="183.5"/>\r
+      <eng-data  t="2.043" f="32.855" m="1.24262" cg="183.5"/>\r
+      <eng-data  t="2.184" f="0." m="0." cg="183.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
index c7da07b27115d5b78b65198f5b2eabbddfb6281d..f220b24b9f393795a53dcaf55246121ea2bb98b2 100644 (file)
@@ -1,24 +1,83 @@
-J425BS 38 421 16-13-11-9-7 0.405 0.7000000000000001 Cesaroni\r
-   0.028 141.739\r
-   0.053 133.043\r
-   0.079 126.957\r
-   0.126 123.478\r
-   0.574 116.957\r
-   1.014 110.0\r
-   1.3 105.652\r
-   1.34 102.609\r
-   1.374 95.217\r
-   1.414 77.826\r
-   1.437 73.478\r
-   1.472 72.174\r
-   1.519 64.783\r
-   1.547 54.783\r
-   1.595 36.087\r
-   1.658 18.261\r
-   1.695 13.913\r
-   1.747 10.87\r
-   1.821 9.13\r
-   1.898 6.087\r
-   1.935 4.783\r
-   1.944 3.478\r
-   1.945 0.0\r
+; Pro38 784J425-16A\r
+J425 38 409.2 16-13-11-9-7 0.405 0.7000000000000001 CTI\r
+   0.0060 4.399\r
+   0.01 92.386\r
+   0.011 272.759\r
+   0.012 434.068\r
+   0.013 507.39\r
+   0.016 589.511\r
+   0.02 668.699\r
+   0.021 720.025\r
+   0.027 659.901\r
+   0.037 632.038\r
+   0.053 589.511\r
+   0.069 566.048\r
+   0.098 554.317\r
+   0.135 552.85\r
+   0.167 548.451\r
+   0.206 546.984\r
+   0.251 542.585\r
+   0.289 542.585\r
+   0.326 538.186\r
+   0.369 533.786\r
+   0.41 526.454\r
+   0.455 527.921\r
+   0.489 523.521\r
+   0.508 520.588\r
+   0.524 520.588\r
+   0.561 517.655\r
+   0.589 522.055\r
+   0.62 517.655\r
+   0.656 513.256\r
+   0.687 510.323\r
+   0.72 505.924\r
+   0.75 507.39\r
+   0.787 505.924\r
+   0.818 504.457\r
+   0.856 500.058\r
+   0.887 495.659\r
+   0.919 494.192\r
+   0.952 492.726\r
+   0.987 489.793\r
+   1.017 489.793\r
+   1.05 485.394\r
+   1.078 482.461\r
+   1.113 482.461\r
+   1.146 479.528\r
+   1.18 479.528\r
+   1.217 472.196\r
+   1.252 473.662\r
+   1.288 470.729\r
+   1.321 464.863\r
+   1.348 451.665\r
+   1.366 431.135\r
+   1.382 401.806\r
+   1.395 378.343\r
+   1.407 357.813\r
+   1.421 338.749\r
+   1.445 325.551\r
+   1.476 313.819\r
+   1.498 300.621\r
+   1.521 278.625\r
+   1.541 249.296\r
+   1.556 224.366\r
+   1.568 206.769\r
+   1.58 184.772\r
+   1.596 161.309\r
+   1.607 140.779\r
+   1.625 117.316\r
+   1.641 93.853\r
+   1.67 73.322\r
+   1.69 63.057\r
+   1.717 52.792\r
+   1.745 48.393\r
+   1.772 45.46\r
+   1.796 42.527\r
+   1.821 42.527\r
+   1.849 38.128\r
+   1.884 29.329\r
+   1.906 26.396\r
+   1.929 19.064\r
+   1.955 16.131\r
+   1.978 10.265\r
+   1.996 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_J425.rse b/core/resources/datafiles/thrustcurves/Cesaroni_J425.rse
deleted file mode 100644 (file)
index cdc3bd6..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<engine-database>\r
-  <engine-list>\r
-    <engine  mfg="Cesaroni" code="J425-Blue Streak" Type="reloadable" dia="38." len="421."\r
-initWt="700." propWt="405." delays="16,13,11,9,7" auto-calc-mass="1"\r
-auto-calc-cg="1" avgThrust="90.581" peakThrust="141.739" throatDia="0."\r
-exitDia="0." Itot="176.179" burn-time="1.95" massFrac="57.86" Isp="44.36"\r
-tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
-mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
-    <data>\r
-      <eng-data  t="0." f="0." m="405." cg="210.5"/>\r
-      <eng-data  t="0.028" f="141.739" m="400.438" cg="210.5"/>\r
-      <eng-data  t="0.053" f="133.043" m="392.543" cg="210.5"/>\r
-      <eng-data  t="0.079" f="126.957" m="384.773" cg="210.5"/>\r
-      <eng-data  t="0.126" f="123.478" m="371.244" cg="210.5"/>\r
-      <eng-data  t="0.574" f="116.957" m="247.437" cg="210.5"/>\r
-      <eng-data  t="1.014" f="110." m="132.656" cg="210.5"/>\r
-      <eng-data  t="1.3" f="105.652" m="61.7657" cg="210.5"/>\r
-      <eng-data  t="1.34" f="102.609" m="52.1907" cg="210.5"/>\r
-      <eng-data  t="1.374" f="95.217" m="44.4598" cg="210.5"/>\r
-      <eng-data  t="1.414" f="77.826" m="36.5039" cg="210.5"/>\r
-      <eng-data  t="1.437" f="73.478" m="32.5041" cg="210.5"/>\r
-      <eng-data  t="1.472" f="72.174" m="26.6446" cg="210.5"/>\r
-      <eng-data  t="1.519" f="64.783" m="19.246" cg="210.5"/>\r
-      <eng-data  t="1.547" f="54.783" m="15.398" cg="210.5"/>\r
-      <eng-data  t="1.595" f="36.087" m="10.3846" cg="210.5"/>\r
-      <eng-data  t="1.658" f="18.261" m="6.44913" cg="210.5"/>\r
-      <eng-data  t="1.695" f="13.913" m="5.08084" cg="210.5"/>\r
-      <eng-data  t="1.747" f="10.87" m="3.5996" cg="210.5"/>\r
-      <eng-data  t="1.821" f="9.13" m="1.89849" cg="210.5"/>\r
-      <eng-data  t="1.898" f="6.087" m="0.55173" cg="210.5"/>\r
-      <eng-data  t="1.935" f="4.783" m="0.0894541" cg="210.5"/>\r
-      <eng-data  t="1.944" f="3.478" m="0.0039976" cg="210.5"/>\r
-      <eng-data  t="1.945" f="0." m="0." cg="210.5"/>\r
-    </data>\r
-  </engine>\r
-</engine-list>\r
-</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_J453.rse b/core/resources/datafiles/thrustcurves/Cesaroni_J453.rse
new file mode 100644 (file)
index 0000000..1521623
--- /dev/null
@@ -0,0 +1,28 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="1013-J453-WH-16A" Type="unspecified" dia="38." len="500."\r
+initWt="964.3" propWt="613.2" delays="16,13,11,9,7" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="430.622" peakThrust="725.18" throatDia="0."\r
+exitDia="0." Itot="1017.99" burn-time="2.36" massFrac="63.59" Isp="169.29"\r
+tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
+mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>White 38mm 6GXL\r
+1013-J453-WH-16A\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="613.2" cg="250."/>\r
+      <eng-data  t="0.018" f="663.789" m="609.601" cg="250."/>\r
+      <eng-data  t="0.04" f="725.18" m="600.398" cg="250."/>\r
+      <eng-data  t="0.105" f="630.216" m="573.864" cg="250."/>\r
+      <eng-data  t="0.23" f="578.417" m="528.362" cg="250."/>\r
+      <eng-data  t="0.451" f="543.885" m="453.66" cg="250."/>\r
+      <eng-data  t="1.454" f="535.252" m="127.669" cg="250."/>\r
+      <eng-data  t="1.797" f="291.607" m="42.2501" cg="250."/>\r
+      <eng-data  t="1.91" f="188.969" m="25.8944" cg="250."/>\r
+      <eng-data  t="2.088" f="128.537" m="8.87281" cg="250."/>\r
+      <eng-data  t="2.276" f="19.185" m="0.508479" cg="250."/>\r
+      <eng-data  t="2.364" f="0." m="0." cg="250."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_K2000.rse b/core/resources/datafiles/thrustcurves/Cesaroni_K2000.rse
new file mode 100644 (file)
index 0000000..addbb82
--- /dev/null
@@ -0,0 +1,30 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="2330-K2000-VM-P" Type="unspecified" dia="75." len="350."\r
+initWt="2464.5" propWt="1164.2" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="1957.59" peakThrust="2473.68" throatDia="0." exitDia="0."\r
+Itot="2331.49" burn-time="1.19" massFrac="47.24" Isp="204.21" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>VMax 75mm 2G\r
+2330-K2000-VM-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="1164.2" cg="175."/>\r
+      <eng-data  t="0.01" f="1979.53" m="1159.26" cg="175."/>\r
+      <eng-data  t="0.029" f="1634.5" m="1142.11" cg="175."/>\r
+      <eng-data  t="0.161" f="1947.37" m="1024.07" cg="175."/>\r
+      <eng-data  t="0.321" f="2190.06" m="858.791" cg="175."/>\r
+      <eng-data  t="0.457" f="2397.66" m="703.015" cg="175."/>\r
+      <eng-data  t="0.548" f="2473.68" m="592.339" cg="175."/>\r
+      <eng-data  t="0.678" f="2383.04" m="434.704" cg="175."/>\r
+      <eng-data  t="0.768" f="2263.16" m="330.303" cg="175."/>\r
+      <eng-data  t="0.977" f="1923.98" m="111.815" cg="175."/>\r
+      <eng-data  t="1.027" f="1883.04" m="64.2905" cg="175."/>\r
+      <eng-data  t="1.104" f="859.649" m="11.5636" cg="175."/>\r
+      <eng-data  t="1.149" f="87.719" m="0.91983" cg="175."/>\r
+      <eng-data  t="1.191" f="0." m="0." cg="175."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_K580.eng b/core/resources/datafiles/thrustcurves/Cesaroni_K580.eng
new file mode 100644 (file)
index 0000000..0d67f6e
--- /dev/null
@@ -0,0 +1,48 @@
+;Created by Jesus Manuel Recuenco Andres 2011\r
+;with Tctracer v1.0\r
+K580  54.0 491.00 1000 0.89500 1.82300 Cesaroni\r
+   0.02     624.92 \r
+   0.03    1076.60 \r
+   0.07     846.73 \r
+   0.12     884.56 \r
+   0.20     855.46 \r
+   0.29     840.91 \r
+   0.39     835.09 \r
+   0.48     822.58 \r
+   0.56     808.60 \r
+   0.66     800.62 \r
+   0.74     784.64 \r
+   0.83     776.66 \r
+   0.90     762.68 \r
+   0.96     760.68 \r
+   1.03     748.71 \r
+   1.10     734.32 \r
+   1.14     713.24 \r
+   1.18     720.75 \r
+   1.27     704.78 \r
+   1.35     682.82 \r
+   1.43     666.85 \r
+   1.51     650.87 \r
+   1.59     632.91 \r
+   1.67     622.92 \r
+   1.73     604.95 \r
+   1.79     598.96 \r
+   1.86     579.00 \r
+   1.94     561.03 \r
+   1.99     559.03 \r
+   2.03     539.07 \r
+   2.09     533.08 \r
+   2.16     517.11 \r
+   2.24     507.12 \r
+   2.31     491.15 \r
+   2.39     477.18 \r
+   2.45     463.20 \r
+   2.51     442.28 \r
+   2.55     407.36 \r
+   2.60     360.81 \r
+   2.65     320.07 \r
+   2.69     276.42 \r
+   2.76     232.78 \r
+   2.82     194.95 \r
+   2.96     122.21 \r
+   3.20       0.00 \r
index 190a5760ca5c4d618b4bdcaec35035d70abde14f..3bc2f6b69a92ef05e65cd502b12c1edfd4c1fba1 100644 (file)
@@ -1,28 +1,25 @@
 <engine-database>\r
   <engine-list>\r
-<engine  mfg="Cesaroni Technology Inc." code="K650SS" Type="reloadable" dia="54."\r
-len="488." initWt="1989.9" propWt="1281." delays="16" auto-calc-mass="1"\r
-auto-calc-cg="1" avgThrust="657.68" peakThrust="728.7" throatDia="0."\r
-exitDia="0." Itot="1749.43" burn-time="2.66" massFrac="64.38" Isp="139.26"\r
+    <engine  mfg="CTI" code="1997-K650-PK-21" Type="unspecified" dia="54." len="488."\r
+initWt="1710." propWt="1065.1" delays="21,19,17,15,13,11" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="578.782" peakThrust="1353.5" throatDia="0."\r
+exitDia="0." Itot="1997.38" burn-time="3.45" massFrac="62.29" Isp="191.23"\r
 tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
 mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
-<data>\r
-<eng-data  t="0." f="0." m="1281." cg="244."/>\r
-<eng-data  t="0.04" f="664.52" m="1271.27" cg="244."/>\r
-<eng-data  t="0.12" f="645.9" m="1232.89" cg="244."/>\r
-<eng-data  t="0.31" f="642.24" m="1143.28" cg="244."/>\r
-<eng-data  t="0.6" f="664.78" m="1004.51" cg="244."/>\r
-<eng-data  t="0.91" f="684.59" m="851.358" cg="244."/>\r
-<eng-data  t="1.22" f="712.82" m="692.757" cg="244."/>\r
-<eng-data  t="1.5" f="723.41" m="545.524" cg="244."/>\r
-<eng-data  t="1.8" f="728.7" m="386.03" cg="244."/>\r
-<eng-data  t="2.1" f="664.52" m="233.005" cg="244."/>\r
-<eng-data  t="2.4" f="614.68" m="92.5027" cg="244."/>\r
-<eng-data  t="2.51" f="680.53" m="40.3405" cg="244."/>\r
-<eng-data  t="2.55" f="534.62" m="22.5449" cg="244."/>\r
-<eng-data  t="2.61" f="268.19" m="4.90948" cg="244."/>\r
-<eng-data  t="2.66" f="0." m="0." cg="244."/>\r
-</data>\r
-</engine>\r
+    <comments>Pink 54mm 5G\r
+1997-K650-PK-21\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="1065.1" cg="244."/>\r
+      <eng-data  t="0.011" f="1353.5" m="1061.13" cg="244."/>\r
+      <eng-data  t="0.028" f="793.832" m="1051.4" cg="244."/>\r
+      <eng-data  t="0.186" f="815.421" m="983.605" cg="244."/>\r
+      <eng-data  t="2.578" f="601.186" m="80.1407" cg="244."/>\r
+      <eng-data  t="2.689" f="479.953" m="48.144" cg="244."/>\r
+      <eng-data  t="2.855" f="189.324" m="18.522" cg="244."/>\r
+      <eng-data  t="3.086" f="43.179" m="4.20209" cg="244."/>\r
+      <eng-data  t="3.451" f="0." m="0." cg="244."/>\r
+    </data>\r
+  </engine>\r
 </engine-list>\r
 </engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_K650_1.rse b/core/resources/datafiles/thrustcurves/Cesaroni_K650_1.rse
new file mode 100644 (file)
index 0000000..190a576
--- /dev/null
@@ -0,0 +1,28 @@
+<engine-database>\r
+  <engine-list>\r
+<engine  mfg="Cesaroni Technology Inc." code="K650SS" Type="reloadable" dia="54."\r
+len="488." initWt="1989.9" propWt="1281." delays="16" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="657.68" peakThrust="728.7" throatDia="0."\r
+exitDia="0." Itot="1749.43" burn-time="2.66" massFrac="64.38" Isp="139.26"\r
+tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
+mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+<data>\r
+<eng-data  t="0." f="0." m="1281." cg="244."/>\r
+<eng-data  t="0.04" f="664.52" m="1271.27" cg="244."/>\r
+<eng-data  t="0.12" f="645.9" m="1232.89" cg="244."/>\r
+<eng-data  t="0.31" f="642.24" m="1143.28" cg="244."/>\r
+<eng-data  t="0.6" f="664.78" m="1004.51" cg="244."/>\r
+<eng-data  t="0.91" f="684.59" m="851.358" cg="244."/>\r
+<eng-data  t="1.22" f="712.82" m="692.757" cg="244."/>\r
+<eng-data  t="1.5" f="723.41" m="545.524" cg="244."/>\r
+<eng-data  t="1.8" f="728.7" m="386.03" cg="244."/>\r
+<eng-data  t="2.1" f="664.52" m="233.005" cg="244."/>\r
+<eng-data  t="2.4" f="614.68" m="92.5027" cg="244."/>\r
+<eng-data  t="2.51" f="680.53" m="40.3405" cg="244."/>\r
+<eng-data  t="2.55" f="534.62" m="22.5449" cg="244."/>\r
+<eng-data  t="2.61" f="268.19" m="4.90948" cg="244."/>\r
+<eng-data  t="2.66" f="0." m="0." cg="244."/>\r
+</data>\r
+</engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_K661.rse b/core/resources/datafiles/thrustcurves/Cesaroni_K661.rse
new file mode 100644 (file)
index 0000000..3d32597
--- /dev/null
@@ -0,0 +1,33 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="2430-K661-BS-P" Type="unspecified" dia="75." len="350."\r
+initWt="2527.8" propWt="1262.5" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="641.518" peakThrust="758.091" throatDia="0." exitDia="0."\r
+Itot="2436.49" burn-time="3.8" massFrac="49.94" Isp="196.79" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>Blue Streak 75mm 2G\r
+2430-K661-BS-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="1262.5" cg="175."/>\r
+      <eng-data  t="0.041" f="588.591" m="1256.25" cg="175."/>\r
+      <eng-data  t="0.073" f="659.371" m="1245.9" cg="175."/>\r
+      <eng-data  t="0.122" f="635.157" m="1229.47" cg="175."/>\r
+      <eng-data  t="0.225" f="634.226" m="1195.59" cg="175."/>\r
+      <eng-data  t="0.679" f="713.388" m="1037.08" cg="175."/>\r
+      <eng-data  t="1.039" f="751.572" m="900.446" cg="175."/>\r
+      <eng-data  t="1.241" f="758.091" m="821.438" cg="175."/>\r
+      <eng-data  t="1.832" f="727.357" m="593.99" cg="175."/>\r
+      <eng-data  t="2.298" f="687.311" m="423.194" cg="175."/>\r
+      <eng-data  t="2.729" f="667.753" m="271.882" cg="175."/>\r
+      <eng-data  t="3.195" f="645.402" m="113.341" cg="175."/>\r
+      <eng-data  t="3.367" f="670.547" m="54.6998" cg="175."/>\r
+      <eng-data  t="3.584" f="182.538" m="6.73867" cg="175."/>\r
+      <eng-data  t="3.672" f="55.879" m="1.30294" cg="175."/>\r
+      <eng-data  t="3.72" f="18.626" m="0.376402" cg="175."/>\r
+      <eng-data  t="3.798" f="0." m="0." cg="175."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_K735.rse b/core/resources/datafiles/thrustcurves/Cesaroni_K735.rse
new file mode 100644 (file)
index 0000000..5c648e8
--- /dev/null
@@ -0,0 +1,31 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="1955-K735-SK-P" Type="unspecified" dia="75." len="350."\r
+initWt="2508.8" propWt="1222.1" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="692.838" peakThrust="889.282" throatDia="0." exitDia="0."\r
+Itot="1961.42" burn-time="2.83" massFrac="48.71" Isp="163.66" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>Skidmark 75mm 2G\r
+1955-K735-SK-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="1222.1" cg="175."/>\r
+      <eng-data  t="0.053" f="683.157" m="1210.82" cg="175."/>\r
+      <eng-data  t="0.142" f="593.64" m="1175.42" cg="175."/>\r
+      <eng-data  t="0.408" f="697.291" m="1068.44" cg="175."/>\r
+      <eng-data  t="0.893" f="848.057" m="834.95" cg="175."/>\r
+      <eng-data  t="1.109" f="886.926" m="718.2" cg="175."/>\r
+      <eng-data  t="1.24" f="882.214" m="646." cg="175."/>\r
+      <eng-data  t="1.362" f="889.282" m="578.671" cg="175."/>\r
+      <eng-data  t="2." f="783.274" m="246.236" cg="175."/>\r
+      <eng-data  t="2.346" f="706.714" m="85.6289" cg="175."/>\r
+      <eng-data  t="2.439" f="648.999" m="46.3503" cg="175."/>\r
+      <eng-data  t="2.612" f="123.675" m="4.70677" cg="175."/>\r
+      <eng-data  t="2.676" f="36.514" m="1.51289" cg="175."/>\r
+      <eng-data  t="2.754" f="12.956" m="0.31079" cg="175."/>\r
+      <eng-data  t="2.831" f="0." m="0." cg="175."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_K935.eng b/core/resources/datafiles/thrustcurves/Cesaroni_K935.eng
new file mode 100644 (file)
index 0000000..2595afb
--- /dev/null
@@ -0,0 +1,48 @@
+;Created by Jesus Manuel Recuenco Andres 2011\r
+;with Tctracer v1.0\r
+K935  54.0 403.00 1000 0.73200 1.50800 Cesaroni\r
+   0.01    1072.70 \r
+   0.02    1043.71 \r
+   0.04     974.21 \r
+   0.07    1015.94 \r
+   0.10    1029.21 \r
+   0.14    1040.97 \r
+   0.17    1049.51 \r
+   0.22    1059.74 \r
+   0.25    1064.00 \r
+   0.29    1070.18 \r
+   0.34    1072.70 \r
+   0.39    1072.26 \r
+   0.42    1069.80 \r
+   0.45    1072.70 \r
+   0.49    1069.80 \r
+   0.52    1070.18 \r
+   0.58    1064.00 \r
+   0.64    1059.74 \r
+   0.70    1055.30 \r
+   0.76    1045.14 \r
+   0.81    1035.01 \r
+   0.85    1029.21 \r
+   0.88    1022.20 \r
+   0.91    1017.62 \r
+   0.94    1014.72 \r
+   0.97    1008.92 \r
+   1.00    1003.42 \r
+   1.06     985.72 \r
+   1.12     965.87 \r
+   1.16     950.93 \r
+   1.21     936.66 \r
+   1.26     919.04 \r
+   1.30     903.29 \r
+   1.34     890.05 \r
+   1.38     876.17 \r
+   1.43     861.06 \r
+   1.48     846.96 \r
+   1.51     719.71 \r
+   1.54     619.58 \r
+   1.56     510.26 \r
+   1.58     415.14 \r
+   1.60     295.72 \r
+   1.63     181.49 \r
+   1.66      66.76 \r
+   1.70       0.00 \r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_L1050.rse b/core/resources/datafiles/thrustcurves/Cesaroni_L1050.rse
new file mode 100644 (file)
index 0000000..848390c
--- /dev/null
@@ -0,0 +1,32 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="3727-L1050-BS-P" Type="unspecified" dia="75." len="486."\r
+initWt="3447.7" propWt="1863.4" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="1000.17" peakThrust="1207.29" throatDia="0." exitDia="0."\r
+Itot="3731.64" burn-time="3.73" massFrac="54.05" Isp="204.21" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>Blue Streak 75mm 3G\r
+3727-L1050-BS-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="1863.4" cg="243."/>\r
+      <eng-data  t="0.035" f="721.412" m="1857.1" cg="243."/>\r
+      <eng-data  t="0.081" f="1110.12" m="1836.06" cg="243."/>\r
+      <eng-data  t="0.131" f="1057.41" m="1809." cg="243."/>\r
+      <eng-data  t="0.249" f="1100.23" m="1745.43" cg="243."/>\r
+      <eng-data  t="0.913" f="1194.12" m="1365.06" cg="243."/>\r
+      <eng-data  t="1.125" f="1207.29" m="1237.96" cg="243."/>\r
+      <eng-data  t="2.271" f="1100.23" m="577.705" cg="243."/>\r
+      <eng-data  t="2.797" f="1055.77" m="294.559" cg="243."/>\r
+      <eng-data  t="3.076" f="1042.59" m="148.389" cg="243."/>\r
+      <eng-data  t="3.122" f="996.471" m="124.97" cg="243."/>\r
+      <eng-data  t="3.23" f="807.059" m="76.3379" cg="243."/>\r
+      <eng-data  t="3.452" f="289.882" m="15.5367" cg="243."/>\r
+      <eng-data  t="3.544" f="123.529" m="6.04054" cg="243."/>\r
+      <eng-data  t="3.685" f="36.235" m="0.416162" cg="243."/>\r
+      <eng-data  t="3.731" f="0." m="0." cg="243."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_L1350.rse b/core/resources/datafiles/thrustcurves/Cesaroni_L1350.rse
new file mode 100644 (file)
index 0000000..f43df57
--- /dev/null
@@ -0,0 +1,32 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="4263-L1350-CS-P" Type="unspecified" dia="75." len="486."\r
+initWt="3570.7" propWt="2024.5" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="1303.34" peakThrust="1540.73" throatDia="0." exitDia="0."\r
+Itot="4280.17" burn-time="3.28" massFrac="56.7" Isp="215.59" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>C-Star 75mm 3G\r
+4263-L1350-CS-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="2024.5" cg="243."/>\r
+      <eng-data  t="0.016" f="1421.72" m="2019.12" cg="243."/>\r
+      <eng-data  t="0.034" f="1345.22" m="2007.34" cg="243."/>\r
+      <eng-data  t="0.049" f="1502.48" m="1997.24" cg="243."/>\r
+      <eng-data  t="0.081" f="1415.35" m="1975.16" cg="243."/>\r
+      <eng-data  t="0.21" f="1432.35" m="1888.28" cg="243."/>\r
+      <eng-data  t="0.453" f="1432.35" m="1723.65" cg="243."/>\r
+      <eng-data  t="0.809" f="1462.1" m="1479.96" cg="243."/>\r
+      <eng-data  t="1.07" f="1534.36" m="1295." cg="243."/>\r
+      <eng-data  t="1.28" f="1540.73" m="1142.27" cg="243."/>\r
+      <eng-data  t="2.661" f="1283.59" m="219.84" cg="243."/>\r
+      <eng-data  t="2.843" f="1277.21" m="109.616" cg="243."/>\r
+      <eng-data  t="2.932" f="1115.7" m="59.2496" cg="243."/>\r
+      <eng-data  t="3.037" f="488.784" m="19.4066" cg="243."/>\r
+      <eng-data  t="3.163" f="82.881" m="2.37174" cg="243."/>\r
+      <eng-data  t="3.284" f="0." m="0." cg="243."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_L3200.rse b/core/resources/datafiles/thrustcurves/Cesaroni_L3200.rse
new file mode 100644 (file)
index 0000000..0b150ec
--- /dev/null
@@ -0,0 +1,30 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="3300-L3200-VM-P" Type="unspecified" dia="75." len="486."\r
+initWt="3263.7" propWt="1658.4" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="3127.56" peakThrust="3711.92" throatDia="0." exitDia="0."\r
+Itot="3299.58" burn-time="1.05" massFrac="50.81" Isp="202.88" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>VMax 75mm 3G\r
+3300-L3200-VM-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="1658.4" cg="243."/>\r
+      <eng-data  t="0.008" f="3315.23" m="1651.73" cg="243."/>\r
+      <eng-data  t="0.024" f="2672.96" m="1627.66" cg="243."/>\r
+      <eng-data  t="0.108" f="2975.21" m="1508.43" cg="243."/>\r
+      <eng-data  t="0.415" f="3669.42" m="995.789" cg="243."/>\r
+      <eng-data  t="0.524" f="3711.92" m="793.598" cg="243."/>\r
+      <eng-data  t="0.644" f="3669.42" m="571.002" cg="243."/>\r
+      <eng-data  t="0.819" f="3225.5" m="267.774" cg="243."/>\r
+      <eng-data  t="0.911" f="3022.43" m="123.322" cg="243."/>\r
+      <eng-data  t="0.937" f="3050.77" m="83.6397" cg="243."/>\r
+      <eng-data  t="0.957" f="2899.65" m="53.7324" cg="243."/>\r
+      <eng-data  t="1.022" f="288.076" m="1.66152" cg="243."/>\r
+      <eng-data  t="1.039" f="51.948" m="0.208877" cg="243."/>\r
+      <eng-data  t="1.055" f="0." m="0." cg="243."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_L645.rse b/core/resources/datafiles/thrustcurves/Cesaroni_L645.rse
new file mode 100644 (file)
index 0000000..2e34c77
--- /dev/null
@@ -0,0 +1,29 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="3419-L645-GR-P" Type="unspecified" dia="75." len="486."\r
+initWt="3751.8" propWt="2144.1" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="637.051" peakThrust="764.97" throatDia="0." exitDia="0." Itot="3433.7"\r
+burn-time="5.39" massFrac="57.15" Isp="163.3" tDiv="10" tStep="-1." tFix="1"\r
+FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1." mFix="1" cgDiv="10"\r
+cgStep="-1." cgFix="1">\r
+    <comments>Green 75mm 3G\r
+3419-L645-GR-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="2144.1" cg="243."/>\r
+      <eng-data  t="0.05" f="511.243" m="2136.12" cg="243."/>\r
+      <eng-data  t="0.12" f="647.574" m="2110.79" cg="243."/>\r
+      <eng-data  t="0.256" f="689.231" m="2054.03" cg="243."/>\r
+      <eng-data  t="0.425" f="684.497" m="1981.55" cg="243."/>\r
+      <eng-data  t="1.554" f="736.568" m="1480.64" cg="243."/>\r
+      <eng-data  t="2.043" f="764.97" m="1251.39" cg="243."/>\r
+      <eng-data  t="3.075" f="687.337" m="783.453" cg="243."/>\r
+      <eng-data  t="4.557" f="601.183" m="187.254" cg="243."/>\r
+      <eng-data  t="4.756" f="550.059" m="115.726" cg="243."/>\r
+      <eng-data  t="4.985" f="412.781" m="46.8863" cg="243."/>\r
+      <eng-data  t="5.281" f="69.112" m="2.35197" cg="243."/>\r
+      <eng-data  t="5.39" f="0." m="0." cg="243."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_L805.rse b/core/resources/datafiles/thrustcurves/Cesaroni_L805.rse
new file mode 100644 (file)
index 0000000..92b4eb5
--- /dev/null
@@ -0,0 +1,27 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="2833-L805-WH-P" Type="unspecified" dia="54." len="649."\r
+initWt="2502.5" propWt="1675.2" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="746.357" peakThrust="1618.1" throatDia="0." exitDia="0."\r
+Itot="2856.31" burn-time="3.83" massFrac="66.94" Isp="173.87" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>White 54mm 6GXL\r
+2833-L805-WH-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="1675.2" cg="324.5"/>\r
+      <eng-data  t="0.012" f="1618.1" m="1669.51" cg="324.5"/>\r
+      <eng-data  t="0.037" f="1171.8" m="1649.05" cg="324.5"/>\r
+      <eng-data  t="0.173" f="1027.97" m="1561.32" cg="324.5"/>\r
+      <eng-data  t="0.388" f="994.125" m="1433.83" cg="324.5"/>\r
+      <eng-data  t="0.626" f="985.664" m="1295.66" cg="324.5"/>\r
+      <eng-data  t="2.318" f="886.251" m="366.868" cg="324.5"/>\r
+      <eng-data  t="3.054" f="448.414" m="78.8087" cg="324.5"/>\r
+      <eng-data  t="3.464" f="126.91" m="9.63702" cg="324.5"/>\r
+      <eng-data  t="3.608" f="40.188" m="2.58091" cg="324.5"/>\r
+      <eng-data  t="3.827" f="0." m="0." cg="324.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_L910.rse b/core/resources/datafiles/thrustcurves/Cesaroni_L910.rse
new file mode 100644 (file)
index 0000000..49baf2e
--- /dev/null
@@ -0,0 +1,30 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="2856-L910-CS-P" Type="unspecified" dia="75." len="350."\r
+initWt="2615.8" propWt="1364.3" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="879.58" peakThrust="1047.55" throatDia="0." exitDia="0."\r
+Itot="2869.19" burn-time="3.26" massFrac="52.16" Isp="214.45" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>C-Star 75mm 2G\r
+2856-L910-CS-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="1364.3" cg="175."/>\r
+      <eng-data  t="0.034" f="858.741" m="1357.36" cg="175."/>\r
+      <eng-data  t="0.056" f="921.678" m="1348.05" cg="175."/>\r
+      <eng-data  t="0.305" f="952.448" m="1237.1" cg="175."/>\r
+      <eng-data  t="0.718" f="983.217" m="1047.03" cg="175."/>\r
+      <eng-data  t="1.221" f="1047.55" m="804.178" cg="175."/>\r
+      <eng-data  t="1.642" f="1005.59" m="598.673" cg="175."/>\r
+      <eng-data  t="1.842" f="973.427" m="504.57" cg="175."/>\r
+      <eng-data  t="2.951" f="773.427" m="43.9864" cg="175."/>\r
+      <eng-data  t="3.035" f="584.615" m="16.8649" cg="175."/>\r
+      <eng-data  t="3.108" f="169.231" m="3.78139" cg="175."/>\r
+      <eng-data  t="3.152" f="72.727" m="1.25026" cg="175."/>\r
+      <eng-data  t="3.182" f="27.972" m="0.532027" cg="175."/>\r
+      <eng-data  t="3.262" f="0." m="0." cg="175."/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_M2245.eng b/core/resources/datafiles/thrustcurves/Cesaroni_M2245.eng
new file mode 100644 (file)
index 0000000..4db1b65
--- /dev/null
@@ -0,0 +1,13 @@
+; Imax Pro75 6GXL\r
+; 9977 M2245-IM-P\r
+9977-M2245-IM-P 75 1025 P 5.309 8.182 CTI\r
+   0.043 3045.655\r
+   0.136 2629.813\r
+   1.393 3003.3\r
+   2.168 3007.151\r
+   2.708 2972.497\r
+   2.837 2883.938\r
+   3.152 1955.996\r
+   3.397 1409.241\r
+   3.878 562.156\r
+   4.371 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_M2245.rse b/core/resources/datafiles/thrustcurves/Cesaroni_M2245.rse
new file mode 100644 (file)
index 0000000..4e1f7d6
--- /dev/null
@@ -0,0 +1,27 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="9977-M2245-IM-P" Type="unspecified" dia="75." len="1025."\r
+initWt="8182." propWt="5309." delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="2282.85" peakThrust="3045.66" throatDia="0." exitDia="0."\r
+Itot="9978.32" burn-time="4.37" massFrac="64.89" Isp="191.66" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>Imax Pro75 6GXL\r
+9977 M2245-IM-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="5309." cg="512.5"/>\r
+      <eng-data  t="0.043" f="3045.66" m="5274.16" cg="512.5"/>\r
+      <eng-data  t="0.136" f="2629.81" m="5133.75" cg="512.5"/>\r
+      <eng-data  t="1.393" f="3003.3" m="3250.06" cg="512.5"/>\r
+      <eng-data  t="2.168" f="3007.15" m="2010.88" cg="512.5"/>\r
+      <eng-data  t="2.708" f="2972.5" m="1151.88" cg="512.5"/>\r
+      <eng-data  t="2.837" f="2883.94" m="950.898" cg="512.5"/>\r
+      <eng-data  t="3.152" f="1956." m="545.32" cg="512.5"/>\r
+      <eng-data  t="3.397" f="1409.24" m="325.985" cg="512.5"/>\r
+      <eng-data  t="3.878" f="562.156" m="73.7274" cg="512.5"/>\r
+      <eng-data  t="4.371" f="0." m="0." cg="512.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_N2540.rse b/core/resources/datafiles/thrustcurves/Cesaroni_N2540.rse
new file mode 100644 (file)
index 0000000..0717817
--- /dev/null
@@ -0,0 +1,30 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="17907-N2540-GR-P" Type="unspecified" dia="98." len="1239."\r
+initWt="16280.5" propWt="10704.2" delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="2479.42" peakThrust="2894.98" throatDia="0." exitDia="0."\r
+Itot="17906.4" burn-time="7.22" massFrac="65.75" Isp="170.58" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>Green 98mm 6GXL\r
+17907-N2540-GR-P\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="10704.2" cg="619.5"/>\r
+      <eng-data  t="0.073" f="2586.93" m="10647.8" cg="619.5"/>\r
+      <eng-data  t="0.11" f="2789.97" m="10588.3" cg="619.5"/>\r
+      <eng-data  t="0.398" f="2761.96" m="10110.4" cg="619.5"/>\r
+      <eng-data  t="1.14" f="2761.96" m="8885.29" cg="619.5"/>\r
+      <eng-data  t="1.73" f="2828.47" m="7899.43" cg="619.5"/>\r
+      <eng-data  t="2.613" f="2894.98" m="6388.88" cg="619.5"/>\r
+      <eng-data  t="4.16" f="2747.96" m="3779.65" cg="619.5"/>\r
+      <eng-data  t="5.666" f="2565.93" m="1387.7" cg="619.5"/>\r
+      <eng-data  t="5.972" f="2415.4" m="932.099" cg="619.5"/>\r
+      <eng-data  t="6.338" f="1953.33" m="454.182" cg="619.5"/>\r
+      <eng-data  t="6.819" f="745.624" m="66.1607" cg="619.5"/>\r
+      <eng-data  t="7.061" f="101.517" m="4.88518" cg="619.5"/>\r
+      <eng-data  t="7.222" f="0." m="0." cg="619.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Cesaroni_O25000.rse b/core/resources/datafiles/thrustcurves/Cesaroni_O25000.rse
new file mode 100644 (file)
index 0000000..df73d78
--- /dev/null
@@ -0,0 +1,28 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="CTI" code="O25,000-VM-P" Type="unspecified" dia="132." len="1407."\r
+initWt="23558." propWt="14705." delays="0" auto-calc-mass="1" auto-calc-cg="1"\r
+avgThrust="23414.8" peakThrust="26281.5" throatDia="0." exitDia="0."\r
+Itot="30907.5" burn-time="1.32" massFrac="62.42" Isp="214.33" tDiv="10"\r
+tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10" mStep="-1."\r
+mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <comments>CTI 30,795-O25,000-VM-P\r
+Single-Use\r
+</comments>\r
+    <data>\r
+      <eng-data  t="0." f="0." m="14705." cg="703.5"/>\r
+      <eng-data  t="0.008" f="21113.4" m="14664.8" cg="703.5"/>\r
+      <eng-data  t="0.022" f="24705.9" m="14512.2" cg="703.5"/>\r
+      <eng-data  t="0.042" f="26281.5" m="14269.6" cg="703.5"/>\r
+      <eng-data  t="0.067" f="24390.8" m="13968.3" cg="703.5"/>\r
+      <eng-data  t="0.201" f="24044.1" m="12424.3" cg="703.5"/>\r
+      <eng-data  t="0.56" f="25052.5" m="8231.4" cg="703.5"/>\r
+      <eng-data  t="0.927" f="24075.6" m="3942.28" cg="703.5"/>\r
+      <eng-data  t="1.202" f="22815.1" m="874.738" cg="703.5"/>\r
+      <eng-data  t="1.25" f="23602.9" m="344.709" cg="703.5"/>\r
+      <eng-data  t="1.297" f="4852.94" m="26.5524" cg="703.5"/>\r
+      <eng-data  t="1.32" f="0." m="0." cg="703.5"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/Estes_E12.eng b/core/resources/datafiles/thrustcurves/Estes_E12.eng
new file mode 100644 (file)
index 0000000..0213b4b
--- /dev/null
@@ -0,0 +1,33 @@
+; Based on NAR Published Data, 7/31/12, C. J. Kobel\r
+E12 24 95 0-4-6-8 0.0359 0.0599 Estes\r
+   0.052 5.045\r
+   0.096 9.910\r
+   0.196 24.144\r
+   0.251 31.351\r
+   0.287 32.973\r
+   0.300 29.910\r
+   0.344 17.117\r
+   0.370 14.414\r
+   0.400 12.973\r
+   0.500 11.712\r
+   0.600 11.171\r
+   0.700 10.631\r
+   0.800 10.09\r
+   0.900 9.73\r
+   1.000 9.55\r
+   1.101 9.91\r
+   1.200 9.55\r
+   1.300 9.73\r
+   1.400 9.73\r
+   1.500 9.73\r
+   1.600 9.73\r
+   1.700 9.55\r
+   1.800 9.73\r
+   1.900 9.73\r
+   2.000 9.55\r
+   2.100 9.55\r
+   2.200 9.73\r
+   2.300 9.19\r
+   2.375 9.37\r
+   2.400 5.95\r
+   2.440 0.0\r
diff --git a/core/resources/datafiles/thrustcurves/Estes_E30.eng b/core/resources/datafiles/thrustcurves/Estes_E30.eng
new file mode 100644 (file)
index 0000000..096896d
--- /dev/null
@@ -0,0 +1,29 @@
+; Estes E30\r
+; from NAR data sheet updated 08/01/2010\r
+; created by David Moore  08/17/2012\r
+E30 24 70 4-7 .0178 .0470 ESTES\r
+   0.01 49\r
+   0.02 49\r
+   0.05 46\r
+   0.10 44\r
+   0.20 43\r
+   0.25 42\r
+   0.30 41\r
+   0.35 40\r
+   0.40 39\r
+   0.45 38\r
+   0.50 37\r
+   0.55 35\r
+   0.60 33\r
+   0.65 32\r
+   0.70 31\r
+   0.75 30\r
+   0.80 27\r
+   0.85 25\r
+   0.90 20\r
+   0.91 19\r
+   0.93 12\r
+   0.95  5\r
+   0.97  1\r
+   1.00  0\r
+;\r
diff --git a/core/resources/datafiles/thrustcurves/Estes_F26.eng b/core/resources/datafiles/thrustcurves/Estes_F26.eng
new file mode 100644 (file)
index 0000000..e005837
--- /dev/null
@@ -0,0 +1,36 @@
+;\r
+;ESTES G80\r
+;From NAR Certification 11/28/2007\r
+;File created 08/17/2012 by David Moore\r
+;Blue Thunder propellant [Relabeled Aerotech]\r
+G80 29 128 7 0.0625 0.128 Estes\r
+   0.006    1.2\r
+   0.008    7.5\r
+   0.010   33.8\r
+   0.012   64.6\r
+   0.014   62.9\r
+   0.016   58.8\r
+   0.018   74.9\r
+   0.020   85.0\r
+   0.022   91.1\r
+   0.026   94.0\r
+   0.028   98.4\r
+   0.032   97.7\r
+   0.074   97.3\r
+   0.124   95.4\r
+   0.376   99.3\r
+   0.680   99.4\r
+   0.994   91.6\r
+   1.246   83.0\r
+   1.282   77.4\r
+   1.316   62.0\r
+   1.360   44.6\r
+   1.424   29.1\r
+   1.504   21.2\r
+   1.598   19.3\r
+   1.656   16.3 \r
+   1.676   13.9\r
+   1.678   11.8\r
+   1.714    5.1\r
+   1.734    1.4\r
+   1.808    0.0\r
diff --git a/core/resources/datafiles/thrustcurves/Estes_F50.eng b/core/resources/datafiles/thrustcurves/Estes_F50.eng
new file mode 100644 (file)
index 0000000..ba92966
--- /dev/null
@@ -0,0 +1,37 @@
+; Estes F50 Blue thunder Porpellant [Relabeled Aerotech]\r
+; File produced July 4, 2000\r
+; The total impulse, peak thrust, average thrust and burn time are\r
+; the same as the averaged static test data on the NAR web site in\r
+; the certification file.\r
+F50 29 98 6 .0379 .0836 Estes\r
+  0.012 51.377\r
+  0.023 61.197\r
+  0.026 66.117\r
+  0.044 66.564\r
+  0.082 69.685\r
+  0.152 73.264\r
+  0.208 75.053\r
+  0.237 77.279\r
+  0.254 76.832\r
+  0.272 77.726\r
+  0.307 77.726\r
+  0.330 76.832\r
+  0.336 78.621\r
+  0.342 76.832\r
+  0.354 79.590\r
+  0.363 76.385\r
+  0.371 77.756\r
+  0.395 76.385\r
+  0.447 75.937\r
+  0.523 73.711\r
+  0.652 68.344\r
+  0.810 60.302\r
+  0.828 62.539\r
+  0.836 58.076\r
+  0.901 53.603\r
+  1.079 37.074\r
+  1.158 29.480\r
+  1.196 25.464\r
+  1.246 16.976\r
+  1.301  9.380\r
+  1.430  0.000\r
diff --git a/core/resources/datafiles/thrustcurves/Estes_G40.eng b/core/resources/datafiles/thrustcurves/Estes_G40.eng
new file mode 100644 (file)
index 0000000..006dbba
--- /dev/null
@@ -0,0 +1,16 @@
+;ESTES G40W [Relabeled Aerotech]\r
+;Entered for ESTES on 8/18/2012 by David Moore\r
+;Original file by Tim VanMilligan\r
+G40W 29 124 7 0.0538 0.123 AeroTech\r
+   0.024 74.325\r
+   0.057 67.005\r
+   0.252 65.879\r
+   0.500 63.063\r
+   0.765 60.248\r
+   1.000 54.054\r
+   1.250 47.298\r
+   1.502 36.599\r
+   1.751 25.338\r
+   1.999 12.951\r
+   2.121  3.941\r
+   2.300      0\r
diff --git a/core/resources/datafiles/thrustcurves/Estes_G40_1.eng b/core/resources/datafiles/thrustcurves/Estes_G40_1.eng
new file mode 100644 (file)
index 0000000..c845b31
--- /dev/null
@@ -0,0 +1,16 @@
+;ESTES G40W [Relabeled Aerotech]\r
+;Entered for ESTES on 8/18/2012 by David Moore\r
+;Original file by Tim VanMilligan\r
+G40W 29 124 4-7-10 0.0538 0.123 AeroTech\r
+   0.024 74.325\r
+   0.057 67.005\r
+   0.252 65.879\r
+   0.500 63.063\r
+   0.765 60.248\r
+   1.000 54.054\r
+   1.250 47.298\r
+   1.502 36.599\r
+   1.751 25.338\r
+   1.999 12.951\r
+   2.121  3.941\r
+   2.300      0\r
diff --git a/core/resources/datafiles/thrustcurves/GR_M1025.rse b/core/resources/datafiles/thrustcurves/GR_M1025.rse
new file mode 100644 (file)
index 0000000..10cb999
--- /dev/null
@@ -0,0 +1,19 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="Gorilla_Rocket_Motors" code="M1025WC" Type="reloadable" dia="98."\r
+len="869.95" initWt="10138." propWt="5329." delays="1000" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="1024.39" peakThrust="1780." throatDia="0."\r
+exitDia="0." Itot="9590.88" burn-time="9.36" massFrac="52.56" Isp="183.52"\r
+tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
+mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <data>\r
+      <eng-data  t="0." f="0." m="5329." cg="434.975"/>\r
+      <eng-data  t="0.1" f="1780." m="5279.55" cg="434.975"/>\r
+      <eng-data  t="0.5" f="1558." m="4908.61" cg="434.975"/>\r
+      <eng-data  t="3.25641" f="1500." m="2566.87" cg="434.975"/>\r
+      <eng-data  t="6.17949" f="795.082" m="703.085" cg="434.975"/>\r
+      <eng-data  t="9.3625" f="0." m="0." cg="434.975"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
diff --git a/core/resources/datafiles/thrustcurves/GR_M1465.rse b/core/resources/datafiles/thrustcurves/GR_M1465.rse
new file mode 100644 (file)
index 0000000..3db24a4
--- /dev/null
@@ -0,0 +1,22 @@
+<engine-database>\r
+  <engine-list>\r
+    <engine  mfg="Gorilla_Rocket_Motors" code="M1465BL" Type="reloadable" dia="98."\r
+len="869.95" initWt="9801." propWt="4992." delays="1000" auto-calc-mass="1"\r
+auto-calc-cg="1" avgThrust="1449.69" peakThrust="2219." throatDia="0."\r
+exitDia="0." Itot="7538.4" burn-time="5.2" massFrac="50.93" Isp="153.99"\r
+tDiv="10" tStep="-1." tFix="1" FDiv="10" FStep="-1." FFix="1" mDiv="10"\r
+mStep="-1." mFix="1" cgDiv="10" cgStep="-1." cgFix="1">\r
+    <data>\r
+      <eng-data  t="0." f="0." m="4992." cg="434.975"/>\r
+      <eng-data  t="0.33" f="1113." m="4870.39" cg="434.975"/>\r
+      <eng-data  t="1.64957" f="1752.05" m="3618.6" cg="434.975"/>\r
+      <eng-data  t="3." f="2219." m="1843.01" cg="434.975"/>\r
+      <eng-data  t="3.51282" f="2100.41" m="1109.59" cg="434.975"/>\r
+      <eng-data  t="3.98291" f="1823.77" m="498.8" cg="434.975"/>\r
+      <eng-data  t="4.3" f="1335." m="167.156" cg="434.975"/>\r
+      <eng-data  t="4.45299" f="334." m="82.6109" cg="434.975"/>\r
+      <eng-data  t="5.2" f="0." m="0." cg="434.975"/>\r
+    </data>\r
+  </engine>\r
+</engine-list>\r
+</engine-database>\r
index 397d8b343f1223792d6889212fe98b191012be77..d1226505d25f97b05d601c87021f1f81b3c8b7c9 100644 (file)
@@ -4,7 +4,7 @@
 ; the certification file. The curve drawn with these data points is as\r
 ; close to the certification curve as can be with such a limited\r
 ; number of points (32) allowed with wRASP up to v1.6.\r
-D5 20 96 4-6 0.0240 0.451 QUEST\r
+D5 20 96 4-6 0.0240 0.0451 QUEST\r
 0.010 1.014\r
 0.122 2.652\r
 0.172 4.836\r
diff --git a/core/resources/datafiles/thrustcurves/Quest_Micro_Maxx_II.eng b/core/resources/datafiles/thrustcurves/Quest_Micro_Maxx_II.eng
new file mode 100644 (file)
index 0000000..274c231
--- /dev/null
@@ -0,0 +1,39 @@
+; Traced from NAR certification data dated 1-29-2009\r
+MicroMaxxII 6 26 1 5.0E-4 0.0010 Q\r
+   0.021 0.015\r
+   0.036 0.05\r
+   0.043 0.103\r
+   0.049 0.198\r
+   0.08 1.636\r
+   0.092 1.3\r
+   0.109 0.995\r
+   0.124 0.805\r
+   0.133 0.442\r
+   0.143 0.301\r
+   0.164 0.21\r
+   0.186 0.149\r
+   0.199 0.183\r
+   0.235 0.145\r
+   0.256 0.145\r
+   0.293 0.149\r
+   0.327 0.164\r
+   0.367 0.156\r
+   0.387 0.175\r
+   0.409 0.183\r
+   0.431 0.191\r
+   0.461 0.21\r
+   0.474 0.202\r
+   0.49 0.217\r
+   0.505 0.175\r
+   0.513 0.198\r
+   0.537 0.172\r
+   0.553 0.175\r
+   0.602 0.156\r
+   0.623 0.175\r
+   0.644 0.183\r
+   0.674 0.21\r
+   0.689 0.191\r
+   0.697 0.229\r
+   0.731 0.21\r
+   0.753 0.092\r
+   0.771 0.0\r
diff --git a/core/resources/dejavu-font/DejaVuSerif.ttf b/core/resources/dejavu-font/DejaVuSerif.ttf
new file mode 100644 (file)
index 0000000..ed53a29
Binary files /dev/null and b/core/resources/dejavu-font/DejaVuSerif.ttf differ
diff --git a/core/resources/dejavu-font/LICENSE b/core/resources/dejavu-font/LICENSE
new file mode 100644 (file)
index 0000000..254e2cc
--- /dev/null
@@ -0,0 +1,99 @@
+Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
+Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
+
+Bitstream Vera Fonts Copyright
+------------------------------
+
+Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
+a trademark of Bitstream, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of the fonts accompanying this license ("Fonts") and associated
+documentation files (the "Font Software"), to reproduce and distribute the
+Font Software, including without limitation the rights to use, copy, merge,
+publish, distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright and trademark notices and this permission notice shall
+be included in all copies of one or more of the Font Software typefaces.
+
+The Font Software may be modified, altered, or added to, and in particular
+the designs of glyphs or characters in the Fonts may be modified and
+additional glyphs or characters may be added to the Fonts, only if the fonts
+are renamed to names not containing either the words "Bitstream" or the word
+"Vera".
+
+This License becomes null and void to the extent applicable to Fonts or Font
+Software that has been modified and is distributed under the "Bitstream
+Vera" names.
+
+The Font Software may be sold as part of a larger software package but no
+copy of one or more of the Font Software typefaces may be sold by itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
+TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
+FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
+ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
+THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
+FONT SOFTWARE.
+
+Except as contained in this notice, the names of Gnome, the Gnome
+Foundation, and Bitstream Inc., shall not be used in advertising or
+otherwise to promote the sale, use or other dealings in this Font Software
+without prior written authorization from the Gnome Foundation or Bitstream
+Inc., respectively. For further information, contact: fonts at gnome dot
+org. 
+
+Arev Fonts Copyright
+------------------------------
+
+Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the fonts accompanying this license ("Fonts") and
+associated documentation files (the "Font Software"), to reproduce
+and distribute the modifications to the Bitstream Vera Font Software,
+including without limitation the rights to use, copy, merge, publish,
+distribute, and/or sell copies of the Font Software, and to permit
+persons to whom the Font Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright and trademark notices and this permission notice
+shall be included in all copies of one or more of the Font Software
+typefaces.
+
+The Font Software may be modified, altered, or added to, and in
+particular the designs of glyphs or characters in the Fonts may be
+modified and additional glyphs or characters may be added to the
+Fonts, only if the fonts are renamed to names not containing either
+the words "Tavmjong Bah" or the word "Arev".
+
+This License becomes null and void to the extent applicable to Fonts
+or Font Software that has been modified and is distributed under the 
+"Tavmjong Bah Arev" names.
+
+The Font Software may be sold as part of a larger software package but
+no copy of one or more of the Font Software typefaces may be sold by
+itself.
+
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
+TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
+
+Except as contained in this notice, the name of Tavmjong Bah shall not
+be used in advertising or otherwise to promote the sale, use or other
+dealings in this Font Software without prior written authorization
+from Tavmjong Bah. For further information, contact: tavmjong @ free
+. fr.
+
+$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $
diff --git a/core/resources/dejavu-font/README b/core/resources/dejavu-font/README
new file mode 100644 (file)
index 0000000..0f2079a
--- /dev/null
@@ -0,0 +1,59 @@
+DejaVu fonts 2.33 (c)2004-2011 DejaVu fonts team
+------------------------------------------------
+
+The DejaVu fonts are a font family based on the Bitstream Vera Fonts
+(http://gnome.org/fonts/). Its purpose is to provide a wider range of
+characters (see status.txt for more information) while maintaining the
+original look and feel.
+
+DejaVu fonts are based on Bitstream Vera fonts version 1.10.
+
+Available fonts (Sans = sans serif, Mono = monospaced):
+
+DejaVu Sans Mono
+DejaVu Sans Mono Bold
+DejaVu Sans Mono Bold Oblique
+DejaVu Sans Mono Oblique
+DejaVu Sans
+DejaVu Sans Bold
+DejaVu Sans Bold Oblique
+DejaVu Sans Oblique
+DejaVu Sans ExtraLight (experimental)
+DejaVu Serif
+DejaVu Serif Bold
+DejaVu Serif Bold Italic (experimental)
+DejaVu Serif Italic (experimental)
+DejaVu Sans Condensed (experimental)
+DejaVu Sans Condensed Bold (experimental)
+DejaVu Sans Condensed Bold Oblique (experimental)
+DejaVu Sans Condensed Oblique (experimental)
+DejaVu Serif Condensed (experimental)
+DejaVu Serif Condensed Bold (experimental)
+DejaVu Serif Condensed Bold Italic (experimental)
+DejaVu Serif Condensed Italic (experimental)
+
+All fonts are also available as derivative called DejaVu LGC with support
+only for Latin, Greek and Cyrillic scripts.
+
+For license information see LICENSE. What's new is described in NEWS. Known
+bugs are in BUGS. All authors are mentioned in AUTHORS.
+
+Fonts are published in source form as SFD files (Spline Font Database from
+FontForge - http://fontforge.sf.net/) and in compiled form as TTF files
+(TrueType fonts).
+
+For more information go to http://dejavu.sourceforge.net/.
+
+Characters from Arev fonts, Copyright (c) 2006 by Tavmjong Bah:
+---------------------------
+U+01BA, U+01BF, U+01F7, U+021C-U+021D, U+0220, U+0222-U+0223,
+U+02B9, U+02BA, U+02BD, U+02C2-U+02C5, U+02d4-U+02D5,
+U+02D7, U+02EC-U+02EE, U+0346-U+034E, U+0360, U+0362,
+U+03E2-03EF, U+0460-0463, U+0466-U+0486, U+0488-U+0489, U+04A8-U+04A9,
+U+0500-U+050F, U+2055-205E, U+20B0, U+20B2-U+20B3, U+2102, U+210D, U+210F,
+U+2111, U+2113, U+2115, U+2118-U+211A, U+211C-U+211D, U+2124, U+2135,
+U+213C-U+2140, U+2295-U+2298, U+2308-U+230B, U+26A2-U+26B1, U+2701-U+2704,
+U+2706-U+2709, U+270C-U+274B, U+2758-U+275A, U+2761-U+2775, U+2780-U+2794,
+U+2798-U+27AF, U+27B1-U+27BE, U+FB05-U+FB06
+
+$Id: README 2471 2011-02-27 14:25:15Z ben_laenen $
index 4ffdbd98f9ce70a25e4d4e3e62da4da0bcd74e2d..1c68f3fd20bd7561b89746040ca537b053426a7a 100644 (file)
@@ -1,4 +1,3 @@
-
 #
 # English base translation file
 #
@@ -26,7 +25,7 @@ RocketActions.DelCompAct.Delete = Delete
 RocketActions.DelCompAct.ttip.Delete = Delete the selected component.
 RocketActions.DelSimuAct.Delete = Delete
 RocketActions.DelSimuAct.ttip.Delete = Delete the selected simulation.
-RocketActions.DelAct.Delete = Delete 
+RocketActions.DelAct.Delete = Delete
 RocketActions.DelAct.ttip.Delete = Delete the selected component or simulation.
 RocketActions.CutAction.Cut = Cut
 RocketActions.CutAction.ttip.Cut = Cut this component or simulation to the clipboard and remove from this design
@@ -48,7 +47,7 @@ RocketActions.MoveDownAct.ttip.Movedown = Move this component downwards.
 RocketPanel.FigTypeAct.Sideview = Side view
 RocketPanel.FigTypeAct.ttip.Sideview = Side view
 RocketPanel.FigTypeAct.Backview = Back view
-RocketPanel.FigTypeAct.ttip.Backview = Rear view 
+RocketPanel.FigTypeAct.ttip.Backview = Rear view
 RocketPanel.FigViewAct.2D = 2D View
 RocketPanel.FigViewAct.ttip.2D = 2D View
 RocketPanel.FigViewAct.3D = 3D View
@@ -90,12 +89,12 @@ dlg.but.ok = OK
 dlg.but.cancel = Cancel
 dlg.but.close = Close
 
-
 ! General file type names
 filetypes.pdf = PDF files (*.pdf)
 BasicFrame.SimpleFileFilter1 = All rocket designs (*.ork; *.rkt)
 BasicFrame.SimpleFileFilter2 = OpenRocket designs (*.ork)
 BasicFrame.SimpleFileFilter3 = RockSim designs (*.rkt)
+BasicFrame.SimpleFileFilter4 = OpenRocket presets (*.orc)
 filetypes.images = Image files
 
 
@@ -107,9 +106,9 @@ AboutDialog.lbl.version = Version
 ! - AboutDialog.lbl.translatorWebsite is a URL to the translator / group (may be empty)
 ! - AboutDialog.lbl.translatorIcon is the file name of an icon under pix/translators/ (may be empty)
 AboutDialog.lbl.translation = English translation by:
-AboutDialog.lbl.translator = 
-AboutDialog.lbl.translatorWebsite = 
-AboutDialog.lbl.translatorIcon =  
+AboutDialog.lbl.translator =
+AboutDialog.lbl.translatorWebsite =
+AboutDialog.lbl.translatorIcon =
 
 
 ! Print dialog
@@ -124,7 +123,6 @@ PrintDialog.error.preview.title = Unable to open preview
 PrintDialog.error.preview.desc1 = Unable to open PDF preview.
 PrintDialog.error.preview.desc2 = Please use the "Save as PDF" option instead.
 
-
 !PrintSettingsDialog
 PrintSettingsDialog.title = Print settings
 PrintSettingsDialog.lbl.Templatefillcolor = Template fill color:
@@ -171,6 +169,9 @@ debuglogdlg.lbl.Logmessage = Log message:
 debuglogdlg.lbl.Stacktrace = Stack trace:
 
 
+! MotorChooserDialog
+MotorChooserDialog.title = Select a rocket motor
+
 ! Edit Motor configuration dialog
 edtmotorconfdlg.but.removemotor = Remove motor
 edtmotorconfdlg.but.Selectmotor = Select motor
@@ -221,7 +222,7 @@ pref.dlg.but.reset = Reset
 pref.dlg.but.checknow = Check now
 pref.dlg.but.defaultmetric = Default metric
 pref.dlg.but.defaultimperial = Default imperial
-pref.dlg.title.Preferences = Preferences 
+pref.dlg.title.Preferences = Preferences
 pref.dlg.tab.Units = Units
 pref.dlg.tab.Defaultunits = Default units
 pref.dlg.tab.Materials = Materials
@@ -231,6 +232,7 @@ pref.dlg.tab.Miscellaneousoptions = Miscellaneous options
 pref.dlg.lbl.Positiontoinsert = Position to insert new body components:
 pref.dlg.lbl.Confirmdeletion = Confirm deletion of simulations:
 pref.dlg.lbl.User-definedthrust = User-defined thrust curves:
+pref.dlg.lbl.Windspeed = Wind speed
 pref.dlg.Allthrustcurvefiles = All thrust curve files (*.eng; *.rse; *.zip; directories)
 pref.dlg.RASPfiles = RASP motor files (*.eng)
 pref.dlg.RockSimfiles = RockSim engine files (*.rse)
@@ -286,6 +288,7 @@ simedtdlg.lbl.Simname = Simulation name:
 simedtdlg.tab.Launchcond = Launch conditions
 simedtdlg.tab.Simopt = Simulation options
 simedtdlg.tab.Plotdata = Plot data
+simedtdlg.tab.CustomExpressions = Custom expressions
 simedtdlg.tab.Exportdata = Export data
 simedtdlg.lbl.Motorcfg = Motor configuration:
 simedtdlg.lbl.ttip.Motorcfg = Select the motor configuration to use.
@@ -340,7 +343,7 @@ simedtdlg.lbl.ttip.Timestep1 = <html>The time between simulation steps.<br>A sma
 simedtdlg.lbl.ttip.Timestep2 = The 4<sup>th</sup> order simulation method is quite accurate with a time step of
 simedtdlg.but.ttip.resettodefault = Reset the time step to its default value (
 simedtdlg.border.Simlist = Simulator listeners
-simedtdlg.txt.longA1 = <html><i>Simulation listeners</i> is an advanced feature that allows user-written code to listen to and interact with the simulation.  
+simedtdlg.txt.longA1 = <html><i>Simulation listeners</i> is an advanced feature that allows user-written code to listen to and interact with the simulation.
 simedtdlg.txt.longA2 = For details on writing simulation listeners, see the OpenRocket technical documentation.
 simedtdlg.lbl.Curlist = Current listeners:
 simedtdlg.lbl.Addsimlist = Add simulation listener
@@ -391,6 +394,14 @@ simpanel.col.Maxacceleration = Max. acceleration
 simpanel.col.Timetoapogee = Time to apogee
 simpanel.col.Flighttime = Flight time
 simpanel.col.Groundhitvelocity = Ground hit velocity
+simpanel.ttip.uptodate = <i>Up to date</i>
+simpanel.ttip.loaded = <i>Data loaded from a file</i>
+simpanel.ttip.outdated = <i><font color=\"red\">Data is out of date</font></i><br>Click <i><b>Run simulations</b></i> to simulate.
+simpanel.ttip.external = <i>Imported data</i>
+simpanel.ttip.notSimulated = <i>Not simulated yet</i><br>Click <i><b>Run simulations</b></i> to simulate.
+simpanel.ttip.noData = No simulation data available.
+simpanel.ttip.noWarnings = <font color=\"gray\">No warnings.</font>
+simpanel.ttip.warnings = <font color=\"red\">Warnings:</font>
 
 ! SimulationRunDialog
 SimuRunDlg.title.RunSim = Running simulations...
@@ -410,6 +421,7 @@ SimuRunDlg.msg.unknownerror2 = The program may be unstable, you should save all
 
 RK4SimulationStepper.error.valuesTooLarge = Simulation values exceeded limits.  Try selecting a shorter time step.
 
+SimulationModifierTree.OptimizationParameters = Optimization Parameters
 
 ! SimulationExportPanel
 SimExpPan.desc = Comma Separated Files (*.csv)
@@ -434,7 +446,7 @@ SimExpPan.Fileexists.desc1 = File \"
 SimExpPan.Fileexists.desc2 = \" exists.  Overwrite?
 SimExpPan.Fileexists.title = File exists
 SimExpPan.ExportingVar.desc1 = Exporting 1 variable out of
-SimExpPan.ExportingVar.desc2 = Exporting 
+SimExpPan.ExportingVar.desc2 = Exporting
 SimExpPan.ExportingVar.desc3 = variables out of
 SimExpPan.Col.Variable = Variable
 SimExpPan.Col.Unit = Unit
@@ -444,6 +456,82 @@ CsvOptionPanel.separator.space = SPACE
 CsvOptionPanel.separator.tab = TAB
 
 
+! Custom expression general stuff
+customExpression.Name = Name
+customExpression.Symbol = Symbol
+customExpression.Expression = Expression
+customExpression.Units = Units
+customExpression.Operator = Operator
+customExpression.Description = Description
+
+! Custom expression panel
+customExpressionPanel.but.NewExpression = New expression
+customExpressionPanel.but.ttip.NewExpression = Add a new custom expression
+customExpressionPanel.but.Import = Import
+customExpressionPanel.but.ttip.Import = Import custom expressions from another .ork file
+customExpressionPanel.lbl.UpdateNote = You must run the simulation before data will be available for plotting.
+customExpressionPanel.lbl.CalcNote = Expressions will be calculated in the order shown.
+customExpressionPanel.lbl.CustomExpressions = Custom Expressions
+customExpression.Units.but.ttip.Remove = Remove this expression
+customExpression.Units.but.ttip.Edit = Edit this expression
+customExpression.Units.but.ttip.MoveUp = Move expression up in calculation order
+customExpression.Units.but.ttip.MoveDown = Move expression down in calculation order
+
+
+! Custom expression builder window
+ExpressionBuilderDialog.title = Expression Builder
+ExpressionBuilderDialog.InsertVariable = Insert Variable
+ExpressionBuilderDialog.InsertOperator = Insert Operator
+ExpressionBuilderDialog.led.ttip.Name = Name must not have already been used
+ExpressionBuilderDialog.led.ttip.Symbol = Symbol must not have already been used
+ExpressionBuilderDialog.led.ttip.Expression = Expression must use only known symbols and operators
+ExpressionBuilderDialog.CopyToOtherSimulations = Copy to other simulations
+ExpressionBuilderDialog.CopyToOtherSimulations.ttip = <html>Make a copy of this expression in other simulations in this document.<br>Will not overwrite or modify any existing expressions in other simulations. 
+
+! Custom expression variable selector
+CustomVariableSelector.title = Variable Selector
+
+! Custom operator selector
+CustomOperatorSelector.title = Operator Selector
+
+! Operators
+Operator.plus = Addition
+Operator.minus = Subtraction
+Operator.star = Multiplication
+Operator.div = Division
+Operator.mod = Modulo
+Operator.pow = Exponentiation
+Operator.abs = Absolute value
+Operator.ceil = Ceiling (next integer value)
+Operator.floor = Floor (previous integer value)
+Operator.sqrt = Square root
+Operator.cbrt = Cubic root
+Operator.exp = Euler\'s number raised to the value (e^x)
+Operator.ln = Natural logarithm
+Operator.sin = Sine
+Operator.cos = Cosine
+Operator.tan = Tangent
+Operator.asin = Arc sine
+Operator.acos = Arc cosine
+Operator.atan = Arc tangent
+Operator.hsin = Hyperbolic sine
+Operator.hcos = Hyperbolic cosine
+Operator.htan = Hyperbolic tangent
+Operator.log10 = Base 10 logarithm
+Operator.round = Round to nearest integer value
+Operator.random = Random number between zero and given value
+Operator.expm1 = The same as exp(x)-1, but more accurate for small x 
+Operator.mean = The arithmetic mean of a given range
+Operator.min = The minimum value in a given range
+Operator.max = The maximum value in a given range
+Operator.var = The variance of a given range
+Operator.stdev = The standard deviation of a given range
+Operator.rms = The root-mean-squared value of a given range
+Operator.lclip = Clips a value (1st parameter) to be no less than a given value (2nd parameter)
+Operator.uclip = Clips a value (1st parameter) to be no greater than a given value (2nd parameter)
+Operator.binf = Gives the fraction of values in a given range (1st parameter) inside a bin with given lower (2nd parameter) and upper (3rd parameter) bounds
+Operator.trapz = Integrates the given range using trapezoidal integration
+Operator.tnear = Find the time corresponding to the point in a range (1st parameter) nearest to a given value (2nd parameter)
 
 ! MotorPlot
 MotorPlot.title.Motorplot = Motor plot
@@ -457,8 +545,6 @@ MotorPlot.txt.Type = Type:
 MotorPlot.txt.Delays = Delays:
 MotorPlot.txt.Comment = Comment:\n
 
-
-
 ! Simulation plot panel
 simplotpanel.lbl.Presetplotconf = Preset plot configurations:
 simplotpanel.lbl.Xaxistype = X axis type:
@@ -472,7 +558,7 @@ simplotpanel.but.Plotflight = Plot flight
 simplotpanel.lbl.Axis = Axis:
 simplotpanel.but.ttip.Removethisplot = Remove this plot
 simplotpanel.Desc = The data will be plotted in time order even if the X axis type is not time.
-simplotpanel.OptionPane.lbl1 = A maximum of 15 plots is allowed. 
+simplotpanel.OptionPane.lbl1 = A maximum of 15 plots is allowed.
 simplotpanel.OptionPane.lbl2 = Cannot add plot
 simplotpanel.AUTO_NAME = Auto
 simplotpanel.LEFT_NAME = Left
@@ -481,7 +567,6 @@ simplotpanel.CUSTOM = Custom
 SimulationPlotPanel.error.noPlotSelected = Please add one or more variables to plot on the Y-axis.
 SimulationPlotPanel.error.noPlotSelected.title = Nothing to plot
 
-
 ! Component add buttons
 compaddbuttons.Bodycompandfinsets = Body components and fin sets
 compaddbuttons.Nosecone = Nose cone
@@ -521,6 +606,9 @@ componentanalysisdlg.lbl.rollrate = Roll rate:
 componentanalysisdlg.lbl.activestages = Active stages:
 componentanalysisdlg.lbl.motorconf = Motor configuration:
 componentanalysisdlg.TabStability.Col = Component
+componentanalysisdlg.TabStability.Col.CG = CG
+componentanalysisdlg.TabStability.Col.Mass = Mass
+componentanalysisdlg.TabStability.Col.CP = CP
 componentanalysisdlg.TabStability = Stability
 componentanalysisdlg.TabStability.ttip = Stability information
 componentanalysisdlg.dragTableModel.Col.Component = Component
@@ -538,14 +626,16 @@ componentanalysisdlg.rollTableModel = Roll dynamics
 componentanalysisdlg.rollTableModel.ttip = Roll dynamics
 componentanalysisdlg.println.closingmethod = Closing method called:
 componentanalysisdlg.println.settingnam = SETTING NAN VALUES
-componentanalysisdlg.lbl.reflenght = Reference length: 
-componentanalysisdlg.lbl.refarea = Reference area: 
+componentanalysisdlg.lbl.reflenght = Reference length:
+componentanalysisdlg.lbl.refarea = Reference area:
 !componentanalysisdlg.But.close =Close
 componentanalysisdlg.TabStability.Col.Component = Component
+componentanalysisdlg.TOTAL = Total
+componentanalysisdlg.noWarnings = <html><i><font color=\"gray\">No warnings.</font></i>
 
 ! Custom Material dialog
 custmatdlg.title.Custommaterial = Custom material
-custmatdlg.lbl.Materialname = Material name: 
+custmatdlg.lbl.Materialname = Material name:
 custmatdlg.lbl.Materialtype = Material type:
 custmatdlg.lbl.Materialdensity = Material density:
 custmatdlg.checkbox.Addmaterial = Add material to database
@@ -658,7 +748,7 @@ RocketCompCfg.checkbox.Endcapped = End capped
 RocketCompCfg.ttip.Endcapped = Whether the end of the shoulder is capped.
 RocketCompCfg.title.Noseconeshoulder = Nose cone shoulder
 RocketCompCfg.title.Aftshoulder = Aft shoulder
-RocketCompCfg.border.Foreshoulder = Fore shoulder 
+RocketCompCfg.border.Foreshoulder = Fore shoulder
 !RocketCompCfg.lbl.Length = Length:
 
 ! BulkheadConfig
@@ -753,6 +843,7 @@ LaunchLugCfg.tab.Generalprop = General properties
 
 ! MassComponentConfig
 MassComponentCfg.lbl.Mass = Mass:
+MassComponentCfg.lbl.Density = Approximate density:
 MassComponentCfg.lbl.Length = Length:
 MassComponentCfg.lbl.Diameter = Diameter:
 MassComponentCfg.lbl.PosRelativeto = Position relative to:
@@ -802,7 +893,7 @@ ParachuteCfg.lbl.Material = Material:
 ParachuteCfg.combo.MaterialModel = The component material affects the weight of the component.
 ParachuteCfg.lbl.longA1 = <html>Drag coefficient C<sub>D</sub>:
 ParachuteCfg.lbl.longB1 = <html>The drag coefficient relative to the total area of the parachute.<br>
-ParachuteCfg.lbl.longB2 = A larger drag coefficient yields a slowed descent rate.  
+ParachuteCfg.lbl.longB2 = A larger drag coefficient yields a slowed descent rate.
 ParachuteCfg.lbl.longB3 = A typical value for parachutes is 0.8.
 ParachuteCfg.but.Reset = Reset
 ParachuteCfg.lbl.Shroudlines = Shroud lines:
@@ -825,7 +916,7 @@ ParachuteCfg.lbl.Radialdirection = Radial direction:
 ParachuteCfg.but.Reset = Reset
 ParachuteCfg.lbl.plusdelay = plus
 
-! ShockCordConfig 
+! ShockCordConfig
 ShockCordCfg.lbl.Shockcordlength = Shock cord length:
 ShockCordCfg.lbl.Shockcordmaterial = Shock cord material:
 ShockCordCfg.lbl.Posrelativeto = Position relative to:
@@ -958,6 +1049,7 @@ TCMotorSelPan.lbl.Digest = Digest:
 TCMotorSelPan.title.Thrustcurve = Thrust curve:
 TCMotorSelPan.title.Thrust = Thrust
 TCMotorSelPan.delayBox.None = None
+TCMotorSelPan.noDescription = No description available.
 
 
 ! PlotDialog
@@ -969,7 +1061,7 @@ PlotDialog.lbl.Chart = Click and drag down+right to zoom in, up+left to zoom out
 
 ! "main" prefix is used for the main application dialog
 
-# FIXME: Rename the description keys 
+# FIXME: Rename the description keys
 
 main.menu.file = File
 main.menu.file.desc = File-handling related tasks
@@ -977,6 +1069,8 @@ main.menu.file.new = New
 main.menu.file.new.desc = Create a new rocket design
 main.menu.file.open = Open...
 BasicFrame.item.Openrocketdesign = Open a rocket design
+main.menu.file.openRecent = Open Recent...
+BasicFrame.item.Openrecentrocketdesign = Open a recent rocket design
 main.menu.file.openExample = Open example...
 BasicFrame.item.Openexamplerocketdesign = Open an example rocket design
 main.menu.file.save = Save
@@ -1011,6 +1105,8 @@ main.menu.analyze.componentAnalysis = Component analysis
 main.menu.analyze.componentAnalysis.desc = Analyze the rocket components separately
 main.menu.analyze.optimization = Rocket optimization
 main.menu.analyze.optimization.desc = General rocket design optimization
+main.menu.analyze.customExpressions = Custom expressions
+main.menu.analyze.customExpressions.desc = Define new flight data types by writing custom mathematical expressions 
 
 main.menu.help = Help
 main.menu.help.desc = Information about OpenRocket
@@ -1033,55 +1129,61 @@ main.menu.debug.createtestrocket = Create test rocket
 ! Translate here all material database
 !
 
+Material.CUSTOM = Custom
+
 ! Material database
+Databases.materials.types.Bulk = Bulk
+Databases.materials.types.Line = Line
+Databases.materials.types.Surface = Surface
+
 ! BULK_MATERIAL
-Databases.materials.Acrylic = Acrylic
-Databases.materials.Aluminum = Aluminum
-Databases.materials.Balsa = Balsa
-Databases.materials.Basswood = Basswood
-Databases.materials.Birch = Birch
-Databases.materials.Brass = Brass
-Databases.materials.Cardboard = Cardboard
-Databases.materials.Carbonfiber = Carbon fiber
-Databases.materials.Cork = Cork
-Databases.materials.DepronXPS = Depron (XPS)
-Databases.materials.Fiberglass = Fiberglass
-Databases.materials.Kraftphenolic = Kraft phenolic
-Databases.materials.Maple = Maple
-Databases.materials.Paperoffice = Paper (office)
-Databases.materials.Pine = Pine
-Databases.materials.Plywoodbirch = Plywood (birch)
-Databases.materials.PolycarbonateLexan = Polycarbonate (Lexan)
-Databases.materials.Polystyrene = Polystyrene
-Databases.materials.PVC = PVC
-Databases.materials.Spruce = Spruce
-Databases.materials.Steel = Steel
-Databases.materials.StyrofoamgenericEPS = Styrofoam (generic EPS)
-Databases.materials.StyrofoamBluefoamXPS = Styrofoam \"Blue foam\" (XPS)
-Databases.materials.Titanium = Titanium
-Databases.materials.Quantumtubing = Quantum tubing
-Databases.materials.BlueTube = Blue tube
+material.acrylic = Acrylic
+material.aluminum = Aluminum
+material.balsa = Balsa
+material.basswood = Basswood
+material.birch = Birch
+material.brass = Brass
+material.cardboard = Cardboard
+material.carbon_fiber = Carbon fiber
+material.cork = Cork
+material.depron_xps = Depron (XPS)
+material.fiberglass = Fiberglass
+material.kraft_phenolic = Kraft phenolic
+material.maple = Maple
+material.paper_office = Paper (office)
+material.pine = Pine
+material.plywood_birch = Plywood (birch)
+material.polycarbonate_lexan = Polycarbonate (Lexan)
+material.polystyrene = Polystyrene
+material.pvc = PVC
+material.spruce = Spruce
+material.steel = Steel
+material.styrofoam_generic_eps = Styrofoam (generic EPS)
+material.styrofoam_blue_foam_xps = Styrofoam \"Blue foam\" (XPS)
+material.titanium = Titanium
+material.quantum_tubing = Quantum tubing
+material.blue_tube = Blue tube
 !SURFACE_MATERIAL
-Databases.materials.Ripstopnylon = Ripstop nylon
-Databases.materials.Mylar = Mylar
-Databases.materials.Polyethylenethin = Polyethylene (thin)
-Databases.materials.Polyethyleneheavy = Polyethylene (heavy)
-Databases.materials.Silk = Silk
-Databases.materials.Paperoffice = Paper (office)
-Databases.materials.Cellophane = Cellophane
-Databases.materials.Crepepaper = Cr\u00eape paper
+material.ripstop_nylon = Ripstop nylon
+material.mylar = Mylar
+material.polyethylene_thin = Polyethylene (thin)
+material.polyethylene_heavy = Polyethylene (heavy)
+material.silk = Silk
+material.paper_office = Paper (office)
+material.cellophane = Cellophane
+material.crepe_paper = Cr\u00eape paper
 ! LINE_MATERIAL
-Databases.materials.Threadheavy-duty = Thread (heavy-duty)
-Databases.materials.Elasticcordround2mm = Elastic cord (round 2mm, 1/16 in)
-Databases.materials.Elasticcordflat6mm = Elastic cord (flat  6mm, 1/4 in)
-Databases.materials.Elasticcordflat12mm = Elastic cord (flat 12mm, 1/2 in)
-Databases.materials.Elasticcordflat19mm = Elastic cord (flat 19mm, 3/4 in)
-Databases.materials.Elasticcordflat25mm = Elastic cord (flat 25mm, 1 in)
-Databases.materials.Braidednylon2mm = Braided nylon (2 mm, 1/16 in)
-Databases.materials.Braidednylon3mm = Braided nylon (3 mm, 1/8 in)
-Databases.materials.Tubularnylon11mm = Tubular nylon (11 mm, 7/16 in)
-Databases.materials.Tubularnylon14mm = Tubular nylon (14 mm, 9/16 in)
-Databases.materials.Tubularnylon25mm = Tubular nylon (25 mm, 1 in)
+material.thread_heavy_duty = Thread (heavy-duty)
+material.elastic_cord_round_2_mm_1_16_in = Elastic cord (round 2 mm, 1/16 in)
+material.elastic_cord_flat_6_mm_1_4_in = Elastic cord (flat 6 mm, 1/4 in)
+material.elastic_cord_flat_12_mm_1_2_in = Elastic cord (flat 12 mm, 1/2 in)
+material.elastic_cord_flat_19_mm_3_4_in = Elastic cord (flat 19 mm, 3/4 in)
+material.elastic_cord_flat_25_mm_1_in = Elastic cord (flat 25 mm, 1 in)
+material.braided_nylon_2_mm_1_16_in = Braided nylon (2 mm, 1/16 in)
+material.braided_nylon_3_mm_1_8_in = Braided nylon (3 mm, 1/8 in)
+material.tubular_nylon_11_mm_7_16_in = Tubular nylon (11 mm, 7/16 in)
+material.tubular_nylon_14_mm_9_16_in = Tubular nylon (14 mm, 9/16 in)
+material.tubular_nylon_25_mm_1_in = Tubular nylon (25 mm, 1 in)
 
 ! ExternalComponent
 ExternalComponent.Rough = Rough
@@ -1106,16 +1208,16 @@ Shape.Ogive.desc1 = An ogive nose cone has a profile that is a segment of a circ
 Shape.Ogive.desc2 = An ogive transition has a profile that is a segment of a circle.   The shape parameter value 1 produces a <b>tangent ogive</b>, which has a smooth transition to the body tube at the aft end, values less than 1 produce <b>secant ogives</b>.
 Shape.Ellipsoid = Ellipsoid
 Shape.Ellipsoid.desc1 = An ellipsoidal nose cone has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.
-Shape.Ellipsoid.desc2 = An ellipsoidal transition has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the transition is not clipped, then the profile is extended at the center by the corresponding radius.             
+Shape.Ellipsoid.desc2 = An ellipsoidal transition has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the transition is not clipped, then the profile is extended at the center by the corresponding radius.
 Shape.Powerseries = Power series
-Shape.Powerseries.desc1 = A power series nose cone has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 this is a <b>\u00BD-power</b> or <b>parabolic</b> nose cone, for <i>k</i>=0.75 a <b>\u00BE-power</b>, and for <i>k</i>=1 a <b>conical</b> nose cone.
-Shape.Powerseries.desc2 = A power series transition has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 the transition is <b>\u00BD-power</b> or <b>parabolic</b>, for <i>k</i>=0.75 a <b>\u00BE-power</b>, and for <i>k</i>=1 <b>conical</b>.
+Shape.Powerseries.desc1 = A power series nose cone has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 this is a <b>\u00bd-power</b> or <b>parabolic</b> nose cone, for <i>k</i>=0.75 a <b>\u00be-power</b>, and for <i>k</i>=1 a <b>conical</b> nose cone.
+Shape.Powerseries.desc2 = A power series transition has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 the transition is <b>\u00bd-power</b> or <b>parabolic</b>, for <i>k</i>=0.75 a <b>\u00be-power</b>, and for <i>k</i>=1 <b>conical</b>.
 Shape.Parabolicseries = Parabolic series
 Shape.Parabolicseries.desc1 = A parabolic series nose cone has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.
 Shape.Parabolicseries.desc2 = A parabolic series transition has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.
 Shape.Haackseries = Haack series
 Shape.Haackseries.desc1 = The Haack series nose cones are designed to minimize drag.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> nose cone, which minimizes drag for fixed length and diameter, while a value of 0.333 produces an <b>LV-Haack</b> nose cone, which minimizes drag for fixed length and volume.
-Shape.Haackseries.desc2 = The Haack series <i>nose cones</i> are designed to minimize drag.  These transition shapes are their equivalents, but do not necessarily produce optimal drag for transitions.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, while a value of 0.333 produces an <b>LV-Haack</b> shape.              
+Shape.Haackseries.desc2 = The Haack series <i>nose cones</i> are designed to minimize drag.  These transition shapes are their equivalents, but do not necessarily produce optimal drag for transitions.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, while a value of 0.333 produces an <b>LV-Haack</b> shape.
 
 
 ! RocketComponent
@@ -1159,6 +1261,14 @@ Parachute.Parachute = Parachute
 ShockCord.ShockCord = Shock cord
 ! Bulkhead
 Bulkhead.Bulkhead = Bulkhead
+! CenteringRing
+CenteringRing.CenteringRing = Centering ring
+! EngineBlock
+EngineBlock.EngineBlock = Engine block
+! Streamer
+Streamer.Streamer = Streamer
+! Sleeve
+Sleeve.Sleeve = Sleeve
 
 !Rocket
 Rocket.motorCount.Nomotor = [No motors]
@@ -1171,7 +1281,7 @@ MotorMount.IgnitionEvent.EJECTION_CHARGE = First ejection charge of previous sta
 MotorMount.IgnitionEvent.BURNOUT = First burnout of previous stage
 MotorMount.IgnitionEvent.NEVER = Never
 
-!ComponentIcons 
+!ComponentIcons
 ComponentIcons.Nosecone = Nose cone
 ComponentIcons.Bodytube = Body tube
 ComponentIcons.Transition = Transition
@@ -1198,6 +1308,8 @@ RecoveryDevice.DeployEvent.LAUNCH = Launch (plus NN seconds)
 RecoveryDevice.DeployEvent.EJECTION = First ejection charge of this stage
 RecoveryDevice.DeployEvent.APOGEE = Apogee
 RecoveryDevice.DeployEvent.ALTITUDE = Specific altitude during descent
+RecoveryDevice.DeployEvent.CURRENT_STAGE_SEPARATION = Current stage separation
+RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION = Lower stage separation
 RecoveryDevice.DeployEvent.NEVER = Never
 
 ! FlightEvent
@@ -1221,10 +1333,19 @@ TCurveMotorCol.TYPE = Type
 TCurveMotorCol.DIAMETER = Diameter
 TCurveMotorCol.LENGTH = Length
 
+TCurveMotor.ttip.diameter = Diameter:
+TCurveMotor.ttip.length = Length:
+TCurveMotor.ttip.maxThrust = Maximum thrust:
+TCurveMotor.ttip.avgThrust = Average thrust:
+TCurveMotor.ttip.burnTime = Burn time:
+TCurveMotor.ttip.totalImpulse = Total impulse:
+TCurveMotor.ttip.launchMass = Launch mass:
+TCurveMotor.ttip.emptyMass = Empty mass:
+
 ! RocketInfo
 RocketInfo.lengthLine.Length = Length
 RocketInfo.lengthLine.maxdiameter = , max. diameter
-RocketInfo.massText1 = Mass with motors 
+RocketInfo.massText1 = Mass with motors
 RocketInfo.massText2 = Mass with no motors
 RocketInfo.at = at M=
 RocketInfo.cgText = CG:
@@ -1266,6 +1387,7 @@ FlightDataType.TYPE_ROLL_RATE = Roll rate
 FlightDataType.TYPE_PITCH_RATE = Pitch rate
 FlightDataType.TYPE_YAW_RATE = Yaw rate
 FlightDataType.TYPE_MASS = Mass
+FlightDataType.TYPE_PROPELLANT_MASS = Propellant mass
 FlightDataType.TYPE_LONGITUDINAL_INERTIA = Longitudinal moment of inertia
 FlightDataType.TYPE_ROTATIONAL_INERTIA = Rotational moment of inertia
 FlightDataType.TYPE_CP_LOCATION = CP location
@@ -1302,6 +1424,7 @@ FlightDataType.TYPE_COMPUTATION_TIME = Computation time
 FlightDataType.TYPE_LATITUDE = Latitude
 FlightDataType.TYPE_LONGITUDE = Longitude
 FlightDataType.TYPE_CORIOLIS_ACCELERATION = Coriolis acceleration
+FlightDataType.TYPE_GRAVITY = Gravitational acceleration
 
 ! PlotConfiguration
 PlotConfiguration.Verticalmotion = Vertical motion vs. time
@@ -1322,6 +1445,10 @@ Warning.JAGGED_EDGED_FIN = Jagged-edged fin predictions may be inaccurate.
 Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
 Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING = Recovery device opened while motor still burning.
 Warning.FILE_INVALID_PARAMETER = Invalid parameter encountered, ignoring.
+Warning.PARALLEL_FINS = Too many parallel fins
+Warning.SUPERSONIC = Body calculations may not be entirely accurate at supersonic speeds.
+Warning.RECOVERY_LAUNCH_ROD = Recovery device device deployed while on the launch guide.
+Warning.RECOVERY_HIGH_SPEED = Recovery device deployment at high speed
 
 
 ! Scale dialog
@@ -1354,6 +1481,7 @@ OpenRocketPrintable.Transitiontemplates = Transition templates
 OpenRocketPrintable.Noseconetemplates = Nose Cone templates
 OpenRocketPrintable.Finmarkingguide = Fin marking guide
 OpenRocketPrintable.DesignReport = Design Report
+OpenRocketPrintable.Centeringringtemplates = Centering Ring templates
 
 OpenRocketDocument.Redo = Redo
 OpenRocketDocument.Undo = Undo
@@ -1576,11 +1704,53 @@ GuidedTourSelectionDialog.btn.start = Start tour!
 
 ! Custom Fin BMP Importer
 CustomFinImport.button.label = Import from image
-CustomFinImport.badFinImage = Invalid fin image. Must be a black and white image (black for the fin), not touching any side, except the bottom of the image, which is the base of the fin.
-CustomFinImport.errorLoadingFile = Error loading file: 
-CustomFinImport.errorParsingFile = Error parsing fin image: 
+CustomFinImport.badFinImage = Invalid fin image. Make sure the fin is a solid black or dark color and touching the bottom of the image.
+CustomFinImport.errorLoadingFile = Error loading file:
+CustomFinImport.errorParsingFile = Error parsing fin image:
 CustomFinImport.undo = Import freeform fin set
 CustomFinImport.error.title = Error loading fin profile
 CustomFinImport.error.badimage = Could not deduce fin shape from image.
-CustomFinImport.description = The image must be a black and white image (black for the fin), not touching any side, except the bottom of the image, which is the base of the fin.
+CustomFinImport.description = The image will be converted internally to black and white image (black for the fin), so make sure you use a solid dark color for the fin, and white or a light color for the background. The fin must be touching the bottom of the image, which is the base of the fin.
+
+
+PresetModel.lbl.select = Select preset
+PresetModel.lbl.database = From database...
+
+
+! Component Preset Chooser Dialog
+ComponentPresetChooserDialog.title = Choose component preset
+ComponentPresetChooserDialog.filter.label = Filter by text:
+ComponentPresetChooserDialog.checkbox.filterAftDiameter = Match aft diameter
+ComponentPresetChooserDialog.checkbox.filterForeDiameter = Match fore diameter
+ComponentPresetChooserDialog.menu.sortAsc = Sort Ascending
+ComponentPresetChooserDialog.menu.sortDesc = Sort Descending
+ComponentPresetChooserDialog.menu.units = Units
+ComponentPresetChooserDialog.checkbox.showAllCompatible = Show all compatible
+table.column.Favorite = Favorite
+table.column.Manufacturer = Manufacturer
+table.column.PartNo = Part Number
+table.column.Description = Description
+table.column.Type = Type
+table.column.Length = Length
+table.column.Width = Width
+table.column.InnerDiameter = Inner Diameter
+table.column.OuterDiameter = Outer Diameter
+table.column.AftOuterDiameter = Aft Outer Diameter
+table.column.AftShoulderLength = Aft Shoulder Length
+table.column.AftShoulderDiameter = Aft Shoulder Diameter
+table.column.ForeShoulderLength = Fore Shoulder Length
+table.column.ForeShoulderDiameter = Fore Shoulder Diameter
+table.column.ForeOuterDiameter = Fore Outer Diameter
+table.column.Shape = Shape
+table.column.Material = Material
+table.column.Finish = Finish
+table.column.Thickness = Thickness
+table.column.Filled = Filled
+table.column.Mass = Mass
+table.column.Diameter = Diameter
+table.column.Sides = Sides
+table.column.LineCount = Line Count
+table.column.LineLength = Line Length
+table.column.LineMaterial = Line Material
+
 
diff --git a/core/resources/l10n/messages_cs.properties b/core/resources/l10n/messages_cs.properties
new file mode 100644 (file)
index 0000000..c8a913d
--- /dev/null
@@ -0,0 +1,1623 @@
+#
+# Czech base translation file
+#
+# Should you need to add new logical keys here is the proposed method
+#
+# className.ComponentType.componentName
+#
+#
+# Text tokens within braces should not be translated, e.g.
+#    "The file '{filename}' exists."
+# They are pieces that are inserted dynamically.
+#
+
+
+! Set to the name of the current translation file (used for debugging purposes)
+debug.currentFile = messages_cs.properties
+
+! RocketActions
+RocketActions.checkbox.Donotaskmeagain = Prí\u0161te se me neptejte
+RocketActions.lbl.Youcanchangedefop = Mu\u017Eete zmenit výchozí operaci v nastavení.
+RocketActions.showConfirmDialog.lbl1 = Chcete smazat oznacenou simulaci?
+RocketActions.showConfirmDialog.lbl2 = <html><i>Tuto operaci nelze vzít zpet.</i>
+RocketActions.showConfirmDialog.title = Sma\u017E simulace
+RocketActions.DelCompAct.Delete = Sma\u017E
+RocketActions.DelCompAct.ttip.Delete = Sma\u017E oznacenou komponentu.
+RocketActions.DelSimuAct.Delete = Sma\u017E
+RocketActions.DelSimuAct.ttip.Delete = Sma\u017E oznacenou simulaci.
+RocketActions.DelAct.Delete = Sma\u017E
+RocketActions.DelAct.ttip.Delete = Sma\u017E vyznacenou komponentu nebo simulaci.
+RocketActions.CutAction.Cut = Vyjmout
+RocketActions.CutAction.ttip.Cut = Vyjmi tuto komponentu nebo simulaci do schránky a odeber z návrhu
+RocketActions.CopyAct.Copy = Copy
+RocketActions.CopyAct.ttip.Copy = Zkopiruj tuto komponentu (a subkomponenty) do schránky.
+RocketActions.PasteAct.Paste = Paste
+RocketActions.PasteAct.ttip.Paste = Paste the component or simulation on the clipboard to the design.
+RocketActions.EditAct.Edit = Edit
+RocketActions.EditAct.ttip.Edit = Edituj vybranou komponentu.
+RocketActions.NewStageAct.Newstage = Nový stupen
+RocketActions.NewStageAct.ttip.Newstage = Pridej nový stupen rakety.
+RocketActions.ActBoosterstage = Urychlovací stupen
+RocketActions.MoveUpAct.Moveup = Presun nahoru
+RocketActions.MoveUpAct.ttip.Moveup = Presun tento stupen smerem nahoru.
+RocketActions.MoveDownAct.Movedown = Presun dolu
+RocketActions.MoveDownAct.ttip.Movedown = Presun tuto komponentu smerem dolu.
+
+! RocketPanel
+RocketPanel.FigTypeAct.Sideview = Pohled ze strany
+RocketPanel.FigTypeAct.ttip.Sideview = Pohled ze strany
+RocketPanel.FigTypeAct.Backview = Zpetný pohled
+RocketPanel.FigTypeAct.ttip.Backview = Zadní pohled 
+RocketPanel.FigViewAct.2D = 2D Pohled
+RocketPanel.FigViewAct.ttip.2D = 2D Pohled
+RocketPanel.FigViewAct.3D = 3D Pohled
+RocketPanel.FigViewAct.ttip.3D = 3D Pohled
+RocketPanel.lbl.Motorcfg = Nastavení motoru:
+RocketPanel.lbl.infoMessage = <html>Stiskni k oznacení &nbsp;&nbsp; Shift+stisknutí my\u0161i k oznacení ostatních &nbsp;&nbsp; Dvojklik my\u0161i k editování k editování &nbsp;&nbsp; Kliknout a táhnout k presunu
+
+
+! BasicFrame
+BasicFrame.SimpleFileFilter1 = V\u0161echny návrhy raket (*.ork; *.rkt)
+BasicFrame.SimpleFileFilter2 = Návrhy OpenRocket (*.ork)
+BasicFrame.SimpleFileFilter3 = Návrhy RockSim (*.rkt)
+BasicFrame.tab.Rocketdesign = Návrh rakety
+BasicFrame.tab.Flightsim = Letová simulace
+BasicFrame.title.Addnewcomp = Pridej novou komponentu
+BasicFrame.dlg.lbl1 = Návrh '
+BasicFrame.dlg.lbl2 = ' nebyl ulo\u017Een.
+BasicFrame.dlg.lbl3 = Chcete ho ulo\u017Eit?
+BasicFrame.dlg.title = Návrh není ulo\u017Een
+BasicFrame.StageName.Sustainer = Udr\u017Eet
+BasicFrame.WarningDialog.txt1 = Následující problémy byly zaznamenány behem otevírání.
+BasicFrame.WarningDialog.txt2 = Nekteré prvky nebyly správne nahrány.
+BasicFrame.WarningDialog.title = Varování behem otevírání souboru
+
+
+! General error messages used in multiple contexts
+error.fileExists.title = Soubor existuje
+error.fileExists.desc = Soubor '{filename}' existuje.  Preejete si ho prepsat?
+
+error.writing.title = Chyba zápisu do souboru
+error.writing.desc = Chyba nastala behem zapisování do souboru:
+
+
+! Labels used in buttons of dialog windows
+# TODO: Rename these to "btn.xxx"
+button.ok = OK
+button.cancel = Zru\u0161it
+button.close = Zavrít
+
+! Common labels used in buttons of dialog windows
+dlg.but.ok = OK
+dlg.but.cancel = Zru\u0161it
+dlg.but.close = Zavrít
+
+
+! General file type names
+filetypes.pdf = Soubory PDF
+
+
+! About Dialog
+AboutDialog.lbl.version = Version
+! The texts below provide additional credits for the translation maintainer
+! - In AboutDialog.lbl.translation replace "English" with the current language.
+! - AboutDialog.lbl.translator is the translator / group name (may be empty)
+! - AboutDialog.lbl.translatorWebsite is a URL to the translator / group (may be empty)
+! - AboutDialog.lbl.translatorIcon is the file name of an icon under pix/translators/ (may be empty)
+AboutDialog.lbl.translation = Do ce\u0161tiny prelo\u017Eil:
+AboutDialog.lbl.translator = Vladimír Beran
+AboutDialog.lbl.translatorWebsite = 
+AboutDialog.lbl.translatorIcon =  
+
+
+! Print dialog
+PrintDialog.title = Vytisknout nebo  exportovat
+PrintDialog.but.previewAndPrint = Náhled & Tisk
+PrintDialog.checkbox.showByStage = Uka\u017E na scéne
+PrintDialog.lbl.selectElements = Zvolte polo\u017Eky k pridání:
+printdlg.but.saveaspdf = Ulo\u017E jako PDF
+printdlg.but.preview = Náhled
+printdlg.but.settings = Nastavení
+PrintDialog.error.preview.title = Nemohu otevrít náhled
+PrintDialog.error.preview.desc1 = Nemohu otevrít PDF Náhled.
+PrintDialog.error.preview.desc2 = Prosím pou\u017Eijte volbu "Ulo\u017Eit jako PDF".
+
+
+!PrintSettingsDialog
+PrintSettingsDialog.title = Nastavení tisku
+PrintSettingsDialog.lbl.Templatefillcolor = \u0160ablona - barva výplne:
+PrintSettingsDialog.lbl.Templatebordercolor = \u0160ablona - barva okraju:
+PrintSettingsDialog.lbl.Papersize = Velikost papíru:
+PrintSettingsDialog.lbl.Paperorientation = Orientace stránky:
+PrintSettingsDialog.but.Reset = Reset
+PrintSettingsDialog.but.Close = Zavrít
+
+
+! Bug Report dialog
+bugreport.dlg.title = Hlá\u0161ení chyb
+bugreport.dlg.but.Sendbugreport = Po\u0161li hlá\u0161ení chyb
+bugreport.dlg.but.Sendbugreport.Ttip = Automaticky posílat hlá\u0161ení o chybách vývojárum OpenRocket.
+bugreport.dlg.successmsg1 = Hlá\u0161ení o chybe bylo úspe\u0161ne odesláno.
+bugreport.dlg.successmsg2 = Dekujeme, \u017Ee  pomáháte vylep\u0161ovat OpenRocket!
+bugreport.dlg.successmsg3 = Hlá\u0161ení o chybe
+bugreport.dlg.connectedInternet = <html>Pokud jste pripojeni k internetu stací kliknout na tlacítko <em>Po\u0161li hlá\u0161ení o chybe</em>.
+bugreport.dlg.otherwise = jinak po\u0161lete následující text na adresu:
+bugreport.lbl.Theinformation = Tato informace mu\u017Ee být zahrnuta do verejného hlá\u0161ení chyb. Dávejte pozor, aby neobsahovala duverné informace které si neprejete zverejnit.
+bugreport.dlg.failedmsg1 = OpenRocket není schopen poslat hlá\u0161ení o chybe:
+bugreport.dlg.failedmsg2 = Prosím po\u0161lete hlá\u0161ní rucne do:
+bugreport.dlg.failedmsg3 = Chyba behem odesílání hlá\u0161ení
+bugreport.reportDialog.txt = <html><b>Mu\u017Eete nahlásit chyby v programu OpenRocket vyplnením a odesláním formuláre.</b><br>Mu\u017Eete také nahlásit chyby na stránce projektu.
+bugreport.reportDialog.txt2 = <html><b>Prosím podejte krátkou zprávu o tom co jste delali kdy\u017E chyba nastala.</b>
+bugreport.dlg.provideDescription = Prosím poskytnete nejprve hlá\u0161ení o chybe.
+bugreport.dlg.provideDescription.title = Chybí popis chyby
+
+
+! Debug log dialog
+debuglogdlg.but.clear = Sma\u017E
+debuglogdlg.OpenRocketdebuglog = Hlá\u0161ení o chybe v OpenRocket
+debuglogdlg.Displayloglines = Zobraz rádky z chybového hlá\u0161ení:
+debuglogdlg.Follow = Následuj
+debuglogdlg.col.Time = Cas
+debuglogdlg.col.Level = Úroven
+debuglogdlg.col.Location = Umístení
+debuglogdlg.col.Message = Zpráva
+debuglogdlg.lbl.Loglinenbr = Záznam císla rádky:
+debuglogdlg.lbl.Time = Cas:
+debuglogdlg.lbl.Level = Úroven:
+debuglogdlg.lbl.Location = Umístení:
+debuglogdlg.lbl.Logmessage = Zpráva záznamu:
+debuglogdlg.lbl.Stacktrace = Tracování zásobníku:
+
+
+! Edit Motor configuration dialog
+edtmotorconfdlg.but.removemotor = Odeber motor
+edtmotorconfdlg.but.Selectmotor = Vyber motor
+edtmotorconfdlg.but.Removeconfiguration = Odeber nastavení
+edtmotorconfdlg.but.Newconfiguration = Nové nastavení
+edtmotorconfdlg.lbl.Motormounts = <html><b>Pripojení motoru:</b>
+edtmotorconfdlg.title.Editmotorconf = Úprava nastavení motoru
+edtmotorconfdlg.selectcomp = <html>Vyber ke kterým komponentám se má motor pripojit:
+edtmotorconfdlg.lbl.Motorconfig = <html><b>Nastavení motoru:</b>
+edtmotorconfdlg.lbl.Configname = Jméno nastavení:
+edtmotorconfdlg.lbl.Leavenamedefault = Nechej prázdné polícko jako výchozí hodnotu.
+
+! Example design dialog
+exdesigndlg.but.open = Otevri
+exdesigndlg.lbl.Selectexample = Vyber ukázkový návrh k otevrení:
+exdesigndlg.lbl.Openexampledesign = Otevri ukázkový návrh
+exdesigndlg.lbl.Exampledesignsnotfound = Ukázkový návrch nebyl nalezen.
+exdesigndlg.lbl.Examplesnotfound = Ukázky nebyly nalezeny
+
+
+! Material edit panel
+matedtpan.but.new = Nový
+matedtpan.but.edit = Edituj
+matedtpan.but.delete = Sma\u017E
+matedtpan.but.revertall = Vrátit v\u0161e zpet
+matedtpan.col.Material = Materiál
+matedtpan.col.Type = Typ
+matedtpan.col.Density = Hustota
+matedtpan.col.but.ttip.New = Pridej nový materiál
+matedtpan.title.Addcustmaterial = Pridej vlastní materiál
+matedtpan.but.ttip.edit = Edituj existující materiál
+matedtpan.title.Editmaterial = Edituj materiál
+matedtpan.title2.Editmaterial = Vestavené materiály nemohou být modifikovány.
+matedtpan.but.ttip.delete = Sma\u017E u\u017Eivatelem definované materiály
+matedtpan.but.ttip.revertall = Sma\u017E v\u0161echny u\u017Eivatelem definované materiály
+matedtpan.title.Deletealluser-defined = Smazat v\u0161echny u\u017Eivatelem definované materiály?
+matedtpan.title.Revertall = Vrátit v\u0161e zpet?
+matedtpan.lbl.edtmaterials = Editování materiálu neovlivní existující návrhy raket.
+
+!MaterialModel
+MaterialModel.title.Material = Materiál
+MaterialModel.title.Defcustmat = Definuj vlastní materiál
+
+
+! Preference dialog
+pref.dlg.but.add = Pridej
+pref.dlg.but.reset = Reset
+pref.dlg.but.checknow = Zkontroluj nyní
+pref.dlg.but.defaultmetric = Výchozí metrická soustava
+pref.dlg.but.defaultimperial = Výchozí imperiální soustava
+pref.dlg.title.Preferences = Nastavení
+pref.dlg.tab.Units = Jednotky
+pref.dlg.tab.Defaultunits = Výchozí jednotky
+pref.dlg.tab.Materials = Materiály
+pref.dlg.tab.Custommaterials = Vlastní materiály
+pref.dlg.tab.Options = Vlastnosti
+pref.dlg.tab.Miscellaneousoptions = Ruzné vlastnosti
+pref.dlg.lbl.Positiontoinsert = Pozice kam pridat nové komponenty tela:
+pref.dlg.lbl.Confirmdeletion = Potvrdte smazání simulace:
+pref.dlg.lbl.User-definedthrust = U\u017Eivatelem definované prubehy výkonu:
+pref.dlg.Allthrustcurvefiles = Soubory v\u0161ech výkonových prubehu (*.eng; *.rse; *.zip; directories)
+pref.dlg.RASPfiles = RASPové soubory motoru (*.eng)
+pref.dlg.RockSimfiles = RockSim sobory motoru (*.rse)
+pref.dlg.ZIParchives = ZIP archivy (*.zip)
+pref.dlg.checkbox.Checkupdates = Zkontrolujte softwarové aktualizace pri startu
+pref.dlg.ttip.Checkupdatesnow = Zkontrolujte softwarové aktualizace nyní
+pref.dlg.lbl.Selectprefunits = Vyberte preferované jednotky:
+pref.dlg.lbl.Rocketdimensions = Rozmery rakety:
+pref.dlg.lbl.Linedensity = linie hustoty:
+pref.dlg.lbl.Motordimensions = Rozmery motoru:
+pref.dlg.lbl.Surfacedensity = Povrchová hustota:
+pref.dlg.lbl.Distance = Vzdálenost:
+pref.dlg.lbl.Bulkdensity = Objemová hustota:
+pref.dlg.lbl.Velocity = Rychlost:
+pref.dlg.lbl.Surfaceroughness = Hrubost povrchu:
+pref.dlg.lbl.Acceleration = Zrychlení:
+pref.dlg.lbl.Area = Oblast:
+pref.dlg.lbl.Mass = Hmostnost:
+pref.dlg.lbl.Angle = Úhel:
+pref.dlg.lbl.Force = Síla:
+pref.dlg.lbl.Rollrate = Míra rotace:
+pref.dlg.lbl.Totalimpulse = Celkový impuls:
+pref.dlg.lbl.Temperature = Teplota:
+pref.dlg.lbl.Momentofinertia = Moment setrvacnosti:
+pref.dlg.lbl.Pressure = Tlak:
+pref.dlg.lbl.Stability = Stabilita:
+pref.dlg.lbl.FlightTime = Letový cas:
+pref.dlg.lbl.effect1 = Projeví se pri dal\u0161ím otevrení okna.
+pref.dlg.lbl.Checkingupdates = Kontrola aktualizací...
+pref.dlg.lbl.msg1 = Nastala chyba behem komunikace ze serverem.
+pref.dlg.lbl.msg2 = Nemohu získat informace o aktualizacích
+pref.dlg.lbl.msg3 = Je spu\u0161tena nejnovej\u0161í verze programu OpenRocket.
+pref.dlg.lbl.msg4 = Nejsou dostupné \u017Eádné aktualizace
+pref.dlg.PrefChoiseSelector1 = Poka\u017Edé se ptej
+pref.dlg.PrefChoiseSelector2 = Vlo\u017E doprostred
+pref.dlg.PrefChoiseSelector3 = Pridej na konec
+pref.dlg.PrefBooleanSelector1 = Sma\u017E
+pref.dlg.PrefBooleanSelector2 = Potvrd
+pref.dlg.Add = Pridej
+pref.dlg.DescriptionArea.Adddirectories = Pridej adresáre, soubory RASP motor  (*.eng), RockSim engine soubory (*.rse) nebo ZIP archiv oddelený oddelovacem (;) k nahrání externích výkonových prubehu. Zmeny se projeví po restaru programu OpenRocket.
+
+PreferencesDialog.lbl.language = Jazyk rohranní:
+PreferencesDialog.languages.default = Výchozí
+PreferencesDialog.lbl.languageEffect = Jazyk se zmení pri dal\u0161ím spu\u0161tení programu OpenRocket.
+
+! Simulation edit dialog
+simedtdlg.but.runsimulation = Simulace be\u017Eí
+simedtdlg.but.resettodefault = Reset do výchozí hodnoty
+simedtdlg.but.add = Pridej
+simedtdlg.but.remove = Odeber
+simedtdlg.title.Editsim = Uprav simulaci
+simedtdlg.lbl.Simname = Jméno simulace:
+simedtdlg.tab.Launchcond = Startovací podmínky
+simedtdlg.tab.Simopt = Parametry simulace
+simedtdlg.tab.Plotdata = Zobraz data
+simedtdlg.tab.Exportdata = Exportuj data
+simedtdlg.lbl.Motorcfg = Nastavení motoru:
+simedtdlg.lbl.ttip.Motorcfg = Nastav konfiguraci motoru k pouziti.
+simedtdlg.combo.ttip.motorconf = Nastav konfiguraci motoru k pouziti.
+simedtdlg.lbl.Wind = Vítr
+simedtdlg.lbl.Averwindspeed = Prumerná rychlost vetru:
+simedtdlg.lbl.ttip.Averwindspeed = Prumerná rychlost vetru vzhledem k zemi.
+simedtdlg.lbl.Stddeviation = Standartní odchylka:
+simedtdlg.lbl.ttip.Stddeviation = <html>Standartní odchylka rychlosti vetru.<br>Rychlost vetru je v rámci dvojnásobku standartní odchylky od prumeru po 95% casu.
+simedtdlg.lbl.Turbulenceintensity = Intenzita turbulencí:
+simedtdlg.lbl.ttip.Turbulenceintensity1 = <html>Intenzita turbulencí je standartní odchylka delená prumerem rychlosti vetru.<br>
+simedtdlg.lbl.ttip.Turbulenceintensity2 = Typické hodnoty od 
+simedtdlg.lbl.ttip.Turbulenceintensity3 = do
+simedtdlg.border.Atmoscond = Atmosférické podmínky
+simedtdlg.checkbox.InterStdAtmosphere = Pou\u017Eij mezinárodní standardizovanou atmosféru
+simedtdlg.checkbox.ttip.InterStdAtmosphere1 = <html>Oznac k pou\u017Eití mezinárodní model standartní atmodféry.<br>Tento model má teplotu
+simedtdlg.checkbox.ttip.InterStdAtmosphere2 = a tlak
+simedtdlg.checkbox.ttip.InterStdAtmosphere3 = na úrovni morsé hladiny.
+simedtdlg.lbl.Temperature = Teplota:
+simedtdlg.lbl.ttip.Temperature = Teplota na startovní plo\u0161e.
+simedtdlg.lbl.Pressure = Tlak:
+simedtdlg.lbl.ttip.Pressure = Atmosférický tlak na startovní plo\u0161e.
+simedtdlg.lbl.Launchsite = Místo startu
+simedtdlg.lbl.Latitude = Zemepisná \u0161írka:
+simedtdlg.lbl.ttip.Latitude = <html>Zemepisná \u0161írka ovlivnuje gravitacní sílu zeme.<br>Pozitivní hodnoty jsou na Severní polokouli, negativní na ji\u017Ení polokouli.
+
+simedtdlg.lbl.Longitude = Zemepisná délka:
+simedtdlg.lbl.ttip.Longitude = <html>Vy\u017Eadováno pro predpoved pocasí a letový model.
+
+simedtdlg.lbl.Altitude = Nadmorská vý\u0161ka:
+simedtdlg.lbl.ttip.Altitude = <html>Startovní nadmorská vý\u0161ka na úrovni hladiny more.<br>Toto ovlivnuje pozici rakety v atmosférickém modelu.
+simedtdlg.border.Launchrod = Startovní pozice
+simedtdlg.lbl.Length = Délka:
+simedtdlg.lbl.ttip.Length = Délka startovní pozice.
+simedtdlg.lbl.Angle = Úhel:
+simedtdlg.lbl.ttip.Angle = Úhel startovní pozice od vertikály.
+simedtdlg.lbl.Direction = Smer:
+simedtdlg.lbl.ttip.Direction1 = <html>Smer vypu\u0161tení vzhledem k vetru.<br>
+simedtdlg.lbl.ttip.Direction2 =  = Proti vetru,
+simedtdlg.lbl.ttip.Direction3 = = po vetru.
+simedtdlg.border.Simopt = Vlastnosti simulátoru
+simedtdlg.lbl.Calcmethod = Výpocetní metoda:
+simedtdlg.lbl.ttip.Calcmethod = <html>Roz\u0161írená Barrowmanova metoda pocítá aerodynamické síly vzhledem <br>to Roz\u0161írené Barrowmanovi rovnice pojmou více podmínek.
+simedtdlg.lbl.ExtBarrowman = Roz\u0161írený Barrowman
+simedtdlg.lbl.Simmethod = Simulacní metoda:
+simedtdlg.lbl.ttip.Simmethod1 = <html>\u0160est stupnu volnosti simulátoru umo\u017Enuje rakete celkovou svobodu behem letu.<br>
+simedtdlg.lbl.ttip.Simmethod2 = Integrace je pocítána za pomoci 4<sup>th</sup> stupnové Runge-Kuttoovi numerické integrace.
+simedtdlg.lbl.GeodeticMethod = Geodetické výpocty:
+simedtdlg.lbl.ttip.GeodeticMethodTip = Pripraven vypocítat povrchové koordináty.  TO také aktivuje výpocet koriolisovy síly.
+simedtdlg.lbl.Timestep = Casový krok:
+simedtdlg.lbl.ttip.Timestep1 = <html>Cas mezi simulacními kroky.<br>Men\u0161í dobu kroku znamená pomalej\u0161í výpocet, ale vy\u0161\u0161í presnost výpoctu.<br>
+simedtdlg.lbl.ttip.Timestep2 = Ctyr stupnová simulace je pomerne presná s délkou kroku
+simedtdlg.but.ttip.resettodefault = Resetuj délku kroku na tuto výchozí hodnotu (
+simedtdlg.border.Simlist = Dal\u0161í zpracování simulace
+simedtdlg.txt.longA1 = <html><i>Dal\u0161í zpacování simulace</i> je pokrocilá technika, která dovoluje pou\u017Eít u\u017Eivatelský kód k zpracování dat ze simulace a k interakci ze simulací.  
+simedtdlg.txt.longA2 = Pro detailní popis jak psát skripty na dal\u0161í zpracování simulace otevrete technickou dokumentaci k programu OpenRocket.
+simedtdlg.lbl.Curlist = Aktivní skript na dal\u0161í zpracování simulace:
+simedtdlg.lbl.Addsimlist = Pridej skript na dal\u0161í zpracování simulace
+simedtdlg.lbl.Noflightdata = Nejsou dostupná letová data.
+simedtdlg.lbl.runsimfirst = Prosím jako první spustte simulaci.
+simedtdlg.chart.Simflight = Letová simulace
+simedtdlg.dlg.Simres = Výsledky simulace
+simedtdlg.IntensityDesc.None = \u017Dádné
+simedtdlg.IntensityDesc.Verylow = Velmi nízké
+simedtdlg.IntensityDesc.Low = Nízké
+simedtdlg.IntensityDesc.Medium = Strední
+simedtdlg.IntensityDesc.High = Velké
+simedtdlg.IntensityDesc.Veryhigh = Velmi velké
+simedtdlg.IntensityDesc.Extreme = Extrémní
+
+GeodeticComputationStrategy.flat.name = Rovná Zeme
+GeodeticComputationStrategy.flat.desc = Vykonej výpocet s aproximací ploché Zeme. Ten je dostatecnou presnost pro nízkový\u0161kové lety.
+GeodeticComputationStrategy.spherical.name = Sférická aproximace
+GeodeticComputationStrategy.spherical.desc = <html>Vykonej geodetický výpocet predpokládající kulovou Zemi.<br>Ten má dostatecnou presnost pro v\u0161echny úcely.
+GeodeticComputationStrategy.wgs84.name = WGS84 ellipsa
+GeodeticComputationStrategy.wgs84.desc = <html>Proved geodetický výpocet na WGS84 elipse za pou\u017Eití Vincentovy metody.<br>Pomalé a nedostatecné ve vet\u0161ine prípadu.
+
+
+
+
+! Simulation Panel
+simpanel.but.newsimulation = Nová simulace
+simpanel.but.editsimulation = Edituj  simulaci
+simpanel.but.runsimulations = Spust simulaci
+simpanel.but.deletesimulations = Sma\u017E simulaci
+simpanel.but.plotexport = Vykresli / exportuj
+simpanel.but.ttip.newsimulation = Pridej novou simulaci
+simpanel.but.ttip.editsim = Edituj oznacenou simulaci
+simpanel.but.ttip.runsimu = Znovu spust oznacenou simulaci
+simpanel.but.ttip.deletesim = Sma\u017E oznacenou simulaci
+simpanel.checkbox.donotask = Neptejte se me znovu
+simpanel.lbl.defpref = Mu\u017Eete zmenit výchozí cinost v nastavení.
+simpanel.dlg.lbl.DeleteSim1 = Smazat oznacenou simulaci?
+simpanel.dlg.lbl.DeleteSim2 = <html><i>Tato operace nemu\u017Ee být vzata zpet.</i>
+simpanel.dlg.lbl.DeleteSim3 = Sma\u017E simulaci
+simpanel.col.Name = Jméno
+simpanel.col.Motors = Motory
+simpanel.col.Velocityoffrod = Rychlost otácení
+simpanel.col.Velocityatdeploy = Rychlost v nasazení
+simpanel.col.Apogee = Vrchol
+simpanel.col.Maxvelocity = Max. rychlost
+simpanel.col.Maxacceleration = Max. zrychlení
+simpanel.col.Timetoapogee = Cas do dosa\u017Eení vrcholu
+simpanel.col.Flighttime = Letový cas
+simpanel.col.Groundhitvelocity = Rychlost pri dopadu na zem
+
+! SimulationRunDialog
+SimuRunDlg.title.RunSim = Simulace be\u017Eí...
+SimuRunDlg.lbl.Running = Be\u017Eí ...
+SimuRunDlg.lbl.Simutime = Doba simulace:
+SimuRunDlg.lbl.Altitude = Vý\u0161ka:
+SimuRunDlg.lbl.Velocity = Rychlost:
+SimuRunDlg.msg.Unabletosim = Nemo\u017Enost simulovat:
+SimuRunDlg.msg.errorOccurred = Chyba nastala behem simulace:
+SimuRunDlg.msg.AnException1 = Vyjímka nastala behem simulace:
+SimuRunDlg.msg.AnException2 = Prosím oznamte toto jako chybu zároven s detaily ní\u017Ee.
+SimuRunDlg.msg.AssertionError1 = Chyba ve výpoctu nastala behem simulace.
+SimuRunDlg.msg.AssertionError2 = Prosím oznamte toto jako chybu zároven s detaily ní\u017Ee.
+SimuRunDlg.msg.unknownerror1 = Neznámá chyba se vyskytla behem simulace.
+SimuRunDlg.msg.unknownerror2 = Program mu\u017Ee být nestabilní mel by-jste ulo\u017Eit v\u0161echny va\u0161e návrhy a okam\u017Eite restartovat OpenRocket !
+
+
+RK4SimulationStepper.error.valuesTooLarge = Hodnoty simulace prekrocily limity. Zkuste nastavit krat\u0161í délku kroku.
+
+
+! SimulationExportPanel
+SimExpPan.desc = Soubory s cárkovým oddelovacem (*.csv)
+SimExpPan.border.Vartoexport = Promenné k exportu
+SimExpPan.but.Selectall = Oznac v\u0161e
+SimExpPan.but.Selectnone = Nic neoznacuj
+SimExpPan.border.Fieldsep = Oddelovac prvku
+SimExpPan.lbl.Fieldsepstr = Retezec slou\u017Eící k oddelování prvku:
+SimExpPan.lbl.longA1 = <html>Retezec slou\u017Eící k oddelení prvku v exportovaném souboru.<br>
+SimExpPan.lbl.longA2 = Pou\u017Eij ',' pro soubory s hodnotami oddelenými carkou (CSV) soubor.
+SimExpPan.checkbox.Includesimudesc = Vlo\u017E popis simulace
+SimExpPan.checkbox.ttip.Includesimudesc = Vlo\u017E komentár na zacátek souboru popisujícího simulaci.
+SimExpPan.border.Comments = Komentáre
+SimExpPan.checkbox.Includefielddesc = Obsahuje popis prvku
+SimExpPan.checkbox.ttip.Includefielddesc = Obsahuje komentár s popisem exportovaných hodnot.
+SimExpPan.checkbox.Incflightevents = Obsahuje letové události
+SimExpPan.checkbox.ttip.Incflightevents = Obsahuje komentár pro ka\u017Edý letový parametr.
+SimExpPan.lbl.Commentchar = Uvozující retezec komentáre:
+SimExpPan.lbl.ttip.Commentchar = Tyto znaky oznacují komentár.
+SimExpPan.but.Exporttofile = Exportuj do souboru...
+SimExpPan.Fileexists.desc1 = Soubor \"
+SimExpPan.Fileexists.desc2 = \" existuje.  Chcete ho prepsat?
+SimExpPan.Fileexists.title = Soubor existuje
+SimExpPan.ExportingVar.desc1 = Exportuji  1 promennou od
+SimExpPan.ExportingVar.desc2 = Exportuji 
+SimExpPan.ExportingVar.desc3 = promenné od
+SimExpPan.Col.Variable = Promenná
+SimExpPan.Col.Unit = Jednoty
+
+
+CsvOptionPanel.separator.space = Mezerník
+CsvOptionPanel.separator.tab = Tabulátor
+
+
+
+! MotorPlot
+MotorPlot.title.Motorplot = Graf motoru
+MotorPlot.but.Select = Vyber
+MotorPlot.Chart.Motorthrustcurve = Výkonová krivka motoru
+MotorPlot.Chart.Time = Cas / s
+MotorPlot.Chart.Thrust = Výkon / N
+MotorPlot.txt.Designation = Oznacení:
+MotorPlot.txt.Manufacturer = Výrobce:
+MotorPlot.txt.Type = Typ:
+MotorPlot.txt.Delays = Zpo\u017Eení:
+MotorPlot.txt.Comment = Komentár:\n
+
+
+
+! Simulation plot panel
+simplotpanel.lbl.Presetplotconf = Prednastavené parametry vykreslení grafu:
+simplotpanel.lbl.Xaxistype = Typ osy X:
+simplotpanel.lbl.Unit = Jednotky:
+simplotpanel.lbl.Yaxistypes = Typ osy Y:
+simplotpanel.lbl.Flightevents = Letové události:
+simplotpanel.but.All = V\u0161e
+simplotpanel.but.None = Nic
+simplotpanel.but.NewYaxisplottype = Nový typ osy Y
+simplotpanel.but.Plotflight = Letový graf
+simplotpanel.lbl.Axis = Osy:
+simplotpanel.but.ttip.Removethisplot = Odeber tento graf
+simplotpanel.Desc = Data budou vykreslena v casovém poradí i kdy\u017E osa x nebude nastavena jako cas.
+simplotpanel.OptionPane.lbl1 = Maximálne 15 grafu je povoleno. 
+simplotpanel.OptionPane.lbl2 = Nemohu pridat graf
+simplotpanel.AUTO_NAME = Automaticky
+simplotpanel.LEFT_NAME = Vlevo 
+simplotpanel.RIGHT_NAME = Vpravo
+simplotpanel.CUSTOM = Vlastní
+SimulationPlotPanel.error.noPlotSelected = Prosím pridejte jednu nebo více promených v grafu na osu Y.
+SimulationPlotPanel.error.noPlotSelected.title = Nic k vykreslení
+
+
+! Component add buttons
+compaddbuttons.Bodycompandfinsets = Komponenty tela a stabilizátory
+compaddbuttons.Nosecone = Prídový ku\u017Eel
+compaddbuttons.Bodytube = Trubka tela
+compaddbuttons.Transition = Prechod trupu
+compaddbuttons.Trapezoidal = Trapézoidní
+compaddbuttons.Elliptical = Eliptycký
+compaddbuttons.Freeform = Volný tvar
+compaddbuttons.Launchlug = Vypou\u0161tecí oko
+compaddbuttons.Innercomponent = Vnitrní komponenty
+compaddbuttons.Innertube = Vnitrní trubka
+compaddbuttons.Coupler = Prípojka
+compaddbuttons.Centeringring = Stred\nring
+compaddbuttons.Bulkhead = Prepá\u017Eka
+compaddbuttons.Engineblock = Motor\nblock
+compaddbuttons.Massobjects = Záva\u017Eí
+compaddbuttons.Parachute = Padák
+compaddbuttons.Streamer = Stuha
+compaddbuttons.Shockcord = Poutací \u0161nura
+compaddbuttons.Masscomponent = Hmotnost\ncomponent
+compaddbuttons.Donotaskmeagain = Neptejte me me znovu
+compaddbuttons.Selectcomppos = Oznac pozici komponenty
+compaddbuttons.lbl.Youcanchange = Mu\u017Eete zmenit výchozí operace v zálo\u017Ece mo\u017Enosti.
+compaddbuttons.lbl.insertcomp = Vlo\u017Eit komponentu za soucasnou nebo poslední komponentu ?
+compaddbuttons.askPosition.Inserthere = Vlo\u017E zde
+compaddbuttons.askPosition.Addtotheend = Pridej na konec
+compaddbuttons.askPosition.Cancel = Zru\u0161it
+
+! Component Analysis Dialog
+componentanalysisdlg.componentanalysis = Analýza soucástky
+componentanalysisdlg.lbl.winddir = Smer vetru:
+componentanalysisdlg.TitledBorder.warnings = Varování:
+componentanalysisdlg.ToggleBut.worst = Nejhor\u0161í
+componentanalysisdlg.lbl.angleofattack = Úhel nábehu:
+componentanalysisdlg.lbl.machnumber = Machovo císlo:
+componentanalysisdlg.lbl.rollrate = Rychlost otácení:
+componentanalysisdlg.lbl.activestages = Startovací rampa:
+componentanalysisdlg.lbl.motorconf = Nastavení motoru:
+componentanalysisdlg.TabStability.Col = Komponenta
+componentanalysisdlg.TabStability = Stabilita
+componentanalysisdlg.TabStability.ttip = Informace o stabilite
+componentanalysisdlg.dragTableModel.Col.Component = Komponenta
+componentanalysisdlg.dragTableModel.Col.Pressure = <html>Tlak C<sub>D</sub>
+componentanalysisdlg.dragTableModel.Col.Base = <html>Základní C<sub>D</sub>
+componentanalysisdlg.dragTableModel.Col.friction = <html>Trení C<sub>D</sub>
+componentanalysisdlg.dragTableModel.Col.total = <html>Celkem C<sub>D</sub>
+componentanalysisdlg.dragTabchar = Vlastnosti trupu
+componentanalysisdlg.dragTabchar.ttip = Drag characteristics
+componentanalysisdlg.rollTableModel.Col.component = Komponenta
+componentanalysisdlg.rollTableModel.Col.rollforc = Otácecí koefficient
+componentanalysisdlg.rollTableModel.Col.rolldamp = Otácecí tlumící coefficient
+componentanalysisdlg.rollTableModel.Col.total = <html>Celkem C<sub>l</sub>
+componentanalysisdlg.rollTableModel = Otácecí dynamika
+componentanalysisdlg.rollTableModel.ttip = Otácecí dynamika
+componentanalysisdlg.println.closingmethod = Jméno uzavírací metody:
+componentanalysisdlg.println.settingnam = Nastavení NAN hodnot
+componentanalysisdlg.lbl.reflenght = Doporucená délka: 
+componentanalysisdlg.lbl.refarea = Doporucená plocha: 
+!componentanalysisdlg.But.close = Zavrít
+componentanalysisdlg.TabStability.Col.Component = Komponenta
+
+! Custom Material dialog
+custmatdlg.title.Custommaterial = Vlastní materiál
+custmatdlg.lbl.Materialname = Jméno materiálu: 
+custmatdlg.lbl.Materialtype = Typ materiálu:
+custmatdlg.lbl.Materialdensity = Hustota materiálu:
+custmatdlg.checkbox.Addmaterial = Pridej materiál do databáze
+
+
+! Ring Component Config
+ringcompcfg.OuterRadius = Vnej\u0161í rádius
+ringcompcfg.Automatic = Automaticky
+ringcompcfg.InnerRadius = Vnitrní rádius
+ringcompcfg.Thickness = Tloustka
+ringcompcfg.Length = Délka
+ringcompcfg.Positionrelativeto = Pozice vzhledem k:
+ringcompcfg.plus = plus
+ringcompcfg.PositionValue = Hodnota pozice
+ringcompcfg.Radialdistance = Radiální vzdálenost:
+ringcompcfg.Distancefrom = Vzdálenost od osy rakety
+ringcompcfg.Radialdirection = Radiální smer:
+ringcompcfg.radialdirectionfrom = Radiální vzdálenost od smeru osy
+ringcompcfg.but.Reset = Reset
+ringcompcfg.but.Resetcomponant = Resetuj komponentu od osy rakety
+ringcompcfg.EngineBlock.desc = <html>An <b>blok motoru</b> zastaví motor v pohybu vzad v motorové trubici.<br><br>Pokud se pridá motor vytvorí <b>telo</b> nebo <b>skrytou trubku tube</b> a oznací ji jako montá\u017E motoru v<em>Motoru</em> tab.
+ringcompcfg.note.desc = Poznámka: Vnitrní trubka nemá effekt na aerodynamiku motoru i kdy\u017E je umístena mimo telo rakety.
+
+
+! Body Tube Config
+BodyTubecfg.lbl.Bodytubelength = Délka tela rakety:
+BodyTubecfg.lbl.Outerdiameter = Vnej\u0161í prumer:
+BodyTubecfg.lbl.Innerdiameter = Vnitrní prumer:
+BodyTubecfg.lbl.Wallthickness = Tlou\u0161tka steny:
+BodyTubecfg.tab.General = Obecne
+BodyTubecfg.tab.Generalproperties = Obecné vlastnosti
+BodyTubecfg.tab.Motor = Motor
+BodyTubecfg.tab.Motormountconf = Konfigurace pripojení motoru
+BodyTubecfg.checkbox.Automatic = Automaticky
+BodyTubecfg.checkbox.Filled = Vyplnený
+
+! FinSetConfig
+FinSetConfig.tab.Fintabs = Stabilizátory
+FinSetConfig.tab.Through-the-wall = \u017Dlab mezi stenou a stabilizátory
+FinSetConfig.but.Converttofreeform = Konvertovat na volný tvar
+FinSetConfig.but.Converttofreeform.ttip = Konvertuj tyto stabilizátory na volno tvarové stabilizátory
+FinSetConfig.Convertfinset = Konvertuj stabilizátory
+FinSetConfig.but.Splitfins = Rozdel stabilizátory
+FinSetConfig.but.Splitfins.ttip = Rozdel stabiliátory na samostatné
+FinSetConfig.but.AutoCalc = Vypocti automaticky
+FinSetConfig.lbl.Through-the-wall  = \u017Dlab mezi stenou a stabilizátory:
+FinSetConfig.lbl.Tablength = Délka stabilizátoru:
+FinSetConfig.ttip.Tablength = Delka stabilizátoru.
+FinSetConfig.lbl.Tabheight = \u0160írka stabilizátoru:
+FinSetConfig.ttip.Tabheight = \u0160írka rozpetí mezi stabilizátory.
+FinSetConfig.lbl.Tabposition = Pozice stabilizátoru:
+FinSetConfig.ttip.Tabposition = Pozice stabilizátoru.
+FinSetConfig.lbl.relativeto = Vzhledem k
+
+!FinMarkingGuide
+FinMarkingGuide.lbl.Front = Prední strana
+
+! MotorDatabaseLoadingDialog
+MotorDbLoadDlg.title = Plnení motoru
+MotorDbLoadDlg.Loadingmotors = Plnení motoru...
+
+! RocketConfig
+RocketCfg.lbl.Designname = Jméno návrhu:
+RocketCfg.lbl.Designer = Návrhár:
+RocketCfg.lbl.Comments = Komentáre:
+RocketCfg.lbl.Revisionhistory = Prehled historie:
+RocketCfg.lbl.Material = Materiál:
+
+! ShockCordConfig
+ShockCordCfg.lbl.Shockcordlength = Délka poutací \u0161nury:
+
+! RocketComponentConfig
+RocketCompCfg.lbl.Componentname = Jméno komponenty:
+RocketCompCfg.ttip.Thecomponentname = Jméno komponenty.
+RocketCompCfg.tab.Override = Prepsat
+RocketCompCfg.tab.MassandCGoverride = Prepi\u0161 hmotnost a te\u017Ei\u0161te
+RocketCompCfg.tab.Figure = Obrázek
+RocketCompCfg.tab.Figstyleopt = Vlastnosti obrázku
+RocketCompCfg.tab.Comment = Komentár
+RocketCompCfg.tab.Specifyacomment = Upresnení komentáre komponenty
+RocketCompCfg.lbl.Mass = Hmotnost:
+RocketCompCfg.lbl.Componentmass = Hmotnost komponenty:
+RocketCompCfg.lbl.overriddento = (prepsáno na
+RocketCompCfg.lbl.overriddenby = (prepsáno 
+RocketCompCfg.lbl.Componentmaterial = Materiál komponentu:
+RocketCompCfg.lbl.Componentfinish = Povrchová úprava komponenty:
+RocketCompCfg.lbl.ttip.componentmaterialaffects = Materiál komponenty ovlivnuje váhu komponety.
+RocketCompCfg.combo.ttip.componentmaterialaffects = Materiál komponenty ovlivnuje váhu komponety.
+RocketCompCfg.lbl.longA1 = <html> Povrchová úprava komponenty ovlivnuje aerodynamiku komponenty.<br>
+RocketCompCfg.lbl.longA2 = Hodnota odpovídá prumerné hrubosti povrchu.
+RocketCompCfg.but.Setforall = Nastav pro v\u0161echny
+RocketCompCfg.but.ttip.Setforall = Nastav povrchovou úpravu pro v\u0161echny komponenty rakety.
+RocketCompCfg.lbl.Overridemassorcenter = Zmen hmotnost nebo te\u017Ei\u0161te 
+RocketCompCfg.checkbox.Overridemass = Zmen hmotnost:
+RocketCompCfg.checkbox.Overridecenterofgrav = Zmen te\u017Ei\u0161te:
+RocketCompCfg.checkbox.OverridemassandCG = Zmen hmotnost a te\u017Ei\u0161te v\u0161ech komponent
+RocketCompCfg.lbl.longB1 = <html> Zmena hmotnosti nezahrnuje motory.<br>
+RocketCompCfg.lbl.longB2 = Te\u017Ei\u0161te je mereno od predku
+RocketCompCfg.lbl.Commentsonthe = Komentár na
+RocketCompCfg.lbl.Figurestyle = Styl obrátku:
+RocketCompCfg.lbl.Componentcolor = Barva komponenty:
+RocketCompCfg.lbl.Choosecolor = Vyber barvu
+RocketCompCfg.checkbox.Usedefaultcolor = Pou\u017Eij výchozí barvu
+RocketCompCfg.lbl.Complinestyle = Styl cáry:
+RocketCompCfg.but.Saveasdefstyle = Ulo\u017E jako výchozí styl
+RocketCompCfg.lbl.Diameter = Prumer:
+RocketCompCfg.lbl.Length = Délka:
+RocketCompCfg.lbl.Thickness = Tlou\u0161tka:
+RocketCompCfg.checkbox.Endcapped = Záslepka
+RocketCompCfg.ttip.Endcapped = Zdali je konec ramene zaslepen.
+RocketCompCfg.title.Noseconeshoulder = Dr\u017Eák nosního dílu
+RocketCompCfg.title.Aftshoulder = Dr\u017Eák zádi
+RocketCompCfg.border.Foreshoulder = Dr\u017Eák prídi 
+!RocketCompCfg.lbl.Length = Délka:
+
+! BulkheadConfig
+BulkheadCfg.tab.Diameter = Prumer:
+BulkheadCfg.tab.Thickness = Tlou\u0161tka:
+BulkheadCfg.tab.General = Obecné
+BulkheadCfg.tab.Generalproperties = Obecné vlastnosti
+
+!CenteringRingConfig
+CenteringRingCfg.tab.Outerdiam = Vnej\u0161í prumer:
+CenteringRingCfg.tab.Innerdiam = Vnitrní prumer:
+CenteringRingCfg.tab.Thickness = Tlou\u0161tka:
+CenteringRingCfg.tab.General = Obecné
+CenteringRingCfg.tab.Generalproperties = Obecné vlastnosti
+
+!ComponentConfigDialog
+ComponentCfgDlg.configuration = konfigurace
+ComponentCfgDlg.configuration1 =
+ComponentCfgDlg.Modify = Uprav
+
+!StageConfig
+StageConfig.tab.Separation = Oddelení
+StageConfig.tab.Separation.ttip = Vlastnosti oddelení stupne
+StageConfig.separation.lbl.title = Oznac kdy se má tento stupn oddelit:
+StageConfig.separation.lbl.plus = plus
+StageConfig.separation.lbl.seconds = sekundy
+
+!EllipticalFinSetConfig
+EllipticalFinSetCfg.Nbroffins = Pocet stabilizátoru:
+EllipticalFinSetCfg.Rotation = Otocení:
+EllipticalFinSetCfg.Fincant = Natocení stabilizátoru:
+EllipticalFinSetCfg.Rootchord = Vý\u0161ka stabilizátoru:
+EllipticalFinSetCfg.Height = \u0160irka stabilizátoru:
+EllipticalFinSetCfg.Positionrelativeto = Pozice vzhledem k:
+EllipticalFinSetCfg.plus = plus
+EllipticalFinSetCfg.FincrossSection = Hrany stabilizátoru:
+EllipticalFinSetCfg.Thickness = Tlou\u0161tka:
+EllipticalFinSetCfg.General = General
+EllipticalFinSetCfg.Generalproperties = Obecné vlastnosti
+EllipticalFinSetCfg.ttip.Fincant = Úhly stabilizátoru jsou nakloneny vzhledem k telu rakety.
+
+!FreeformFinSetConfig
+FreeformFinSetCfg.tab.General = Obecné
+FreeformFinSetCfg.tab.ttip.General = Obecné vlastnosti
+FreeformFinSetCfg.tab.Shape = Tvar
+FreeformFinSetCfg.tab.ttip.Finshape = Tvar stabilizátoru
+FreeformFinSetCfg.lbl.Numberoffins = Pocet stabilizátoru:
+FreeformFinSetCfg.lbl.Finrotation = Rotace stabilizátoru:
+FreeformFinSetCfg.lbl.Fincant = Natocení stabilizátoru:
+FreeformFinSetCfg.lbl.ttip.Fincant = Úhly stabilizátoru jsou nakloneny vzhledem k telu rakety.
+FreeformFinSetCfg.lbl.Posrelativeto = Pozice vzhledem k:
+FreeformFinSetCfg.lbl.plus = plus
+FreeformFinSetCfg.lbl.FincrossSection = Hrany stabilizátoru:
+FreeformFinSetCfg.lbl.Thickness = Tlou\u0161tka:
+! doubleClick1 + 2 form the message "Double-click to edit", split approximately at the middle
+FreeformFinSetConfig.lbl.doubleClick1 = Dvoj klik
+FreeformFinSetConfig.lbl.doubleClick2 = k editaci
+FreeformFinSetConfig.lbl.clickDrag = Klik a táhnout: Pridej a presun body
+FreeformFinSetConfig.lbl.ctrlClick = Ctrl+klik: Odstran bod
+FreeformFinSetConfig.lbl.scaleFin = Merítko stabilizátoru
+
+
+!InnerTubeConfig
+InnerTubeCfg.tab.Motor = Motor
+InnerTubeCfg.tab.ttip.Motor = Nastavení pripojení motoru
+InnerTubeCfg.tab.Cluster = Shluk
+InnerTubeCfg.tab.ttip.Cluster = Nastavení shluku
+InnerTubeCfg.tab.Radialpos = Vzdálenost od stredu
+InnerTubeCfg.tab.ttip.Radialpos = Vzdálenost od stredu
+InnerTubeCfg.lbl.Selectclustercfg = Nastavení konfigurace shluku:
+InnerTubeCfg.lbl.TubeSep = Vzdálenost od ostatních trubek:
+InnerTubeCfg.lbl.ttip.TubeSep = Vzdálenost od ostatních trubek, 1.0 = dotýkání se ostatních
+InnerTubeCfg.lbl.Rotation = Rotace:
+InnerTubeCfg.lbl.ttip.Rotation = Rotace úhlu shlukové konfigurace
+InnerTubeCfg.lbl.Rotangle = Rotace úhlu shlukové konfigurace
+InnerTubeCfg.but.Splitcluster = Rozdel shluk
+InnerTubeCfg.lbl.longA1 = <html>Rozdelí shluka na dílcí komponenty.<br>
+InnerTubeCfg.lbl.longA2 = Toto také duplikuje v\u0161echny komponenty pripojené k této vnitrní trubce.
+InnerTubeCfg.but.Resetsettings = Resetuj nastavení
+InnerTubeCfg.but.ttip.Resetsettings = Resetuj rozdelení a rotaci na výchozí hodnoty
+
+! LaunchLugConfig
+LaunchLugCfg.lbl.Length = Délka:
+LaunchLugCfg.lbl.Outerdiam = Vnej\u0161í prumer:
+LaunchLugCfg.lbl.Innerdiam = Vnitrní prumer:
+LaunchLugCfg.lbl.Thickness = Tlou\u0161tka:
+LaunchLugCfg.lbl.Radialpos = Vzdálenost od stredu:
+LaunchLugCfg.lbl.Posrelativeto = Pozice vzhledem k:
+LaunchLugCfg.lbl.plus = plus
+LaunchLugCfg.tab.General = Obecné
+LaunchLugCfg.tab.Generalprop = Obecné vlastnosti
+
+! MassComponentConfig
+MassComponentCfg.lbl.Mass = Hmotnost:
+MassComponentCfg.lbl.Length = Délka:
+MassComponentCfg.lbl.Diameter = Prumer:
+MassComponentCfg.lbl.PosRelativeto = Pozice vzhledem k:
+MassComponentCfg.lbl.plus = plus
+MassComponentCfg.tab.General = Obecné
+MassComponentCfg.tab.ttip.General = Obecné vlastnosti
+MassComponentCfg.tab.Radialpos = Vzdálenost od stredu
+MassComponentCfg.tab.ttip.Radialpos = Radial position configuration
+MassComponentCfg.lbl.Radialdistance = Vzdálenost od stredu:
+MassComponentCfg.lbl.Radialdirection = Smer vzdalování se od stredu:
+MassComponentCfg.but.Reset = Reset
+
+! MotorConfig
+MotorCfg.checkbox.compmotormount = Tto komponeta je pripojení motoru
+MotorCfg.lbl.Motorcfg = Nastavení motoru:
+MotorCfg.but.New = Nový
+MotorCfg.lbl.Currentmotor = Soucasný motor:
+MotorCfg.lbl.Motoroverhang = Precnívání motoru:
+MotorCfg.lbl.Ignitionat = Zapalování v:
+MotorCfg.lbl.plus = plus
+MotorCfg.lbl.seconds = sekundy
+MotorCfg.lbl.longA1 = Soucasný návrh má pouze jeden motor.
+MotorCfg.lbl.longA2 = Stupne mohou být pridány kliknutím na  \"Nový stupen\".
+MotorCfg.lbl.longB1 = Soucasný návrh má
+MotorCfg.lbl.longB2 = stupnu.
+MotorCfg.but.Selectmotor = Vyber motor
+MotorCfg.but.Removemotor = Odeber motor
+MotorCfg.lbl.motorLabel = Nic
+
+! NoseConeConfig
+NoseConeCfg.lbl.Noseconeshape = Tvar nosního ku\u017Eele:
+NoseConeCfg.lbl.Shapeparam = Tvarový parametr:
+NoseConeCfg.lbl.Noseconelength = Délka nosního ku\u017Eelu:
+NoseConeCfg.lbl.Basediam = Základový prumer:
+NoseConeCfg.checkbox.Automatic = Automaticky
+NoseConeCfg.lbl.Wallthickness =  Tlou\u0161tka steny:
+NoseConeCfg.checkbox.Filled = Vyplneno
+NoseConeCfg.tab.General = Obecný
+NoseConeCfg.tab.ttip.General = Obecné vlastnosti
+NoseConeCfg.tab.Shoulder = Pripojení
+NoseConeCfg.tab.ttip.Shoulder = Parametry pripojení
+
+! ParachuteConfig
+ParachuteCfg.lbl.Canopy = Vrchlík padáku:
+ParachuteCfg.lbl.Diameter = Prumer:
+ParachuteCfg.lbl.Material = Materiál:
+ParachuteCfg.combo.MaterialModel = Materiál padáku ovlivnuje hmotnost padáku.
+ParachuteCfg.lbl.longA1 = <html>Brzdný koeficient C<sub>D</sub>:
+ParachuteCfg.lbl.longB1 = <html>Brzdný koeficient je vzta\u017Ený k celkové plo\u0161e padáku.<br>
+ParachuteCfg.lbl.longB2 = Vy\u0161\u0161í brzdný koeficient dovoluje pomalej\u0161í sestup.  
+ParachuteCfg.lbl.longB3 = Typické hodnoty pro padák jsou 0.8.
+ParachuteCfg.but.Reset = Reset
+ParachuteCfg.lbl.Shroudlines = Padákové \u0161nury:
+ParachuteCfg.lbl.Numberoflines = Pocet \u0161nur:
+ParachuteCfg.lbl.Linelength = Délka \u0161nur:
+ParachuteCfg.lbl.Material = Materiál:
+ParachuteCfg.lbl.Posrelativeto = Pozice vzhledem k:
+ParachuteCfg.lbl.plus = plus
+ParachuteCfg.lbl.Packedlength = Délka balíku:
+ParachuteCfg.lbl.Packeddiam = Prumer balíku:
+ParachuteCfg.lbl.Deploysat = Rozvinout v:
+ParachuteCfg.lbl.seconds = sekundy
+ParachuteCfg.lbl.Altitude = Vý\u0161ka:
+ParachuteCfg.tab.General = Obecné
+ParachuteCfg.tab.ttip.General = Obecné vlastnosti
+ParachuteCfg.tab.Radialpos = Vzdálenost od stredu
+ParachuteCfg.tab.ttip.Radialpos = Konfigurace stredové pozice
+ParachuteCfg.lbl.Radialdistance = Vzdálenost od stredu:
+ParachuteCfg.lbl.Radialdirection = Smer vzdalování se od stredu:
+ParachuteCfg.but.Reset = Reset
+ParachuteCfg.lbl.plusdelay = plus
+
+! ShockCordConfig 
+ShockCordCfg.lbl.Shockcordlength = Délka poutací \u0161nury:
+ShockCordCfg.lbl.Shockcordmaterial = Materiál poutací \u0161nury:
+ShockCordCfg.lbl.Posrelativeto = Pozice vzhledem k:
+ShockCordCfg.lbl.plus = plus
+ShockCordCfg.lbl.Packedlength = Délka balíku:
+ShockCordCfg.lbl.Packeddiam =   Prumer balíku:
+ShockCordCfg.tab.General = General
+ShockCordCfg.tab.ttip.General = Obecné vlastnosti
+
+!SleeveConfig
+SleeveCfg.tab.Outerdiam = Vnej\u0161í prumer:
+SleeveCfg.tab.Innerdiam = Vnitrní prumer:
+SleeveCfg.tab.Wallthickness = Tlou\u0161tka zdi:
+SleeveCfg.tab.Length = Délka:
+SleeveCfg.tab.General = Obecný
+SleeveCfg.tab.Generalproperties = Obecné vlastnosti
+
+! StreamerConfig
+StreamerCfg.lbl.Striplength = Délka pruhu:
+StreamerCfg.lbl.Stripwidth = \u0160írka pruhu:
+StreamerCfg.lbl.Striparea = Plocha pruhu:
+StreamerCfg.lbl.Aspectratio = Pomer pruhu:
+StreamerCfg.lbl.Material = Materiál:
+StreamerCfg.combo.ttip.MaterialModel = Materiál komponenty má vliv na váhu komponenty.
+StreamerCfg.lbl.longA1 = <html>Brzdný koeficient C<sub>D</sub>:
+StreamerCfg.lbl.longB1 = <html>Brzdný koeficient se vztahuje k celkové plose stuhy.<br>
+StreamerCfg.lbl.longB2 = Vy\u0161\u0161í brzdný koeficient dovoluje pomalej\u0161í sestup.
+StreamerCfg.lbl.Automatic = Automatický
+StreamerCfg.lbl.longC1 = Brzdný koeficient se vztahuje k celkové plose stuhy.
+StreamerCfg.lbl.Posrelativeto = Pozice vzhledem k:
+StreamerCfg.lbl.plus = plus
+StreamerCfg.lbl.Packedlength = Délka balíku:
+StreamerCfg.lbl.Packeddiam = Prumer balíku:
+StreamerCfg.lbl.Deploysat = Rozvinout v:
+StreamerCfg.lbl.seconds = sekundy
+StreamerCfg.lbl.Altitude = Nadmorská vý\u0161ka:
+StreamerCfg.tab.General = Obecný
+StreamerCfg.tab.ttip.General = Obecné vlastnosti
+StreamerCfg.tab.Radialpos = Vzdálenost od stredu
+StreamerCfg.tab.ttip.Radialpos = Nastavení pozice od stredu
+StreamerCfg.lbl.Radialdistance = Vzdálenost od stredu:
+StreamerCfg.lbl.Radialdirection = Smer vzdalování se od stredu:
+StreamerCfg.but.Reset = Reset
+StreamerCfg.lbl.plusdelay = plus
+
+! ThicknessRingComponentConfig
+ThicknessRingCompCfg.tab.Outerdiam = Vnej\u0161í prumer:
+ThicknessRingCompCfg.tab.Innerdiam = Vnitrní prumer:
+ThicknessRingCompCfg.tab.Wallthickness = Tlou\u0161tka zdi:
+ThicknessRingCompCfg.tab.Length = Délka:
+ThicknessRingCompCfg.tab.General = Obecný
+ThicknessRingCompCfg.tab.Generalprop = Obecné vlastnosti
+
+! TransitionConfig
+TransitionCfg.lbl.Transitionshape = Tvar prechodu trupu:
+TransitionCfg.checkbox.Clipped = Zkrácený
+TransitionCfg.lbl.Shapeparam = Parametr tvaru:
+TransitionCfg.lbl.Transitionlength = Délka prechodu trupu:
+TransitionCfg.lbl.Forediam = Prídový prumer prechodu trupu:
+TransitionCfg.checkbox.Automatic = Automatický
+TransitionCfg.lbl.Aftdiam = Zádový prumer:
+TransitionCfg.lbl.Wallthickness = Tlou\u0161tka steny:
+TransitionCfg.checkbox.Filled = Vyplneno
+TransitionCfg.tab.General = Obecný
+TransitionCfg.tab.Generalproperties = Obecné vlastnosti
+TransitionCfg.tab.Shoulder = Pripojení 
+TransitionCfg.tab.Shoulderproperties = Parametry pripojení
+
+! TrapezoidFinSetConfig
+TrapezoidFinSetCfg.lbl.Nbroffins = Pocet stabilizátoru:
+TrapezoidFinSetCfg.lbl.ttip.Nbroffins = Pocet krídélek tvorící stabilizátor.
+TrapezoidFinSetCfg.lbl.Finrotation = Rotace stabilizátoru:
+TrapezoidFinSetCfg.lbl.ttip.Finrotation = Úhel prvního kridélka v stabilizátoru.
+TrapezoidFinSetCfg.lbl.Fincant = Natocení stabilizátoru:
+TrapezoidFinSetCfg.lbl.ttip.Fincant = Úhly stabilizátoru jsou nakloneny vzhledem k telu rakety.
+TrapezoidFinSetCfg.lbl.Rootchord = Koren krídla:
+TrapezoidFinSetCfg.lbl.Tipchord = Konec krídla:
+TrapezoidFinSetCfg.lbl.Height = Vý\u0161ka:
+TrapezoidFinSetCfg.lbl.Sweeplength = Délka skosení:
+TrapezoidFinSetCfg.lbl.Sweepangle = Úhel skosení:
+TrapezoidFinSetCfg.lbl.FincrossSection = Hrany stabilizátoru:
+TrapezoidFinSetCfg.lbl.Thickness = Tlou\u0161tka:
+TrapezoidFinSetCfg.lbl.Posrelativeto = Pozice vzhledem k:
+TrapezoidFinSetCfg.lbl.plus = plus
+TrapezoidFinSetCfg.tab.General = Obecné
+TrapezoidFinSetCfg.tab.Generalproperties = Obecné vlastnosti
+
+!MotorConfigurationModel
+MotorCfgModel.Editcfg = Editace konfigurace
+
+! StorageOptionChooser
+StorageOptChooser.lbl.Simdatatostore = Simulacní data k ulo\u017Eení:
+StorageOptChooser.rdbut.Allsimdata = V\u0161echny data ze simulace
+StorageOptChooser.lbl.longA1 = <html>Ulo\u017Eí v\u0161echny simulacní data.<br>
+StorageOptChooser.lbl.longA2 = Výsledek mu\u017Ee vyústit ve velmi velké soubory!
+StorageOptChooser.rdbut.Every = Ka\u017Edý
+StorageOptChooser.lbl.longB1 = <html>Store plottable values approximately this far apart.<br>
+StorageOptChooser.lbl.longB2 = Vet\u0161í hodnoty vyústí v men\u0161í soubory.
+StorageOptChooser.lbl.seconds = sekundy
+StorageOptChooser.rdbut.Onlyprimfig = Pouze hlavní grafy
+StorageOptChooser.lbl.longC1 = <html>Ulo\u017E pouze hodnoty ukázané v prehledu.<br>
+StorageOptChooser.lbl.longC2 = This results in the smallest files.
+StorageOptChooser.checkbox.Compfile = Zkomprimovat soubor
+StorageOptChooser.lbl.UsingComp = Pou\u017Eitím komprese se významne redukuje velikost souboru.
+StorageOptChooser.lbl.longD1 = Odhad jak velký bude výsledný soubor se stavajícím nastavením.
+StorageOptChooser.ttip.Saveopt = Ulo\u017Eit nastavení
+StorageOptChooser.lbl.Estfilesize = Odhadovaná velikost souboru:
+StorageOptChooser.lbl.Saveopt = Ulo\u017Eit nastavení
+
+! ThrustCurveMotorSelectionPanel
+TCMotorSelPan.lbl.Selrocketmotor = Vyber raketový motor:
+TCMotorSelPan.checkbox.hideSimilar = Schovej velmi podobné výkonové krivky
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = Uka\u017E v\u0161echny motory
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc2 = Uka\u017E motory s prumerem men\u0161ím ne\u017E toto uchycení motoru
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc3 = Uka\u017E motory se stejným prumerem jako toto uchycení motoru
+TCMotorSelPan.lbl.Motormountdia = Prumer uchycení motoru:
+TCMotorSelPan.lbl.Search = Hledej:
+TCMotorSelPan.lbl.Selectthrustcurve = Vyber výkonovou krivku:
+TCMotorSelPan.lbl.Ejectionchargedelay = Oddelovací zpo\u017Edení:
+TCMotorSelPan.equalsIgnoreCase.None = Nic
+TCMotorSelPan.lbl.NumberofsecondsorNone = (Pocet sekund nebo \"Nic\")
+TCMotorSelPan.lbl.Totalimpulse = Celkový impulse:
+TCMotorSelPan.lbl.Avgthrust = Prumerný tah:
+TCMotorSelPan.lbl.Maxthrust = Maximální tah:
+TCMotorSelPan.lbl.Burntime = Doba horení:
+TCMotorSelPan.lbl.Launchmass = Hmotnost pri startu:
+TCMotorSelPan.lbl.Emptymass = Prázdná hmotnost:
+TCMotorSelPan.lbl.Datapoints = Datové body:
+TCMotorSelPan.lbl.Digest = Výber:
+TCMotorSelPan.title.Thrustcurve = Výkonová krivka:
+TCMotorSelPan.title.Thrust = Tah
+TCMotorSelPan.delayBox.None = Nic
+
+
+! PlotDialog
+PlotDialog.title.Flightdataplot = Flight data plot
+PlotDialog.Chart.Simulatedflight = Simulovaný let
+PlotDialog.CheckBox.Showdatapoints = Uka\u017E datové body
+PlotDialog.lbl.Chart = Kliknout a táhnout dolu a doprava zvet\u0161ení nahoru a vlevo zmen\u0161ení
+
+
+! "main" prefix is used for the main application dialog
+
+# FIXME: Rename the description keys 
+
+main.menu.file = Soubor
+main.menu.file.desc = Operace se souborem 
+main.menu.file.new = Nový
+main.menu.file.new.desc = Vytvorit nový návrh rakety
+main.menu.file.open = Otevrít...
+BasicFrame.item.Openrocketdesign = Otevrít návrh rakety
+main.menu.file.openExample = Otevrít ukázku...
+BasicFrame.item.Openexamplerocketdesign = Otevrít ukázkový návrh rakety
+main.menu.file.save = Ulo\u017Eit
+BasicFrame.item.SavecurRocketdesign = Ulo\u017Eit soucasný návrh rakety
+main.menu.file.saveAs = Ulo\u017Eit jako...
+BasicFrame.item.SavecurRocketdesnewfile = Ulo\u017Eit soucasný návrh rakety do nového souboru
+main.menu.file.print = Vytisknout / exportovat do PDF...
+main.menu.file.print.desc = Vytisknout nebo exportovat do PDF jako Print or save as PDF the parts list and fin templates
+main.menu.file.close = Zavrít  
+BasicFrame.item.Closedesign = Ulo\u017Eit soucasný návrh rakety
+main.menu.file.quit = Konec
+BasicFrame.item.Quitprogram = Ukonci progrem
+
+main.menu.edit = Edituj
+BasicFrame.menu.Rocketedt = Editace rakety
+main.menu.edit.undo = Zpet
+main.menu.edit.undo.desc = Vrátit zpet predchozí akci
+main.menu.edit.redo = Znovu
+main.menu.edit.redo.desc = Znovu predchozí operaci
+main.menu.edit.cut = Vyjmout
+main.menu.edit.copy = Kopírovat
+main.menu.edit.paste = Vlo\u017Eit
+main.menu.edit.delete = Smazat
+main.menu.edit.resize = Merítko...
+main.menu.edit.resize.desc = Merítko cástí návrhu rakety
+main.menu.edit.preferences = Nastavení
+main.menu.edit.preferences.desc = Nastavení aplikace
+
+main.menu.analyze = Anal\u017Eýza
+main.menu.analyze.desc = Analýza rakety
+main.menu.analyze.componentAnalysis = Analýza komponent
+main.menu.analyze.componentAnalysis.desc = Analyzuj cásti rakety samostatne
+main.menu.analyze.optimization = Optimalizace rakety
+main.menu.analyze.optimization.desc = Obecný návrh optimalizace rakety
+
+main.menu.help = Pomoc
+main.menu.help.desc = Informace o programu OpenRocket
+main.menu.help.tours = Prohlídky z pruvodcem
+main.menu.help.tours.desc = Uka\u017E prohlídku programu OpenRocket
+main.menu.help.license = Licence
+main.menu.help.license.desc = Informaci o licenci OpenRocket
+main.menu.help.bugReport = Hlá\u0161ení chyb
+main.menu.help.bugReport.desc = Informace o hlá\u0161ení chyb v OpenRocket
+main.menu.help.debugLog = Informace o ladení
+main.menu.help.debugLog.desc = Uka\u017E informace o ladení OpenRocket
+main.menu.help.about = O programu
+main.menu.help.about.desc = Detaily autorských práv k OpenRocket
+
+main.menu.debug = ladení
+main.menu.debug.whatisthismenu = Co je v tomto menu?
+main.menu.debug.createtestrocket = Udelej test rakety
+
+! database
+! Translate here all material database
+!
+
+! Material database
+! BULK_MATERIAL
+material.acrylic = Akryl
+material.aluminum = Hliník
+material.balsa = Balza
+material.basswood = Lípa
+material.birch = Bríza
+material.brass = Mosaz
+material.cardboard = Kartón
+material.carbon_fiber = Vystu\u017Eený kartón
+material.cork = Korek
+material.depron_xps = Depron (XPS)
+material.fiberglass = Skelné vlákno
+material.kraft_phenolic = Kraft phenolic
+material.maple = Javor
+material.paper_office = Papír (kancelárský)
+material.pine = Borovice
+material.plywood_birch = Prekli\u017Eka (briza)
+material.polycarbonate_lexan = Polykarbonát (Lexan)
+material.polystyrene = Polystyrén
+material.pvc = PVC
+material.spruce = Smrk
+material.steel = Ocel
+material.styrofoam_generic_eps = Styrofoam (obecný EPS)
+material.styrofoam_blue_foam_xps = Styrofoam \"modrá pena\" (XPS)
+material.titanium = Titan
+material.quantum_tubing = Quantum tubing
+material.blue_tube = Blue tube
+!SURFACE_MATERIAL
+material.ripstop_nylon = Ripstoponový nylon
+material.mylar = Mylar
+material.polyethylene_thin = Polyethylén (tenký)
+material.polyethylene_heavy = Polyethylén (te\u017Eký)
+material.silk = Hedvábí
+material.paper_office = Papír (kancelárský)
+material.cellophane = Celofán
+material.crepe_paper = Celulární papír
+! LINE_MATERIAL
+material.thread_heavy_duty = Vlákno (vysoce odolné)
+material.elastic_cord_round_2_mm_1_16_in = Elastická \u0161nura (round 2mm, 1/16 in)
+material.elastic_cord_flat_6_mm_1_4_in = Elastická \u0161nura (flat  6mm, 1/4 in)
+material.elastic_cord_flat_12_mm_1_2_in = Elastická \u0161nura (flat 12mm, 1/2 in)
+material.elastic_cord_flat_19_mm_3_4_in = Elastická \u0161nura (flat 19mm, 3/4 in)
+material.elastic_cord_flat_25_mm_1_in = Elastická \u0161nura (flat 25mm, 1 in)
+material.braided_nylon_2_mm_1_16_in = Spletený nylon (2 mm, 1/16 in)
+material.braided_nylon_3_mm_1_8_in = Spletený nylon (3 mm, 1/8 in)
+material.tubular_nylon_11_mm_7_16_in = Trubkovitý nylon (11 mm, 7/16 in)
+material.tubular_nylon_14_mm_9_16_in = Trubkovitý nylon (14 mm, 9/16 in)
+material.tubular_nylon_25_mm_1_in = Trubkovitý nylon (25 mm, 1 in)
+
+! ExternalComponent
+ExternalComponent.Rough = drsný
+ExternalComponent.Unfinished = nedokoncený
+ExternalComponent.Regularpaint = normálne natrený
+ExternalComponent.Smoothpaint = jemne natrený
+ExternalComponent.Polished = vyle\u0161tený
+
+! LineStyle
+LineStyle.Solid = pevná
+LineStyle.Dashed = cárkovaná
+LineStyle.Dotted = teckovaná
+LineStyle.Dash-dotted = tecko-cárkovaná
+LineStyle.Defaultstyle = Výchozí styl
+
+! Shape
+Shape.Conical = Ku\u017Eelovitý
+Shape.Conical.desc1 = Ku\u017Eelovitý prídový kryt má profil jako trojúhelník.
+Shape.Conical.desc2 = Ku\u017Eel má rovné strany.
+Shape.Ogive = Obloukovitý
+Shape.Ogive.desc1 = Profil prídového krytu ve tvaru lomeného oblouku tvorí úsek kru\u017Enice. Tvarový parametr o hodnote 1 urcuje <b>tecnu lomeného oblouku</b>, která plynule od oblouku prechází jako telo rakety , hodota men\u0161í ne\u017E 1 urcuje <b>secnu lomeného oblouku</b>.
+Shape.Ogive.desc2 = Profil prídového krytu ve tvaru lomeného oblouku tvorí úsek kru\u017Enice. Tvarový parametr o hodnote 1 urcuje <b>tecnu lomeného oblouku</b>, která plynule od oblouku prechází jako telo rakety na zád, hodota men\u0161í ne\u017E 1 urcuje <b>secnu lomeného oblouku</b>.
+Shape.Ellipsoid = Eliptycký
+Shape.Ellipsoid.desc1 = Eliptický prídový kryt má profil jako polovina epilpsy a hlavními osamy jsou 2&times;<i>délka</i> a <i>prumer</i>.
+Shape.Ellipsoid.desc2 = Eliptický prídový kryt má profil jako polovina epilpsy a hlavními osamy jsou 2&times;<i>délka</i> a <i>prumer</i>.  Pokud prechod není oríznut, pak je profi roz\u0161íren v centru odpovídajícím polomeru.            
+Shape.Powerseries = Mocniná rada
+Shape.Powerseries.desc1 = Prídový kryt ve tvaru mocniné rady má profil <i>rádiusu</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>délka</i>)<sup><i>k</i></sup> kde <i>k</i> je tvarový parametr.  Pro <i>k</i>=0.5 je to <b>\u00BD-power</b> nebo <b>parabolický</b> prídový kryt, pro <i>k</i>=0.75 a <b>\u00BE-power</b>, a pro <i>k</i>=1 a <b>ku\u017Eelovitý</b> prídový kryt.
+Shape.Powerseries.desc2 = Prechod trupu ve tvaru mocniné rady má profil <i>rádiusu</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>délka</i>)<sup><i>k</i></sup> kde <i>k</i> je tvarový parametr.  Pro <i>k</i>=0.5 je prechod trupu <b>\u00BD-power</b> nebo <b>parabola</b>, pro <i>k</i>=0.75 a <b>\u00BE-power</b>, a pro <i>k</i>=1 <b>ku\u017Eel</b>.
+Shape.Parabolicseries = Parabola
+Shape.Parabolicseries.desc1 = Parabolický prídový kryt má profil paraboly.  Tvarový parametr definuje úsek paraboly, který je vyu\u017Eit.  Tvarový parametr 1.0 produkuje <b>plnou parabolu</b> kde telová trubka je její tecnou, 0.75 produkuje <b>3/4 parabolu</b>, 0.5 produkuje <b>1/2 parabolu</b> a 0 produkuje <b>ku\u017Eelovitý</b> prídový kryt.
+Shape.Parabolicseries.desc2 = Parabolický prechod trupu má profil paraboly.  Tvarový parametr definuje úsek paraboly, který je vyu\u017Eit.  Tvarový parametr 1.0 produkuje <b>plnou parabolu</b> kde telová trubka je její tecnou na zadní cásti, 0.75 produkuje <b>3/4 parabolu</b>, 0.5 produkuje <b>1/2 parabolu</b> a 0 produkuje <b>ku\u017Eelovitý</b> prechod trupu.
+Shape.Haackseries = Haack 
+Shape.Haackseries.desc1 = Haackový prídový kryt je navr\u017Een pro minimalizování aerodynamického odporu.  Tvarový parametr 0 produkuje <b>LD-Haack</b> nebo <b>Von Karmanuv</b> prídový kryz, který minimalizuje aerodynamický odpor pro pevne danou délku a prumer, zatímco hodnota 0.333 produkuje <b>LV-Haack</b> prídový kryt, který minimalizuje aerodynamický odpor pro pevn\u0161 danou délku a objem.
+Shape.Haackseries.desc2 = Haackový <i>prídový kryt</i> je navr\u017Een pro minimalizování aerodynamického odporu.  Tyto prechody trupu jsou jeho ekvivalenty, ale nemusí mit nutne optimální aerodynamický odpor vzduchu pro prechod trupu.  Tvarový parametr 0 produkuje <b>LD-Haack</b> nebo <b>Von Karmanuv</b> tvar, zatímco hodnota 0.333 produkuje tvar<b>LV-Haack</b>.          
+
+
+! RocketComponent
+RocketComponent.Position.TOP = Vrchol rodicovské komponenty
+RocketComponent.Position.MIDDLE = Stred rodicovské komponenty
+RocketComponent.Position.BOTTOM = Spodek rodicovské komponenty
+RocketComponent.Position.AFTER = Za rodicovskou komponentou
+RocketComponent.Position.ABSOLUTE = \u0160picka nosního ku\u017Eelu
+
+! LaunchLug
+LaunchLug.Launchlug = Vypou\u0161tecí oko
+! NoseCone
+NoseCone.NoseCone = Nosní ku\u017Eel
+! Transition
+Transition.Transition = Prechod
+!Stage
+Stage.Stage = Stupen
+
+Stage.SeparationEvent.UPPER_IGNITION = Horní stupen zapálení motoru
+Stage.SeparationEvent.IGNITION = Soucasný stupen zapálení motoru
+Stage.SeparationEvent.BURNOUT = Current stage motor burnout
+Stage.SeparationEvent.EJECTION = Current stage ejection charge
+Stage.SeparationEvent.LAUNCH = Vypust
+Stage.SeparationEvent.NEVER = Nikdy
+
+! BodyTube
+BodyTube.BodyTube = Telo rakety
+! TubeCoupler
+TubeCoupler.TubeCoupler = Spojení trubic
+!InnerTube
+InnerTube.InnerTube = Vnitrní trubice
+! TrapezoidFinSet
+TrapezoidFinSet.TrapezoidFinSet = Lichobe\u017Eníkové stabilizátory
+! FreeformFinSet
+FreeformFinSet.FreeformFinSet = Volno tvarové stabilizátory
+!MassComponent
+MassComponent.MassComponent = Hmotnost komponenty
+! Parachute
+Parachute.Parachute = Padák
+! ShockCord
+ShockCord.ShockCord = Poutací \u0160nura
+! Bulkhead
+Bulkhead.Bulkhead = Prepá\u017Eka
+
+!Rocket
+Rocket.motorCount.Nomotor = [\u017Dádné motory]
+Rocket.compname.Rocket = Raketa
+
+!MotorMount
+MotorMount.IgnitionEvent.AUTOMATIC = Automatický (vypu\u0161tení nebo vyhození predchozího stupne)
+MotorMount.IgnitionEvent.LAUNCH = Vypu\u0161tení
+MotorMount.IgnitionEvent.EJECTION_CHARGE = První vypu\u0161tení nebo vyhození predchozího stupne
+MotorMount.IgnitionEvent.BURNOUT = První vyhorení predchozího stupne
+MotorMount.IgnitionEvent.NEVER = Nikdy
+
+!ComponentIcons 
+ComponentIcons.Nosecone = Celní ku\u017Eel
+ComponentIcons.Bodytube = Telová trubka 
+ComponentIcons.Transition = Prechod trupu
+ComponentIcons.Trapezoidalfinset = Lichobe\u017Eníkové stabilizátory
+ComponentIcons.Ellipticalfinset = Eliptické stabilizátory
+ComponentIcons.Freeformfinset = Volno tvarové stabilizátory
+ComponentIcons.Launchlug = Vypou\u0161tecí oko
+ComponentIcons.Innertube = Vnitrní trubka
+ComponentIcons.Tubecoupler = Spojení trubic
+ComponentIcons.Centeringring = Trupová prepá\u017Eka
+ComponentIcons.Bulkhead = Prepá\u017Eka
+ComponentIcons.Engineblock = Blok motoru
+ComponentIcons.Parachute = Padák
+ComponentIcons.Streamer = Brzdící prou\u017Eek
+ComponentIcons.Shockcord = Poutací \u0161nura
+ComponentIcons.Masscomponent = Hmotnost komponenty
+ComponentIcons.disabled = (zakázaný)
+
+! StageAction
+StageAction.Stage = Stupen
+
+! RecoveryDevice
+RecoveryDevice.DeployEvent.LAUNCH = Vypu\u0161tení (plus NN sekund)
+RecoveryDevice.DeployEvent.EJECTION = První vyhorení tohoto stupne
+RecoveryDevice.DeployEvent.APOGEE = Vrchol
+RecoveryDevice.DeployEvent.ALTITUDE = Konkrétní vý\u0161ka behem sestupu
+RecoveryDevice.DeployEvent.NEVER = Nikdy
+
+! FlightEvent
+FlightEvent.Type.LAUNCH = Vypu\u0161tení
+FlightEvent.Type.IGNITION = Zapálení motoru
+FlightEvent.Type.LIFTOFF = Vzlétnout
+FlightEvent.Type.LAUNCHROD = Vzdálenost vypou\u0161tecí tyce
+FlightEvent.Type.BURNOUT = Vyhorení motoru
+FlightEvent.Type.EJECTION_CHARGE = Ejection charge
+FlightEvent.Type.STAGE_SEPARATION = Oddelení stupne
+FlightEvent.Type.APOGEE = Vrchol
+FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT = Navrácení nasazení zarízení
+FlightEvent.Type.GROUND_HIT = Náraz do zeme
+FlightEvent.Type.SIMULATION_END = Konec simulace
+FlightEvent.Type.ALTITUDE = Zmena vý\u0161ky
+
+! ThrustCurveMotorColumns
+TCurveMotorCol.MANUFACTURER = Výrobce
+TCurveMotorCol.DESIGNATION = Pojmenování
+TCurveMotorCol.TYPE = Druh
+TCurveMotorCol.DIAMETER = Prumer
+TCurveMotorCol.LENGTH = Délka
+
+! RocketInfo
+RocketInfo.lengthLine.Length = Délka
+RocketInfo.lengthLine.maxdiameter = , max. prumer
+RocketInfo.massText1 = Hmotnost s motory 
+RocketInfo.massText2 = Hmotnost bez motoru
+RocketInfo.at = v M=
+RocketInfo.cgText = Te\u017Eí\u0161te:
+RocketInfo.cpText = Centrum tlaku:
+RocketInfo.stabText = Stabilita:
+RocketInfo.Warning = Varování:
+RocketInfo.Calculating = Pocítám...
+RocketInfo.Apogee = Vrchol:
+RocketInfo.Maxvelocity = Max. rychlost:
+RocketInfo.Maxacceleration = Max. akcelerace:
+RocketInfo.apogeeValue = N/A
+RocketInfo.Mach = (Mach
+RocketInfo.velocityValue = N/A
+RocketInfo.accelerationValue = N/A
+
+! FinSet
+FinSet.CrossSection.SQUARE = Ctvercový
+FinSet.CrossSection.ROUNDED = Oblý
+FinSet.CrossSection.AIRFOIL = Aerodynamický profil
+FinSet.TabRelativePosition.FRONT = Tetiva u korene nábe\u017Ené hrany
+FinSet.TabRelativePosition.CENTER = Stred tetivy u korene
+FinSet.TabRelativePosition.END = Tetiva u korene odtokové hrany
+
+! FlightDataType
+FlightDataType.TYPE_TIME = Cas
+FlightDataType.TYPE_ALTITUDE = Nadmorská vý\u0161ka
+FlightDataType.TYPE_VELOCITY_Z = Svislá rychlost
+FlightDataType.TYPE_ACCELERATION_Z = Svislé zrychlení
+FlightDataType.TYPE_VELOCITY_TOTAL = Celková rychlost
+FlightDataType.TYPE_ACCELERATION_TOTAL = Celkové zrychlení
+FlightDataType.TYPE_POSITION_X = Pozice proti vetru
+FlightDataType.TYPE_POSITION_Y = Pozice po vetru
+FlightDataType.TYPE_POSITION_XY = Bocní vzdálenost
+FlightDataType.TYPE_POSITION_DIRECTION = Bocní smer
+FlightDataType.TYPE_VELOCITY_XY = Bocní rychlost
+FlightDataType.TYPE_ACCELERATION_XY = Bocní zrychlení
+FlightDataType.TYPE_AOA = Úhel nábehu
+FlightDataType.TYPE_ROLL_RATE = Úhlová rychlost klonení
+FlightDataType.TYPE_PITCH_RATE = Úhlová rychlost klopení
+FlightDataType.TYPE_YAW_RATE = Úhlová rychlost zatácení
+FlightDataType.TYPE_MASS = Hmotnost
+FlightDataType.TYPE_LONGITUDINAL_INERTIA = Podélný moment setrvacnosti
+FlightDataType.TYPE_ROTATIONAL_INERTIA = Tocivý moment setrvacnosti
+FlightDataType.TYPE_CP_LOCATION = Umístení pusobi\u0161te tlaku
+FlightDataType.TYPE_CG_LOCATION = Umístení te\u017Ei\u0161te
+FlightDataType.TYPE_STABILITY = Kvalita bezpecnosti stability
+FlightDataType.TYPE_MACH_NUMBER = Machovo císlo
+FlightDataType.TYPE_REYNOLDS_NUMBER = Reynoldsovo císlo
+FlightDataType.TYPE_THRUST_FORCE = Tah
+FlightDataType.TYPE_DRAG_FORCE = Brzdící síla
+FlightDataType.TYPE_DRAG_COEFF = Brzdící koeficient
+FlightDataType.TYPE_AXIAL_DRAG_COEFF = Osový brzdící koeficient
+FlightDataType.TYPE_FRICTION_DRAG_COEFF = Soucinitel brzdného trení
+FlightDataType.TYPE_PRESSURE_DRAG_COEFF = Tlakový brzdící koeficient
+FlightDataType.TYPE_BASE_DRAG_COEFF = Základní brzdící koeficient
+FlightDataType.TYPE_NORMAL_FORCE_COEFF = Normání silový koeficient
+FlightDataType.TYPE_PITCH_MOMENT_COEFF = Koeficient klopivého momentu
+FlightDataType.TYPE_YAW_MOMENT_COEFF = Koeficient zatácivého momentu
+FlightDataType.TYPE_SIDE_FORCE_COEFF = Koeficient bocní síly
+FlightDataType.TYPE_ROLL_MOMENT_COEFF = Koeficient klonivého momentu
+FlightDataType.TYPE_ROLL_FORCING_COEFF = Koeficient klonivé síly
+FlightDataType.TYPE_ROLL_DAMPING_COEFF = Koeficinet klonivého tlumení
+FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF = Koeficient klopivého tlumení
+FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF = Koeficient zatácivého tlumení
+FlightDataType.TYPE_REFERENCE_LENGTH = Doporucená délka
+FlightDataType.TYPE_REFERENCE_AREA = Doporucená obast
+FlightDataType.TYPE_ORIENTATION_THETA = Svislá orientace (zenit)
+FlightDataType.TYPE_ORIENTATION_PHI = Bocní orientace (azimut)
+FlightDataType.TYPE_WIND_VELOCITY = Rychlost vetru
+FlightDataType.TYPE_AIR_TEMPERATURE = Teplota vzduchu
+FlightDataType.TYPE_AIR_PRESSURE = Tlak vzduchu
+FlightDataType.TYPE_SPEED_OF_SOUND = Rychlost zvuku
+FlightDataType.TYPE_TIME_STEP = Simulacní krok
+FlightDataType.TYPE_COMPUTATION_TIME = Výpocetní cas
+FlightDataType.TYPE_LATITUDE = Zemepisná \u0161írka
+FlightDataType.TYPE_LONGITUDE = Zemepisná délka
+FlightDataType.TYPE_CORIOLIS_ACCELERATION = Koriolisovo zrychlení
+
+! PlotConfiguration
+PlotConfiguration.Verticalmotion = Vertikální pohyb vs. cas
+PlotConfiguration.Totalmotion = Celkový pohyb vs. cas
+PlotConfiguration.Flightside = Letový profil
+PlotConfiguration.Stability = Stabilita vs. cas
+PlotConfiguration.Dragcoef = Brzdící koeficient vs. Machovo císlo
+PlotConfiguration.Rollcharacteristics = Charakteristiky prícného náklonu
+PlotConfiguration.Angleofattack = Úhel nábehu a orientace 
+vs cas
+PlotConfiguration.Simulationtime = Simulacní krok a výpocetní cas
+
+! Warning
+Warning.LargeAOA.str1 = Velký úhel nábehu.
+Warning.LargeAOA.str2 = Velký úhel nábehu (
+Warning.DISCONTINUITY = Nespojitost v prumeru tela rakety.
+Warning.THICK_FIN = Tlou\u0161tka stabilizátoru se nemu\u017Ee modelovat presne.
+Warning.JAGGED_EDGED_FIN = Zubaté hrany stabilizátoru mohou být vypocteny nepresne.
+Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation
+Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING = Záchrané zarízení se otevrelo, zatímco motor stále horel.
+Warning.FILE_INVALID_PARAMETER = Setkání s neplatným parametrem, ignorace.
+
+
+! Scale dialog
+ScaleDialog.lbl.scaleRocket = Celá raketa
+ScaleDialog.lbl.scaleSubselection = Oznac a v\u0161echny subkomponenty
+ScaleDialog.lbl.scaleSelection = Pouze oznacené komponenty
+ScaleDialog.title = Stupnice merítka
+ScaleDialog.lbl.scale = Merítko:
+ScaleDialog.lbl.scale.ttip = Vyberte, zda chcete zmenit merítko celého návrhu nebo pouze vybraných soucástí
+ScaleDialog.lbl.scaling = Uplatni zmenu merítka:
+ScaleDialog.lbl.scaling.ttip = Výsledná velikost, hodnoty nad 100% znamenají zvet\u0161ení a hodnoty pod 100% zmen\u0161ení návrhu.
+! The scaleFrom/scaleTo pair creates a phrase "Scale from [...] to [...]"
+ScaleDialog.lbl.scaleFrom = Merítko od
+ScaleDialog.lbl.scaleTo = do
+ScaleDialog.lbl.scaleFromTo.ttip = Definování merítka na základe puvodní a výsledné délky.
+ScaleDialog.checkbox.scaleMass = Aktualizace vyjádrené hodnoty hmotnosti
+ScaleDialog.checkbox.scaleMass.ttip = Merítko hmotnosti komponenty a prepsání hodnoty hmotnosti tretí mocninou merítka
+ScaleDialog.button.scale = Merítko
+ScaleDialog.undo.scaleRocket = Merítko rakety
+ScaleDialog.undo.scaleComponent = Merítko komponenty
+ScaleDialog.undo.scaleComponents = Merítko komponent
+
+!icons
+Icons.Undo = Zpet
+Icons.Redo = Znovu
+
+OpenRocketPrintable.Partsdetail = Detail cástí
+OpenRocketPrintable.Fintemplates = \u0160ablony stabilizátoru
+OpenRocketPrintable.Transitiontemplates = \u0160ablony prechodu
+OpenRocketPrintable.Noseconetemplates = \u0160ablony nosního ku\u017Eele
+OpenRocketPrintable.Finmarkingguide = Oznacení pruvodce stabilizátory
+OpenRocketPrintable.DesignReport = Hlá\u0161ení o návrhu
+
+OpenRocketDocument.Redo = Znovu
+OpenRocketDocument.Undo = Zpet
+
+!EllipticalFinSet
+EllipticalFinSet.Ellipticalfinset = Eliptický soubor stabilizátoru
+
+! Optimization
+
+! Modifiers
+
+optimization.modifier.nosecone.length = Délka
+optimization.modifier.nosecone.length.desc = Optimalizace délky celního ku\u017Eelu.
+optimization.modifier.nosecone.diameter = Prumer
+optimization.modifier.nosecone.diameter.desc = Optimalizace prumeru celního ku\u017Eelu.
+optimization.modifier.nosecone.thickness = Tlou\u0161tka
+optimization.modifier.nosecone.thickness.desc = Optimalizace tlou\u0161tky steny nosního ku\u017Eelu.
+optimization.modifier.nosecone.shapeparameter = Parametry tvaru
+optimization.modifier.nosecone.shapeparameter.desc = Optimalizace parametru tvaru nosního ku\u017Eelu.
+
+optimization.modifier.transition.length = Délka
+optimization.modifier.transition.length.desc = Optimalizace délky prechodu trupu.
+optimization.modifier.transition.forediameter = Prídový prumer 
+optimization.modifier.transition.forediameter.desc = Optimalizace prídového prumeru prechodu trupu.
+optimization.modifier.transition.aftdiameter = Zádový prumer
+optimization.modifier.transition.aftdiameter.desc = Optimalizace zádového prumeru prechodu trupu.
+optimization.modifier.transition.thickness = Tlou\u0161tka
+optimization.modifier.transition.thickness.desc = Optimalizace tlou\u0161tky steny prechodu trupu.
+optimization.modifier.transition.shapeparameter = Parametry tvaru
+optimization.modifier.transition.shapeparameter.desc = Optimalizace parametru tvaru prechodu trupu.
+
+optimization.modifier.bodytube.length = Délka
+optimization.modifier.bodytube.length.desc = Optimalizace délky telové trubky.
+optimization.modifier.bodytube.outerDiameter = Vnej\u0161í prumer
+optimization.modifier.bodytube.outerDiameter.desc = Optimalizace vnej\u0161ího prumeru telové trubky pri zachování tlou\u0161tky steny.
+optimization.modifier.bodytube.thickness = Tlou\u0161tka
+optimization.modifier.bodytube.thickness.desc = Optimalizace tlou\u0161tky steny telové trubky.
+
+optimization.modifier.trapezoidfinset.rootChord = Tetiva u korene
+optimization.modifier.trapezoidfinset.rootChord.desc = Optimalizace tetivy u korene stabilizátoru (délka stabilizátoru na tele rakety).
+optimization.modifier.trapezoidfinset.tipChord = Koncová tetiva
+optimization.modifier.trapezoidfinset.tipChord.desc = Optimalizace koncové tetivy stabilizátoru (délka stabilizátoru na vnej\u0161ím okraji).
+optimization.modifier.trapezoidfinset.sweep  = Ostrý úhel
+optimization.modifier.trapezoidfinset.sweep.desc = Optimalizace ostrého úhlu stabilizátoru (vzdálenost mezi nábe\u017Enou hranou a kladným \u0161ípem).
+optimization.modifier.trapezoidfinset.height = Vý\u0161ka
+optimization.modifier.trapezoidfinset.height.desc = Optimalizace vý\u0161ky (poloviny rozpetí) stablizátoru.
+
+optimization.modifier.ellipticalfinset.length = Tetiva u korene
+optimization.modifier.ellipticalfinset.length.desc = Optimalizace délky tetivy u korene stabilizátoru.
+optimization.modifier.ellipticalfinset.height = Vý\u0161ka
+optimization.modifier.ellipticalfinset.height.desc = Optimalizace vý\u0161ky (poloviny rozpetí) stabilizátoru.
+
+optimization.modifier.finset.cant = Úhel náklonu
+optimization.modifier.finset.cant.desc = Optimalizace úhlu náklonu stabilizátoru.
+optimization.modifier.finset.position = Pozice
+optimization.modifier.finset.position.desc = Optimalizace pozice stabilizátoru podél tela rakety.
+
+optimization.modifier.launchlug.length = Délka
+optimization.modifier.launchlug.length.desc = Optimalizace délky vypou\u0161tecího oka.
+optimization.modifier.launchlug.outerDiameter = Vnej\u0161í prumer
+optimization.modifier.launchlug.outerDiameter.desc = Optimalizace vnej\u0161ího prumeru vypou\u0161tecího oka.
+optimization.modifier.launchlug.thickness = Tlou\u0161tka
+optimization.modifier.launchlug.thickness.desc = Optimalizace tlou\u0161tky vypou\u0161tecího oka pri zachování konstantního vnej\u0161ího prumeru.
+optimization.modifier.launchlug.position = Pozice
+optimization.modifier.launchlug.position.desc = Optimalizce vypou\u0161tecího oka vzhledem k telu rakety.
+
+
+optimization.modifier.internalcomponent.position = Pozice
+optimization.modifier.internalcomponent.position.desc = Optimalizace pozice komponenty vzhledem rodicovské komponente.
+
+optimization.modifier.masscomponent.mass = Hmotnost
+optimization.modifier.masscomponent.mass.desc = Optimalizace hmotnosti komponenty.
+
+optimization.modifier.parachute.diameter = Prumer
+optimization.modifier.parachute.diameter.desc = Optimalizace prumeru vrchlíku padáku.
+optimization.modifier.parachute.coefficient = Brzdící koeficient
+optimization.modifier.parachute.coefficient.desc = Optimalizace brzdícího koeficientu padáku.  Typický padák má brzdící koeficient okolo 0.8.
+
+optimization.modifier.streamer.length = Délka
+optimization.modifier.streamer.length.desc = Optimalizace délky brzdícího prou\u017Eku.
+optimization.modifier.streamer.width = \u0160írka
+optimization.modifier.streamer.width.desc = Optimalizace \u0161írky brzdícího prou\u017Eku.
+optimization.modifier.streamer.aspectRatio = Pomer stran
+optimization.modifier.streamer.aspectRatio.desc = Optimalizace pomeru stran brzdícího prou\u017Eku (délka/\u0161írka).  NEMEL-by jste zvolit \u0161írku nebo délku brzdícího prou\u017Eku ve stejném pomeru.
+optimization.modifier.streamer.coefficient = Brzdící koeficient
+optimization.modifier.streamer.coefficient.desc = Optimalizace brzdícího koeficinetu brydícího prou\u017Eku.
+
+optimization.modifier.recoverydevice.deployDelay = Zpo\u017Edení otevrení
+optimization.modifier.recoverydevice.deployDelay.desc = Optimalizace zpo\u017Edení otevrení návratového zarízení.
+optimization.modifier.recoverydevice.deployAltitude = Vý\u0161ka otevrení
+optimization.modifier.recoverydevice.deployAltitude.desc = Optimalizace vý\u0161ky otevrení návratového zarízení.
+
+optimization.modifier.rocketcomponent.overrideMass = Zmena hmotnosti
+optimization.modifier.rocketcomponent.overrideMass.desc = Optimalizace zmeny hmotnosti komponety.
+optimization.modifier.rocketcomponent.overrideCG = Zmena te\u017Ei\u0161te
+optimization.modifier.rocketcomponent.overrideCG.desc = Optimalizace zmeny te\u017Ei\u0161te komponenty.
+
+optimization.modifier.motormount.overhang = Presah motoru
+optimization.modifier.motormount.overhang.desc = Optimalizace presahu motoru.
+optimization.modifier.motormount.delay = Zpo\u017Edení zapálení motoru
+optimization.modifier.motormount.delay.desc = Optimalizace zpo\u017Edení zapálení motoru.
+
+
+
+
+! General rocket design optimization dialog
+
+GeneralOptimizationDialog.title = Optimalizace rakety
+GeneralOptimizationDialog.goal.maximize = Maximalizace hodnot
+GeneralOptimizationDialog.goal.minimize = Minimalizace hodnot
+GeneralOptimizationDialog.goal.seek = Hledej hodnotu
+GeneralOptimizationDialog.btn.start = Zacátek optimalizace
+GeneralOptimizationDialog.btn.stop = Konec optimalizace
+GeneralOptimizationDialog.lbl.paramsToOptimize = Parametry optimalizace:
+GeneralOptimizationDialog.btn.add = Pridej
+GeneralOptimizationDialog.btn.add.ttip = Pridej oznacené parametry k optimalizaci
+GeneralOptimizationDialog.btn.remove = Odeber
+GeneralOptimizationDialog.btn.remove.ttip = Odeber oznacené parametry z optimalizace
+GeneralOptimizationDialog.btn.removeAll = Odeber v\u0161e
+GeneralOptimizationDialog.btn.removeAll.ttip = Odeber v\u0161echny parametry z optimalizace
+GeneralOptimizationDialog.lbl.availableParams = Dostupné parametry:
+GeneralOptimizationDialog.lbl.optimizationOpts = Nastavení optimalizace
+GeneralOptimizationDialog.lbl.optimizeSim = Optimalizuj simulaci:
+GeneralOptimizationDialog.lbl.optimizeSim.ttip = vyber kterou simulaci optimalizovat
+GeneralOptimizationDialog.lbl.optimizeValue = Optimalizovaná hodnota:
+GeneralOptimizationDialog.lbl.optimizeValue.ttip = Vyber hodnota má být optimalizována
+GeneralOptimizationDialog.lbl.optimizeGoal = Optimalizacní cíl:
+GeneralOptimizationDialog.lbl.optimizeGoal.ttip = Oznac cíl optimalizace
+GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip = Vlastní hodota k hledání
+GeneralOptimizationDialog.lbl.requireStability = Vy\u017Eadovaná stabilita
+GeneralOptimizationDialog.lbl.requireMinStability = Minimální stabilita:
+GeneralOptimizationDialog.lbl.requireMinStability.ttip = Vy\u017Eadované minimální rozpetí statické stability návrhu
+GeneralOptimizationDialog.lbl.requireMaxStability = Maximální stabilita:
+GeneralOptimizationDialog.lbl.requireMaxStability.ttip = Vy\u017Eadované maximální rozpetí statické stability návrhu
+GeneralOptimizationDialog.status.bestValue = Nejlep\u0161í hodnota:
+GeneralOptimizationDialog.status.bestValue.ttip = Nejlep\u0161í optimalizacní hodnota byla nalezena príli\u0161 daleko.
+GeneralOptimizationDialog.status.stepCount = Pocítací krok:
+GeneralOptimizationDialog.status.stepCount.ttip = Pocet kroku optimalizace, který bude vykonán.
+GeneralOptimizationDialog.status.evalCount = Ohodnocení:
+GeneralOptimizationDialog.status.evalCount.ttip = Celkový pocet funkcních ohodnocení(simulací), která budou provedena.
+GeneralOptimizationDialog.status.stepSize = Délka kroku:
+GeneralOptimizationDialog.status.stepSize.ttip = Soucasná délka optimalizacního kroku (vzhledem k rozsahu optimalizacních parametru)
+GeneralOptimizationDialog.btn.plotPath = Zakresli postup
+GeneralOptimizationDialog.btn.plotPath.ttip = Zakresli postup optimalizace (pouze jedno a dvoudimenzionální optimalizace)
+GeneralOptimizationDialog.btn.save = Ulo\u017E postup
+GeneralOptimizationDialog.btn.save.ttip = Ulo\u017E výsledky funkcních hodnocení (simulací) jako CSV soubor.
+GeneralOptimizationDialog.btn.apply = Aplikuj optimalizaci
+GeneralOptimizationDialog.btn.apply.ttip = Aplikuj optimalizacní výsledky do návrhu rakety
+GeneralOptimizationDialog.btn.reset = Reset
+GeneralOptimizationDialog.btn.reset.ttip = Resetovat raketový návrh na aktuální konstrukci rakety
+GeneralOptimizationDialog.btn.close = Zavri
+GeneralOptimizationDialog.btn.close.ttip = Zavri dialog bez modifkování návrhu rakety
+GeneralOptimizationDialog.error.selectParams.text = Jako první oznacte parametry k optimalizaci z dostupných parametru.
+GeneralOptimizationDialog.error.selectParams.title = Oznac optimalizacní parametry
+GeneralOptimizationDialog.error.optimizationFailure.text = Optimalizaci se nepodarilo spustit:
+GeneralOptimizationDialog.error.optimizationFailure.title = Optimalizace selhala
+GeneralOptimizationDialog.undoText = Pou\u017Eij optimalizaci
+GeneralOptimizationDialog.basicSimulationName = Základní simulace
+GeneralOptimizationDialog.noSimulationName = Bez simulace
+GeneralOptimizationDialog.table.col.parameter = Parametery
+GeneralOptimizationDialog.table.col.current = Soucasný
+GeneralOptimizationDialog.table.col.min = Minimum
+GeneralOptimizationDialog.table.col.max = Maximum
+GeneralOptimizationDialog.export.header = Vlo\u017E hlavicku
+GeneralOptimizationDialog.export.header.ttip = Vlo\u017E hlavicku jako první rádek obsahující popis pusobnosti.
+GeneralOptimizationDialog.export.stability = Stabilita
+
+
+! Dialog for plotting optimization results
+OptimizationPlotDialog.title = Výsledky optimalizace
+OptimizationPlotDialog.lbl.zoomInstructions = Kliknout a táhnout dolu+doprava k priblí\u017Eení, dolu+doleva k oddálení
+OptimizationPlotDialog.plot1d.title = Výsledky optimalizace
+OptimizationPlotDialog.plot1d.series = Výsledky optimalizace
+OptimizationPlotDialog.plot2d.title = Cestak k optimalizaci
+OptimizationPlotDialog.plot2d.path = Cestak k optimalizaci
+OptimizationPlotDialog.plot2d.evals = Ohodnocení
+OptimizationPlotDialog.plot.ttip.stability = Stabilita:
+OptimizationPlotDialog.plot.label.optimum = Optimum
+
+! Optimization parameters
+MaximumAltitudeParameter.name = Nejvz\u0161\u0161í nadmorská vý\u0161ka
+MaximumVelocityParameter.name = Maximální rychlost
+MaximumAccelerationParameter.name = Maximální akcelerace
+StabilityParameter.name = Stabilita
+GroundHitVelocityParameter.name = Rychlost nárazu na zem
+LandingDistanceParameter.name = Pristávací vzdálenost
+TotalFlightTimeParameter.name = Celkový letový cas
+DeploymentVelocityParameter.name = Rychlost pri rozbalení padáku
+
+
+! Compass directions drawn on a compass rose.
+CompassRose.lbl.north = S
+CompassRose.lbl.east  = V
+CompassRose.lbl.south = J
+CompassRose.lbl.west  = Z
+
+! Compass directions with subdirections.  These might not be localized even if the directions on the compass rose are.
+CompassSelectionButton.lbl.N = S
+CompassSelectionButton.lbl.NE = SV
+CompassSelectionButton.lbl.E = V
+CompassSelectionButton.lbl.SE = JV
+CompassSelectionButton.lbl.S = J
+CompassSelectionButton.lbl.SW = JZ
+CompassSelectionButton.lbl.W = Z
+CompassSelectionButton.lbl.NW = SZ
+
+
+SlideShowDialog.btn.next = Dal\u0161í
+SlideShowDialog.btn.prev = Predchozí
+
+SlideShowLinkListener.error.title = Prohlídka programu nebyla nalezena
+SlideShowLinkListener.error.msg = Prominte, vybraná prohlídka nebyla je\u0161te napsána.
+
+GuidedTourSelectionDialog.title = Prohlídky programu
+GuidedTourSelectionDialog.lbl.selectTour = Vyberte prohlídku programu:
+GuidedTourSelectionDialog.lbl.description = Popis prohlídkz:
+GuidedTourSelectionDialog.lbl.length = Pocet slídu:
+GuidedTourSelectionDialog.btn.start = Zacni prohlídku!
+
+
+! Custom Fin BMP Importer
+CustomFinImport.button.label = Importuj z BMP
+CustomFinImport.filter = Bitmapové soubory (*.bmp)
+CustomFinImport.badFinImage = Nevalidní obrázek stabilizátoru. Obrázek musí být cerný a bílý (cerná pro stabilizátor), nesmí se dotýkat zádné strany, krome spodku obrázku, který je podstavou stabilizátoru.
+CustomFinImport.errorLoadingFile = Chyba behem nahrávání souboru: 
+CustomFinImport.errorParsingFile = Chyba behem zpracovávání obrázku stabilizátoru: 
+CustomFinImport.undo = Importovat sadu volno tvarových stabilizátoru
+CustomFinImport.error.title = Chyba behem nahrávání profilu stabilizátoru
+CustomFinImport.error.badimage = Nemohu vyvodit tvar stabilizátoru z obrázku.
+CustomFinImport.description = Obrázek bude zmenen na cernobílý 
+(cerná pro stabilizátor), ujistete se prosím, \u017Ee jste pou\u017Eily cernou barvu na stabilizátor
+a bílou nebo svetlou barvu na pozadí. Stabilizátor 
+se musí dotýkat steny obrázku, která predstavuje uchycení pro stabilizátor.
+
+
+PresetModel.lbl.select = Výber predvolby:
+PresetModel.lbl.database = Z databáze...
+
+
+! Component Preset Chooser Dialog
+ComponentPresetChooserDialog.title = Vyber predvolby komponenty
+ComponentPresetChooserDialog.filter.label = Filtr:
+ComponentPresetChooserDialog.checkbox.filterAftDiameter = Shoda zadního prumeru
+ComponentPresetChooserDialog.checkbox.filterForeDiameter = Shoda predního prumeru
+ComponentPresetChooserDialog.menu.sortAsc = Serad vzestupne
+ComponentPresetChooserDialog.menu.sortDesc = Serad sestupne
+ComponentPresetChooserDialog.menu.units = Jednotky
+ComponentPresetChooserDialog.checkbox.showAllCompatible = Uka\u017E v\u0161e co je kompaktibilní
+table.column.Favorite = Oblíbené
+table.column.Manufacturer = Výrobce
+table.column.PartNo = Císlo soucástky
+table.column.Description = Popis
+table.column.Type = Typ
+table.column.Length = Délka
+table.column.InnerDiameter = Vnitrní prumer
+table.column.OuterDiameter = Vnej\u0161í prumer
+table.column.ShoulderLength = Délka ramene
+table.column.ShoulderDiameter = Prumer ramene
+table.column.ForeShoulderLength = Prední délka ramene
+table.column.ForeShoulderDiameter = Prední prumer ramene
+table.column.ForeOuterDiameter = Prední vnej\u0161í prumer ramene
+table.column.Shape = Tvar
+table.column.Material = Materiál
+table.column.Finish = Dokoncit
+table.column.Thickness = Tlou\u0161tka
+table.column.Filled = Vyplneno
+table.column.Mass = Hmotnost
+
index 0b972fc10b233ed1f97934526d29b54132b5875b..38133ab98d3d3744f899f40f93253c047231a4b8 100644 (file)
@@ -1,4 +1,3 @@
-\r
 #\r
 # German base translation file\r
 #\r
@@ -49,14 +48,15 @@ RocketPanel.FigTypeAct.Sideview = Seitenansicht
 RocketPanel.FigTypeAct.ttip.Sideview = Seitenansicht\r
 RocketPanel.FigTypeAct.Backview = Rückansicht\r
 RocketPanel.FigTypeAct.ttip.Backview = Vorderansicht\r
+RocketPanel.FigViewAct.2D = 2D Ansicht\r
+RocketPanel.FigViewAct.ttip.2D = 2D Ansicht\r
+RocketPanel.FigViewAct.3D = 3D Ansicht\r
+RocketPanel.FigViewAct.ttip.3D = 3D Ansicht\r
 RocketPanel.lbl.Motorcfg = Motorkonfiguration\r
 RocketPanel.lbl.infoMessage = <html>Zum Auswählen klicken&nbsp;&nbsp; Shift+Klick andere auswählen &nbsp;&nbsp; Doppelklick zum Bearbeiten &nbsp;&nbsp; Klicken+Ziehen zum Verschieben\r
 \r
 \r
 ! BasicFrame\r
-BasicFrame.SimpleFileFilter1 = Alle Raketendesigns (*.ork; *.rkt)\r
-BasicFrame.SimpleFileFilter2 = OpenRocket Designs (*.ork)\r
-BasicFrame.SimpleFileFilter3 = RockSim Designs (*.rkt)\r
 BasicFrame.tab.Rocketdesign = Raketendesign\r
 BasicFrame.tab.Flightsim = Flugsimulation\r
 BasicFrame.title.Addnewcomp = Neue Komponente hinzufügen\r
@@ -71,8 +71,8 @@ BasicFrame.WarningDialog.title = Warnungen w
 \r
 \r
 ! General error messages used in multiple contexts\r
-error.fileExists.title = File exists\r
-error.fileExists.desc = File '{filename}' exists.  Do you want to overwrite it?\r
+error.fileExists.title = Datei existiert bereits\r
+error.fileExists.desc = Datei '{filename}' existiert bereits.  Überschreiben?\r
 \r
 error.writing.title = Error writing file\r
 error.writing.desc = An error occurred while writing to the file:\r
@@ -91,6 +91,11 @@ dlg.but.close = Schlie
 \r
 ! General file type names\r
 filetypes.pdf = PDF files\r
+BasicFrame.SimpleFileFilter1 = Alle Raketendesigns (*.ork; *.rkt)\r
+BasicFrame.SimpleFileFilter2 = OpenRocket Designs (*.ork)\r
+BasicFrame.SimpleFileFilter3 = RockSim Designs (*.rkt)\r
+BasicFrame.SimpleFileFilter4 = OpenRocket presets (*.orc)\r
+filetypes.images = Image files\r
 \r
 \r
 ! About Dialog\r
@@ -144,8 +149,8 @@ bugreport.dlg.failedmsg2 = Bitte senden Sie den Bericht manuell an
 bugreport.dlg.failedmsg3 = Fehler beim Versenden des Berichts\r
 bugreport.reportDialog.txt = <html><b>Sie können eine Fehler in OpenRocket mitteilen, indem Sie das unten stehende Formular ausfüllen und abschicken.</b><br>Sie können Fehler mit angehängten Dateien auch auf der Projekt-Website mitteilen.\r
 bugreport.reportDialog.txt2 = Bitte beschreiben Sie kurz, was Sie getan haben, als der Fehler auftrat.</b>\r
-bugreport.dlg.provideDescription = Please provide a description of the bug first.\r
-bugreport.dlg.provideDescription.title = Bug description missing\r
+bugreport.dlg.provideDescription = Bitte geben Sie eine Beschreibung des Fehlers ein.\r
+bugreport.dlg.provideDescription.title = Fehlerbeschreibung fehlt\r
 \r
 \r
 ! Debug log dialog\r
@@ -160,9 +165,9 @@ debuglogdlg.col.Message = Nachricht
 debuglogdlg.lbl.Loglinenbr = Log-Zeilennummer\r
 debuglogdlg.lbl.Time = Zeit:\r
 debuglogdlg.lbl.Level = Level:\r
-debuglogdlg.lbl.Location = Location:\r
-debuglogdlg.lbl.Logmessage = Log message:\r
-debuglogdlg.lbl.Stacktrace = Stack trace:\r
+debuglogdlg.lbl.Location = Ort:\r
+debuglogdlg.lbl.Logmessage = Log-Eintrag:\r
+debuglogdlg.lbl.Stacktrace = Stacktrace:\r
 \r
 \r
 ! Edit Motor configuration dialog\r
@@ -225,6 +230,7 @@ pref.dlg.tab.Miscellaneousoptions = Weiter Optionen
 pref.dlg.lbl.Positiontoinsert = Position, um neue Komponenten einzufügen:\r
 pref.dlg.lbl.Confirmdeletion = Löschen von Simulationen bestätigen\r
 pref.dlg.lbl.User-definedthrust = Benutzerdefinierte Schubkurven:\r
+pref.dlg.lbl.Windspeed = Windgeschwindigkeit\r
 pref.dlg.Allthrustcurvefiles = Alle Schubkurvendateien (*.eng; *.rrse; *.zzip; Verzeichnisse)\r
 pref.dlg.RASPfiles = RASP Schubkurven (*.eng)\r
 pref.dlg.RockSimfiles = RockSim Schubkurven(*.rse)\r
@@ -251,7 +257,7 @@ pref.dlg.lbl.Temperature = Temperatur:
 pref.dlg.lbl.Momentofinertia = Trägheitsmoment:\r
 pref.dlg.lbl.Pressure = Druck:\r
 pref.dlg.lbl.Stability = Stabilität:\r
-pref.dlg.lbl.FlightTime = Flight time:\r
+pref.dlg.lbl.FlightTime = Flugzeit:\r
 pref.dlg.lbl.effect1 = Die Änderungen werden wirksam, wenn Sie das nächste Mal ein Fenster öffnen.\r
 pref.dlg.lbl.Checkingupdates = Prüfe, ob Aktualisierungen verfügbar sind...\r
 pref.dlg.lbl.msg1 = Ein Fehler trat bei der Kommunikation mit dem Server auf.\r
@@ -266,9 +272,9 @@ pref.dlg.PrefBooleanSelector2 = Best
 pref.dlg.Add = Hinzufügen\r
 pref.dlg.DescriptionArea.Adddirectories = Um eigene Schubkurven zu laden, Verzeichnisse, RASP-Motordateien (*.eng), RockSim-Motordateien (*.rse) oder ZIP-Archive mit Semikolon getrennt eingeben. Änderungen werden beim nächsten Neustart von OpenRocket übernommen.\r
 \r
-PreferencesDialog.lbl.language = Interface language:\r
-PreferencesDialog.languages.default = System default\r
-PreferencesDialog.lbl.languageEffect = The language will change the next time you start OpenRocket.\r
+PreferencesDialog.lbl.language = Sprache:\r
+PreferencesDialog.languages.default = Systemeinstellung\r
+PreferencesDialog.lbl.languageEffect = Die Sprache wird beim nächsten Neustart von OpenRocket geändert.\r
 \r
 ! Simulation edit dialog\r
 simedtdlg.but.runsimulation = Simulation starten\r
@@ -280,6 +286,7 @@ simedtdlg.lbl.Simname = Name der Simulation:
 simedtdlg.tab.Launchcond = Startbedingungen\r
 simedtdlg.tab.Simopt = Simulationsoptionen\r
 simedtdlg.tab.Plotdata = Daten plotten\r
+simedtdlg.tab.CustomExpressions = Benutzerdefinierte Ausdrücke\r
 simedtdlg.tab.Exportdata = Daten exportieren\r
 simedtdlg.lbl.Motorcfg = Motorkonfiguration:\r
 simedtdlg.lbl.ttip.Motorcfg = Motorkonfiguration auswählen\r
@@ -306,8 +313,8 @@ simedtdlg.lbl.Launchsite = Startplatz
 simedtdlg.lbl.Latitude = Breitengrad:\r
 simedtdlg.lbl.ttip.Latitude = <html>Der Breitengrad des Startplatzes beeinflusst die wirksame Gravitationskraft.<br>Positive Werte liegen auf der Nordhalbkugel, negative Werte auf der Südhalbkugel.\r
 \r
-simedtdlg.lbl.Longitude = Longitude:\r
-simedtdlg.lbl.ttip.Longitude = <html>Required for weather prediction and elevation models.\r
+simedtdlg.lbl.Longitude = Längengrad:\r
+simedtdlg.lbl.ttip.Longitude = <html>Wird benötigt für Wettervorhersage und Höhenmodelle.\r
 \r
 simedtdlg.lbl.Altitude = Höhe:\r
 simedtdlg.lbl.ttip.Altitude = <html>Die Höhe des Startplatzes über Meeresniveau.<br>Die Höhe des Startplatzes beeinflusst die Position der Rakete im atmosphärischen Modell.\r
@@ -327,8 +334,8 @@ simedtdlg.lbl.ExtBarrowman = Barrowman (erweitert)
 simedtdlg.lbl.Simmethod = Simulationsmethode:\r
 simedtdlg.lbl.ttip.Simmethod1 = <html>Der Sechs-Freiheitsgradsimulator erlaubt der Rakete völlige Bewegungsfreiheit während des Fluges.<br>\r
 simedtdlg.lbl.ttip.Simmethod2 = Das Integrieren wird nach dem numerischen Runge-Kutta-Verfahren 4. Ordnung durchgeführt.\r
-simedtdlg.lbl.GeodeticMethod = Geodetic calculations:\r
-simedtdlg.lbl.ttip.GeodeticMethodTip = Relate to the calculation of coordinates on the earth.  This also enables coriolis effect computations.\r
+simedtdlg.lbl.GeodeticMethod = Geodätische Berechnungen:\r
+simedtdlg.lbl.ttip.GeodeticMethodTip = Berechnung als Koordinaten auf der Erdkugel. Dies ermöglich die Berechnung von Coriolis-Effekten.\r
 simedtdlg.lbl.Timestep = Zeitschritt:\r
 simedtdlg.lbl.ttip.Timestep1 = <html>Die Zeit zwischen den Simulationsschritten.<br>Kleinere Schritte ergeben genauere Ergebnisse, die Simulationen dauern aber länger.<br>\r
 simedtdlg.lbl.ttip.Timestep2 = Die Berechnung der Simulation mit dem Verfahren 4. Ordnung liefert gute Ergebnisse mit Zeitschritten von\r
@@ -350,12 +357,12 @@ simedtdlg.IntensityDesc.High = Hoch
 simedtdlg.IntensityDesc.Veryhigh = Sehr hoch\r
 simedtdlg.IntensityDesc.Extreme = Extrem\r
 \r
-GeodeticComputationStrategy.none.name = None\r
-GeodeticComputationStrategy.none.desc = Perform no geodetic computations.\r
-GeodeticComputationStrategy.spherical.name = Spherical approximation\r
-GeodeticComputationStrategy.spherical.desc = <html>Perform geodetic computations assuming a spherical Earth.<br>This is sufficiently accurate for almost all purposes.\r
-GeodeticComputationStrategy.wgs84.name = WGS84 ellipsoid\r
-GeodeticComputationStrategy.wgs84.desc = <html>Perform geodetic computations on the WGS84 reference ellipsoid using Vincenty's method.<br>Slower and unnecessary in most cases.\r
+GeodeticComputationStrategy.flat.name = Flache Erde\r
+GeodeticComputationStrategy.flat.desc = Führt keine geodätischen Berechnungen durch.\r
+GeodeticComputationStrategy.spherical.name = Näherung als Kugel\r
+GeodeticComputationStrategy.spherical.desc = <html>Führt geodätische Berechnungen unter der Annahme einer kugelförmigen Erde durch.<br>Dies ist für die meisten Anwendungen hinreichend genau.\r
+GeodeticComputationStrategy.wgs84.name = WGS84 Ellipsoid\r
+GeodeticComputationStrategy.wgs84.desc = <html>Führt geodätische Berechnungen auf Basis des WGS84 Referenz-Ellipsoiden mit Hilfe der Vincenty-Methode durch.<br>Langsamer und in den meisten Fällen nicht benötigt.\r
 \r
 \r
 \r
@@ -377,6 +384,8 @@ simpanel.dlg.lbl.DeleteSim2 = <html><i>Diese Aktion kann nicht r
 simpanel.dlg.lbl.DeleteSim3 = Simulationen löschen\r
 simpanel.col.Name = Name der Simulation:\r
 simpanel.col.Motors = Motoren\r
+simpanel.col.Velocityoffrod = Geschwindigkeit am Ende der Rampe\r
+simpanel.col.Velocityatdeploy = Geschwindigkeit bei der Auslösung\r
 simpanel.col.Apogee = Apogäum\r
 simpanel.col.Maxvelocity = max. Geschwindigkeit\r
 simpanel.col.Maxacceleration = max. Beschleunigung\r
@@ -400,6 +409,8 @@ SimuRunDlg.msg.unknownerror1 = W
 SimuRunDlg.msg.unknownerror2 = Das Programm könnte instabil sein, speichern Sie Ihr Design und starten Sie OpenRocket neu!\r
 \r
 \r
+RK4SimulationStepper.error.valuesTooLarge = Simulationswerte überschreiten die Grenzen.  Kürzere Zeitschritte versuchen.\r
+\r
 \r
 ! SimulationExportPanel\r
 SimExpPan.desc = Komma getrennte Werte (*.csv)\r
@@ -430,10 +441,67 @@ SimExpPan.Col.Variable = Variable
 SimExpPan.Col.Unit = Einheit\r
 \r
 \r
-CsvOptionPanel.separator.space = SPACE\r
+CsvOptionPanel.separator.space = LEER\r
 CsvOptionPanel.separator.tab = TAB\r
 \r
 \r
+! Custom expression general stuff\r
+customExpression.Name = Name\r
+customExpression.Symbol = Symbol\r
+customExpression.Expression = Ausdruck\r
+customExpression.Units = Einheit\r
+customExpression.Operator = Operator\r
+customExpression.Description = Beschreibung\r
+\r
+! Custom expression panel\r
+customExpressionPanel.but.NewExpression = Neuer Ausdruck\r
+customExpressionPanel.lbl.UpdateNote = Die Simulation muss erst ausgeführt werden, bevor die Daten zum Plotten verfügbar sind.\r
+customExpressionPanel.lbl.CalcNote = Ausdrücke werden in der angezeigten Reihenfolge berechnet.\r
+customExpressionPanel.lbl.CustomExpressions = Benutzerdefinierte Ausdrücke:\r
+customExpression.Units.but.ttip.Remove = Diesen Ausdruck entfernen\r
+customExpression.Units.but.ttip.Edit = Diesen Ausdruck bearbeiten\r
+customExpression.Units.but.ttip.MoveUp = Ausdruck in der Berechnungsreihenfolge nach oben schieben\r
+customExpression.Units.but.ttip.MoveDown = Ausdruck in der Berechnungsreihenfolge nach unten schieben\r
+\r
+! Custom expression builder window\r
+ExpressionBuilderDialog.title = Ausddrucksgenerator\r
+ExpressionBuilderDialog.InsertVariable = Variable einfügen\r
+ExpressionBuilderDialog.InsertOperator = Operator einfügen\r
+ExpressionBuilderDialog.led.ttip.Name = Name darf noch nicht benutzt worden sein.\r
+ExpressionBuilderDialog.led.ttip.Symbol = Symbol darf noch nicht benutzt worden sein.\r
+ExpressionBuilderDialog.led.ttip.Expression = Ausdruck darf nur bekannte Symbole und Operatoren verwenden\r
+ExpressionBuilderDialog.CopyToOtherSimulations = In andere Simualtionen kopieren\r
+ExpressionBuilderDialog.CopyToOtherSimulations.ttip = <html>Erstellt eine Kopie dieses Ausdrucks in eine andere Simulation in diesem Dokument.<br>Überschreibt oder ändert keine bereits existierenden Ausdrücke in anderen Simulationen.\r
+\r
+! Custom expression variable selector\r
+CustomVariableSelector.title = Variablen-Auswahl\r
+\r
+! Custom operator selector\r
+CustomOperatorSelector.title = Operator-Auswahl\r
+\r
+! Operators\r
+Operator.plus = Addition\r
+Operator.minus = Subtraktion\r
+Operator.star = Multiplikation\r
+Operator.div = Divison\r
+Operator.mod = Modulo\r
+Operator.pow = Potenzieren\r
+Operator.abs = Absolutwert\r
+Operator.ceil = aufrunden (auf die nächste Ganzzahl\r
+Operator.floor = abrunden (auf die nächste Ganzzahl\r
+Operator.sqrt = Quadratwurzel\r
+Operator.cbrt = Kubikwurzel\r
+Operator.exp = Euler-Zahl hoch Wert (e^x)\r
+Operator.ln = Natürlicher Logarithmus\r
+Operator.sin = Sinus\r
+Operator.cos = Cosinus\r
+Operator.tan = Tangens\r
+Operator.asin = Arcussinus\r
+Operator.acos = Arcuscosinus\r
+Operator.atan = Arcustangens\r
+Operator.hsin = Sinus hyperbolicus\r
+Operator.hcos = Cosinus hyperbolicus\r
+Operator.htan = Tangens hyperbolicus\r
 \r
 ! MotorPlot\r
 MotorPlot.title.Motorplot = Motorkurve\r
@@ -447,8 +515,6 @@ MotorPlot.txt.Type = Typ:
 MotorPlot.txt.Delays = Verzögerungen:\r
 MotorPlot.txt.Comment = Kommentare:\n\r
 \r
-\r
-\r
 ! Simulation plot panel\r
 simplotpanel.lbl.Presetplotconf = Plotparameter setzen\r
 simplotpanel.lbl.Xaxistype = X-Achse:\r
@@ -468,6 +534,8 @@ simplotpanel.AUTO_NAME = Auto
 simplotpanel.LEFT_NAME = Links\r
 simplotpanel.RIGHT_NAME = Rechts\r
 simplotpanel.CUSTOM = Benutzerdefiniert\r
+SimulationPlotPanel.error.noPlotSelected = Bitte eine oder mehr Variablen zum Zeichnen der y-Achse hinzufügen..\r
+SimulationPlotPanel.error.noPlotSelected.title = Nichts zu zeichnen\r
 \r
 ! Component add buttons\r
 compaddbuttons.Bodycompandfinsets = Körperteile und Leitwerke\r
@@ -528,7 +596,7 @@ componentanalysisdlg.println.settingnam = SETTING NAN VALUES
 componentanalysisdlg.lbl.reflenght = Referenzlänge:\r
 componentanalysisdlg.lbl.refarea = Referenzfläche:\r
 !componentanalysisdlg.But.close =Close\r
-componentanalysisdlg.TabStability.Col.Component = Component\r
+componentanalysisdlg.TabStability.Col.Component = Komponente\r
 \r
 ! Custom Material dialog\r
 custmatdlg.title.Custommaterial = Benutzerdefiniertes Material\r
@@ -586,6 +654,9 @@ FinSetConfig.lbl.Tabposition = Position:
 FinSetConfig.ttip.Tabposition = Position des Leitwerks.\r
 FinSetConfig.lbl.relativeto = relativ zu\r
 \r
+!FinMarkingGuide\r
+FinMarkingGuide.lbl.Front = Vorne\r
+\r
 ! MotorDatabaseLoadingDialog\r
 MotorDbLoadDlg.title = Lade Motoren\r
 MotorDbLoadDlg.Loadingmotors = Lade Motoren...\r
@@ -662,6 +733,13 @@ ComponentCfgDlg.configuration = Konfiguration
 ComponentCfgDlg.configuration1 =\r
 ComponentCfgDlg.Modify = Verändern\r
 \r
+!StageConfig\r
+StageConfig.tab.Separation = Stufentrennung\r
+StageConfig.tab.Separation.ttip = Stufentrennungs-Optionen\r
+StageConfig.separation.lbl.title = Auswählen, wenn diese Stufe getrennt wird:\r
+StageConfig.separation.lbl.plus = plus\r
+StageConfig.separation.lbl.seconds = Sekunden\r
+\r
 !EllipticalFinSetConfig\r
 EllipticalFinSetCfg.Nbroffins = Anzahl der Leitwerke\r
 EllipticalFinSetCfg.Rotation = Rotation:\r
@@ -689,11 +767,12 @@ FreeformFinSetCfg.lbl.Posrelativeto = Position relativ zu:
 FreeformFinSetCfg.lbl.plus = plus\r
 FreeformFinSetCfg.lbl.FincrossSection = Querschnitt:\r
 FreeformFinSetCfg.lbl.Thickness = Wandstärke:\r
-! doubleClick1 + 2 form the message "Double-click to edit", split approximately at the middle\r
-FreeformFinSetConfig.lbl.doubleClick1 = Double-click\r
-FreeformFinSetConfig.lbl.doubleClick2 = to edit\r
-FreeformFinSetConfig.lbl.clickDrag = Click+drag: Add and move points\r
-FreeformFinSetConfig.lbl.ctrlClick = Ctrl+click: Remove point\r
+! doubleClick1 + 2 form the message "Doppelklick zum Bearbeiten", ungefähr in der Mitte teilen\r
+FreeformFinSetConfig.lbl.doubleClick1 = Doppelklick\r
+FreeformFinSetConfig.lbl.doubleClick2 = zum Bearbeiten\r
+FreeformFinSetConfig.lbl.clickDrag = Klicken+Ziehen: Punkte bewegen und hinzufügen\r
+FreeformFinSetConfig.lbl.ctrlClick = Strg+Klick: Punkt löschen\r
+FreeformFinSetConfig.lbl.scaleFin = Leitwerk skalieren\r
 \r
 \r
 !InnerTubeConfig\r
@@ -728,6 +807,7 @@ LaunchLugCfg.tab.Generalprop = Allgemeine Eigenschaften
 \r
 ! MassComponentConfig\r
 MassComponentCfg.lbl.Mass = Masse\r
+MassComponentCfg.lbl.Density = Geschätzte Dichte:\r
 MassComponentCfg.lbl.Length = Länge\r
 MassComponentCfg.lbl.Diameter = Durchmesser\r
 MassComponentCfg.lbl.PosRelativeto = Position relativ zu:\r
@@ -947,10 +1027,10 @@ PlotDialog.lbl.Chart = Klicken+ziehen: runter+rechts um hinein zu zoomen, hoch+l
 # FIXME: Rename the description keys \r
 \r
 main.menu.file = Datei\r
-main.menu.file.desc = File-handling related tasks\r
+main.menu.file.desc = Dateiaufgaben\r
 main.menu.file.new = Neu\r
-main.menu.file.new.desc = Create a new rocket design\r
-main.menu.file.open = Öffnen..\r
+main.menu.file.new.desc = Ein neues Raketendesign erstellen\r
+main.menu.file.open = Öffnen...\r
 BasicFrame.item.Openrocketdesign = Raketendesign öffnen\r
 main.menu.file.openExample = Beispiel öffnen..\r
 BasicFrame.item.Openexamplerocketdesign = Beispieldesign öffnen\r
@@ -968,35 +1048,37 @@ BasicFrame.item.Quitprogram = Programm beenden
 main.menu.edit = Bearbeiten\r
 BasicFrame.menu.Rocketedt = Rakete bearbeiten\r
 main.menu.edit.undo = Rückgängig\r
-main.menu.edit.undo.desc = Undo the previous operation\r
+main.menu.edit.undo.desc = Die letze Aktion rückgängig machen\r
 main.menu.edit.redo = Wiederholen\r
-main.menu.edit.redo.desc = Redo the previously undone operation\r
+main.menu.edit.redo.desc = Die letzte Aktion wiederholen\r
 main.menu.edit.cut = Ausschneiden\r
 main.menu.edit.copy = Kopieren\r
 main.menu.edit.paste = Einfügen\r
 main.menu.edit.delete = Löschen\r
-main.menu.edit.resize = Scale...\r
-main.menu.edit.resize.desc = Scale parts of the rocket design\r
+main.menu.edit.resize = Skalieren...\r
+main.menu.edit.resize.desc = Teile des Raketendesigns skalieren\r
 main.menu.edit.preferences = Einstellungen\r
-main.menu.edit.preferences.desc = Setup the application preferences\r
+main.menu.edit.preferences.desc = Einstellungen der Anwenung ändern\r
 \r
 main.menu.analyze = Analysieren\r
-main.menu.analyze.desc = Rocket analysis\r
+main.menu.analyze.desc = Rakete analysieren\r
 main.menu.analyze.componentAnalysis = Komponente analysieren\r
-main.menu.analyze.componentAnalysis.desc = Analyze the rocket components separately\r
+main.menu.analyze.componentAnalysis.desc = Komponenten der Rakete einzeln analysieren\r
 main.menu.analyze.optimization = Rocket optimization\r
 main.menu.analyze.optimization.desc = General rocket design optimization\r
 \r
 main.menu.help = Hilfe\r
-main.menu.help.desc = Information about OpenRocket\r
+main.menu.help.desc = Informationen über OpenRocket\r
+main.menu.help.tours = Geführte Tour\r
+main.menu.help.tours.desc = Eine geführte Tour durch OpenRocket\r
 main.menu.help.license = Lizenz\r
-main.menu.help.license.desc = OpenRocket license information\r
+main.menu.help.license.desc = OpenRocket Lizenzinformationen\r
 main.menu.help.bugReport = Fehlerbericht\r
-main.menu.help.bugReport.desc = Information about reporting bugs in OpenRocket\r
+main.menu.help.bugReport.desc = Informationen über melden von Fehlern in OpenRocket\r
 main.menu.help.debugLog = Debug-Log\r
-main.menu.help.debugLog.desc = View the OpenRocket debug log\r
+main.menu.help.debugLog.desc = OpenRocket Debuglog ansehen\r
 main.menu.help.about = Über\r
-main.menu.help.about.desc = Copyright details about OpenRocket\r
+main.menu.help.about.desc = Copyright-Details über OpenRocket\r
 \r
 main.menu.debug = Debug\r
 main.menu.debug.whatisthismenu = Was macht diese Menü?\r
@@ -1008,48 +1090,53 @@ main.menu.debug.createtestrocket = Eine Testrakete erstellen
 \r
 ! Material database\r
 ! BULK_MATERIAL\r
-Databases.materials.Acrylic = Acryl\r
-Databases.materials.Balsa = Balsa\r
-Databases.materials.Birch = Birke\r
-Databases.materials.Cardboard = Karton\r
-Databases.materials.Carbonfiber = Kohlefaser\r
-Databases.materials.Cork = Kork\r
-Databases.materials.DepronXPS = Depron (XPS)\r
-Databases.materials.Fiberglass = Glasfaser\r
-Databases.materials.Kraftphenolic = Pertinax\r
-Databases.materials.Maple = Ahorn\r
-Databases.materials.Paperoffice = Papier (Büro)\r
-Databases.materials.Pine = Kiefer\r
-Databases.materials.Plywoodbirch = Sperrholz (Birke)\r
-Databases.materials.PolycarbonateLexan = Polycarbonat (Lexan)\r
-Databases.materials.Polystyrene = Polystyrène\r
-Databases.materials.PVC = PVC\r
-Databases.materials.Spruce = Fichte\r
-Databases.materials.StyrofoamgenericEPS = Styropor (EPS)\r
-Databases.materials.StyrofoamBluefoamXPS = Styrodur (XPS)\r
-Databases.materials.Quantumtubing = Quantum tubing\r
-Databases.materials.BlueTube = Blue tube\r
+material.acrylic = Acryl\r
+material.aluminum = Aluminum\r
+material.balsa = Balsa\r
+material.basswood = Linde\r
+material.birch = Birke\r
+material.brass = Messing\r
+material.cardboard = Karton\r
+material.carbon_fiber = Kohlefaser\r
+material.cork = Kork\r
+material.depron_xps = Depron (XPS)\r
+material.fiberglass = Glasfaser\r
+material.kraft_phenolic = Pertinax\r
+material.maple = Ahorn\r
+material.paper_office = Papier (Büro)\r
+material.pine = Kiefer\r
+material.plywood_birch = Sperrholz (Birke)\r
+material.polycarbonate_lexan = Polycarbonat (Lexan)\r
+material.polystyrene = Polystyrène\r
+material.pvc = PVC\r
+material.spruce = Fichte\r
+material.steel = Stahl\r
+material.styrofoam_generic_eps = Styropor (EPS)\r
+material.styrofoam_blue_foam_xps = Styrodur (XPS)\r
+material.titanium = Titan\r
+material.quantum_tubing = Quantum-Röhren\r
+material.blue_tube = 'Blue tube'-Röhren\r
 !SURFACE_MATERIAL\r
-Databases.materials.Ripstopnylon = Ripstop Nylon\r
-Databases.materials.Mylar = Mylar\r
-Databases.materials.Polyethylenethin = Polyethylen (dünn)\r
-Databases.materials.Polyethyleneheavy = Polyethylen (schwer)\r
-Databases.materials.Silk = Seide\r
-Databases.materials.Paperoffice = Papier (Büro)\r
-Databases.materials.Cellophane = Zellophan\r
-Databases.materials.Crepepaper = Krepppapier\r
+material.ripstop_nylon = Ripstop Nylon\r
+material.mylar = Mylar\r
+material.polyethylene_thin = Polyethylen (dünn)\r
+material.polyethylene_heavy = Polyethylen (schwer)\r
+material.silk = Seide\r
+material.paper_office = Papier (Büro)\r
+material.cellophane = Zellophan\r
+material.crepe_paper = Krepppapier\r
 ! LINE_MATERIAL\r
-Databases.materials.Threadheavy-duty = Faden (stark)\r
-Databases.materials.Elasticcordround2mm = Elastikband (rund, 2mm, 1/16 in)\r
-Databases.materials.Elasticcordflat6mm = Elastikband (flach, 6mm, 1/4 in)\r
-Databases.materials.Elasticcordflat12mm = Elastikband (flach, 12mm, 1/2 in)\r
-Databases.materials.Elasticcordflat19mm = Elastikband (flach, 19mm, 3/4 in)\r
-Databases.materials.Elasticcordflat25mm = Elastikband (flach, 25mm, 1 in)\r
-Databases.materials.Braidednylon2mm = Nylonflachband (2 mm, 1/16 in)\r
-Databases.materials.Braidednylon3mm = Nylonflachband (3 mm, 1/8 in)\r
-Databases.materials.Tubularnylon11mm = Tubular Nylon (11 mm, 7/16 in)\r
-Databases.materials.Tubularnylon14mm = Tubular Nylon (14 mm, 9/16 in)\r
-Databases.materials.Tubularnylon25mm = Tubular Nylon (25 mm, 1 in)\r
+material.thread_heavy_duty = Faden (stark)\r
+material.elastic_cord_round_2_mm_1_16_in = Elastikband (rund, 2mm, 1/16 in)\r
+material.elastic_cord_flat_6_mm_1_4_in = Elastikband (flach, 6mm, 1/4 in)\r
+material.elastic_cord_flat_12_mm_1_2_in = Elastikband (flach, 12mm, 1/2 in)\r
+material.elastic_cord_flat_19_mm_3_4_in = Elastikband (flach, 19mm, 3/4 in)\r
+material.elastic_cord_flat_25_mm_1_in = Elastikband (flach, 25mm, 1 in)\r
+material.braided_nylon_2_mm_1_16_in = Nylonflachband (2 mm, 1/16 in)\r
+material.braided_nylon_3_mm_1_8_in = Nylonflachband (3 mm, 1/8 in)\r
+material.tubular_nylon_11_mm_7_16_in = Tubular Nylon (11 mm, 7/16 in)\r
+material.tubular_nylon_14_mm_9_16_in = Tubular Nylon (14 mm, 9/16 in)\r
+material.tubular_nylon_25_mm_1_in = Tubular Nylon (25 mm, 1 in)\r
 \r
 ! ExternalComponent\r
 ExternalComponent.Rough = Rau\r
@@ -1074,9 +1161,9 @@ Shape.Ogive.desc1 = Eine ogive Spitze hat das Profil eines Kreissegments. Der Fo
 Shape.Ogive.desc2 = Eine ogive Spitze hat das Profil eines Kreissegments. Der Formparamter 1 erzeugt eine <b>tangentiale Ogive</b>, die einen weichen Übergang zum Körperrohr am hinteren Ende hat, Werte kleiner 1 erzeugen eine <b>sekante Ogive<b>.\r
 Shape.Ellipsoid = Ellipsoid\r
 Shape.Ellipsoid.desc1 = Eine ellipsoide Spitze hat ein Profil einer Halbellipse mit der einer Hauptachsenlänge von 2&times;<i>Länge</i> und <i>Durchmesser</i> \r
-Shape.Ellipsoid.desc2 = An ellipsoidal transition has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the transition is not clipped, then the profile is extended at the center by the corresponding radius.             \r
+Shape.Ellipsoid.desc2 = Ein ellipsoider Übergang hat das Profil einer Halbellipse mit einer Hauptachsenlänge von 2&times;<i>Länge</i> und <i>Durchmesser</i>.  If the transition is not clipped, then the profile is extended at the center by the corresponding radius.               \r
 Shape.Powerseries = Power series\r
-Shape.Powerseries.desc1 = A power series nose cone has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 this is a <b>\u00BD-power</b> or <b>parabolic</b> nose cone, for <i>k</i>=0.75 a <b>\u00BE-power</b>, and for <i>k</i>=1 a <b>conical</b> nose cone.\r
+Shape.Powerseries.desc1 = Eine Potenzreihenspitze hat das Profil  <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Länge</i>)<sup><i>k</i></sup> wobei <i>k</i> der Formparameter ist.  Für <i>k</i>=0.5 ist dies eine <b>parabolische</b> Spitze, für <i>k</i>=0.75 eine <b>^\u00BE</b>, und für <i>k</i>=1 eine <b>konische</b> Spitze.\r
 Shape.Powerseries.desc2 = A power series transition has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i>=0.5 the transition is <b>\u00BD-power</b> or <b>parabolic</b>, for <i>k</i>=0.75 a <b>\u00BE-power</b>, and for <i>k</i>=1 <b>conical</b>.\r
 Shape.Parabolicseries = Parabolic series\r
 Shape.Parabolicseries.desc1 = A parabolic series nose cone has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.\r
@@ -1101,6 +1188,14 @@ NoseCone.NoseCone = Spitze
 Transition.Transition = Übergang\r
 !Stage\r
 Stage.Stage = Stufe\r
+\r
+Stage.SeparationEvent.UPPER_IGNITION = Oberstufen-Motorzündung\r
+Stage.SeparationEvent.IGNITION = Zündung der aktuellen Stufe\r
+Stage.SeparationEvent.BURNOUT = Brennschluss der aktuelle Stufe\r
+Stage.SeparationEvent.EJECTION = Ausstoßladung der aktuellen Stufe\r
+Stage.SeparationEvent.LAUNCH = Start\r
+Stage.SeparationEvent.NEVER = Nie\r
+\r
 ! BodyTube\r
 BodyTube.BodyTube = Körperrohr\r
 ! TubeCoupler\r
@@ -1158,6 +1253,8 @@ RecoveryDevice.DeployEvent.LAUNCH = Start (plus NN Sekunden)
 RecoveryDevice.DeployEvent.EJECTION = Erste Ausstoßladung dieser Stufe\r
 RecoveryDevice.DeployEvent.APOGEE = Apogäum\r
 RecoveryDevice.DeployEvent.ALTITUDE = Spezifische Höhe während der Landephase\r
+RecoveryDevice.DeployEvent.CURRENT_STAGE_SEPARATION = Trennung der aktuellen Stufe\r
+RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION = Unterstufen-Trennung\r
 RecoveryDevice.DeployEvent.NEVER = Nie\r
 \r
 ! FlightEvent\r
@@ -1259,23 +1356,23 @@ FlightDataType.TYPE_AIR_PRESSURE = Luftdruck
 FlightDataType.TYPE_SPEED_OF_SOUND = Schallgeschwindigkeit\r
 FlightDataType.TYPE_TIME_STEP = Simulationsintervall\r
 FlightDataType.TYPE_COMPUTATION_TIME = Berechnnungszeit\r
-FlightDataType.TYPE_LATITUDE = Latitude\r
-FlightDataType.TYPE_LONGITUDE = Longitude\r
-FlightDataType.TYPE_CORIOLIS_ACCELERATION = Coriolis acceleration\r
+FlightDataType.TYPE_LATITUDE = Breitengrad\r
+FlightDataType.TYPE_LONGITUDE = Längengrad\r
+FlightDataType.TYPE_CORIOLIS_ACCELERATION = Coriolis-Beschleunigung\r
 \r
 ! PlotConfiguration\r
 PlotConfiguration.Verticalmotion = Vertikale Bewegung über Zeit\r
 PlotConfiguration.Totalmotion = Gesamte Bewegung über Zeit\r
-PlotConfiguration.Flightside = Flight side profile\r
+PlotConfiguration.Flightside = Flug Seitenprofil\r
 PlotConfiguration.Stability = Stabilität über Zeit\r
-PlotConfiguration.Dragcoef = Drag coefficients vs. Mach number\r
-PlotConfiguration.Rollcharacteristics = Roll characteristics\r
-PlotConfiguration.Angleofattack = Angle of attack and orientation vs. time\r
+PlotConfiguration.Dragcoef = Luftwiderstandskoeffizient über Mach-Zahl\r
+PlotConfiguration.Rollcharacteristics = Roll-Charakteristik\r
+PlotConfiguration.Angleofattack = Angriffswinkel und Orientierung über Zeit\r
 PlotConfiguration.Simulationtime = Simulationszeitschritt und Berechnungszeit\r
 \r
 ! Warning\r
-Warning.LargeAOA.str1 = Large angle of attack encountered.\r
-Warning.LargeAOA.str2 = Large angle of attack encountered (\r
+Warning.LargeAOA.str1 = Großer Angriffswinkel gefunden\r
+Warning.LargeAOA.str2 = Großer Angriffswinkel gefunden (\r
 Warning.DISCONTINUITY = Unstetigkeit im Raketendurchmesser\r
 Warning.THICK_FIN = Dicke Leitwerke können nicht präzise modelliert werden.\r
 Warning.JAGGED_EDGED_FIN = Gezackte Ecken in Leitwerken können unpräzise Ergebnisse liefern.\r
@@ -1285,244 +1382,303 @@ Warning.FILE_INVALID_PARAMETER = Ignoriere ung
 \r
 \r
 ! Scale dialog\r
-ScaleDialog.lbl.scaleRocket = Entire rocket\r
-ScaleDialog.lbl.scaleSubselection = Selection and all subcomponents\r
-ScaleDialog.lbl.scaleSelection = Only selected component\r
-ScaleDialog.title = Scale design\r
-ScaleDialog.lbl.scale = Scale:\r
-ScaleDialog.lbl.scale.ttip = Select whether to scale the entire design or only the selected component\r
-ScaleDialog.lbl.scaling = Scaling to apply:\r
-ScaleDialog.lbl.scaling.ttip = Resulting size, values above 100% grow and values below 100% shrink the design.\r
+ScaleDialog.lbl.scaleRocket = Gesamte Rakete\r
+ScaleDialog.lbl.scaleSubselection = Auswahl und alle Unterkomponenten\r
+ScaleDialog.lbl.scaleSelection = Nur ausgewählte Komponenten\r
+ScaleDialog.title = Design skalieren\r
+ScaleDialog.lbl.scale = Skalieren:\r
+ScaleDialog.lbl.scale.ttip = Auswählen, ob das gesamte Design oder nur ausgeählte Komponenten skaliert werden sollen\r
+ScaleDialog.lbl.scaling = Skalierungsfaktor:\r
+ScaleDialog.lbl.scaling.ttip = Resultierende Größe, Werte über 100% lassen das Design wachsen, Werte kleiner als 100% lassen das Design schrumpfen.\r
 ! The scaleFrom/scaleTo pair creates a phrase "Scale from [...] to [...]"\r
-ScaleDialog.lbl.scaleFrom = Scale from\r
-ScaleDialog.lbl.scaleTo = to\r
-ScaleDialog.lbl.scaleFromTo.ttip = Define the scaling based on an original and resulting length.\r
-ScaleDialog.checkbox.scaleMass = Update explicit mass values\r
-ScaleDialog.checkbox.scaleMass.ttip = Scale mass component and override mass values by the cube of the scaling factor\r
-ScaleDialog.button.scale = Scale\r
-ScaleDialog.undo.scaleRocket = Scale rocket\r
-ScaleDialog.undo.scaleComponent = Scale component\r
-ScaleDialog.undo.scaleComponents = Scale components\r
+ScaleDialog.lbl.scaleFrom = Skalieren von\r
+ScaleDialog.lbl.scaleTo = nach\r
+ScaleDialog.lbl.scaleFromTo.ttip = Definiert den Skalierungsfaktor basierend auf der Original- und der resultierenden Länge.\r
+ScaleDialog.checkbox.scaleMass = Explizite Massen skalieren\r
+ScaleDialog.checkbox.scaleMass.ttip = Masseobjekte und überschriebene Massen werden in der dirtten Potenz mit dem Skalierungsfaktor skaliert.\r
+ScaleDialog.button.scale = Skalieren\r
+ScaleDialog.undo.scaleRocket = Rakete skalieren\r
+ScaleDialog.undo.scaleComponent = Komponente skalieren\r
+ScaleDialog.undo.scaleComponents = Komponenten skalieren\r
 \r
 !icons\r
-Icons.Undo = Undo\r
-Icons.Redo = Redo\r
+Icons.Undo = Rückgängig\r
+Icons.Redo = Wiederholen\r
 \r
-OpenRocketPrintable.Partsdetail = Parts detail\r
-OpenRocketPrintable.Fintemplates = Fin templates\r
-OpenRocketPrintable.DesignReport = Design Report\r
+OpenRocketPrintable.Partsdetail = Komponentendetails\r
+OpenRocketPrintable.Fintemplates = Leitwerksschablonen\r
+OpenRocketPrintable.Transitiontemplates = Übergangsschablonen\r
+OpenRocketPrintable.Noseconetemplates = Spitzenschablonen\r
+OpenRocketPrintable.Finmarkingguide = Leitwerksmarkierungen\r
+OpenRocketPrintable.DesignReport = Design-Bericht\r
+OpenRocketPrintable.Centeringringtemplates = Zentrierring-Schablonen\r
 \r
-OpenRocketDocument.Redo = Redo\r
-OpenRocketDocument.Undo = Undo\r
+OpenRocketDocument.Redo = Rückgängig\r
+OpenRocketDocument.Undo = Wiederholen\r
 \r
 !EllipticalFinSet\r
-EllipticalFinSet.Ellipticalfinset = Elliptical fin set\r
+EllipticalFinSet.Ellipticalfinset = Elliptische Leitwerke\r
 \r
 ! Optimization\r
 \r
 ! Modifiers\r
 \r
-optimization.modifier.nosecone.length = Length\r
-optimization.modifier.nosecone.length.desc = Optimize the nose cone length.\r
-optimization.modifier.nosecone.diameter = Diameter\r
-optimization.modifier.nosecone.diameter.desc = Optimize the nose cone base diameter.\r
-optimization.modifier.nosecone.thickness = Thickness\r
-optimization.modifier.nosecone.thickness.desc = Optimize the nose cone wall thickness.\r
-optimization.modifier.nosecone.shapeparameter = Shape parameter\r
-optimization.modifier.nosecone.shapeparameter.desc = Optimize the nose cone shape parameter.\r
-\r
-optimization.modifier.transition.length = Length\r
-optimization.modifier.transition.length.desc = Optimize the transition length.\r
-optimization.modifier.transition.forediameter = Fore diameter\r
-optimization.modifier.transition.forediameter.desc = Optimize the transition fore diameter.\r
-optimization.modifier.transition.aftdiameter = Aft diameter\r
-optimization.modifier.transition.aftdiameter.desc = Optimize the transition aft diameter.\r
-optimization.modifier.transition.thickness = Thickness\r
-optimization.modifier.transition.thickness.desc = Optimize the transition wall thickness.\r
-optimization.modifier.transition.shapeparameter = Shape parameter\r
-optimization.modifier.transition.shapeparameter.desc = Optimize the transition shape parameter.\r
-\r
-optimization.modifier.bodytube.length = Length\r
-optimization.modifier.bodytube.length.desc = Optimize the body tube length.\r
-optimization.modifier.bodytube.outerDiameter = Outer diameter\r
-optimization.modifier.bodytube.outerDiameter.desc = Optimize the body tube outer diameter while maintaining the wall thickness.\r
-optimization.modifier.bodytube.thickness = Thickness\r
-optimization.modifier.bodytube.thickness.desc = Optimize the body tube wall thickness.\r
-\r
-optimization.modifier.trapezoidfinset.rootChord = Root chord\r
-optimization.modifier.trapezoidfinset.rootChord.desc = Optimize the root chord length of the fin set (length of fin at the rocket body).\r
-optimization.modifier.trapezoidfinset.tipChord = Tip chord\r
-optimization.modifier.trapezoidfinset.tipChord.desc = Optimize the tip chord length of the fin set (length of fin at outer edge).\r
-optimization.modifier.trapezoidfinset.sweep  = Sweep\r
-optimization.modifier.trapezoidfinset.sweep.desc = Optimize the sweep of the fin set (distance that the leading edge sweeps backwards).\r
-optimization.modifier.trapezoidfinset.height = Height\r
-optimization.modifier.trapezoidfinset.height.desc = Optimize the height (semi-span) of the fin set.\r
-\r
-optimization.modifier.ellipticalfinset.length = Root chord\r
-optimization.modifier.ellipticalfinset.length.desc = Optimize the root chord length of the fin set.\r
-optimization.modifier.ellipticalfinset.height = Height\r
-optimization.modifier.ellipticalfinset.height.desc = Optimize the height (semi-span) of the fin set.\r
-\r
-optimization.modifier.finset.cant = Cant angle\r
-optimization.modifier.finset.cant.desc = Optimize the cant angle of the fin set.\r
+optimization.modifier.nosecone.length = Länge\r
+optimization.modifier.nosecone.length.desc = Optimiert die Spitzenlänge.\r
+optimization.modifier.nosecone.diameter = Durchmesser\r
+optimization.modifier.nosecone.diameter.desc = Optimiert den Spitzendurchmesser.\r
+optimization.modifier.nosecone.thickness = Wandstärke\r
+optimization.modifier.nosecone.thickness.desc = Optimiert die Wandstärke der Spitze.\r
+optimization.modifier.nosecone.shapeparameter = Formparameter\r
+optimization.modifier.nosecone.shapeparameter.desc = Optimiert den Formparameter der Spitze.\r
+\r
+optimization.modifier.transition.length = Länge\r
+optimization.modifier.transition.length.desc = Optimiert die Übergangslänge.\r
+optimization.modifier.transition.forediameter = Vorderer Durchmesser\r
+optimization.modifier.transition.forediameter.desc = Optimiert den vordere Durchmesser des Übergangs.\r
+optimization.modifier.transition.aftdiameter = Hinterer Durchmesser\r
+optimization.modifier.transition.aftdiameter.desc = Optimiert den hinteren Durchmesser des Übergangs.\r
+optimization.modifier.transition.thickness = Wandstärke\r
+optimization.modifier.transition.thickness.desc = Optimiert die Wandstärke des Übergangs\r
+optimization.modifier.transition.shapeparameter = Formparameter\r
+optimization.modifier.transition.shapeparameter.desc = Optimiert den Formparameter des Übergangs.\r
+\r
+optimization.modifier.bodytube.length = Länge\r
+optimization.modifier.bodytube.length.desc = Optimiert die Länge des Körperrohrs.\r
+optimization.modifier.bodytube.outerDiameter = Außendurchmessser\r
+optimization.modifier.bodytube.outerDiameter.desc = Optimiert den Außendurchmesser des Körperohrs unter Beibehaltung der Wandstärke.\r
+optimization.modifier.bodytube.thickness = Wandstärke\r
+optimization.modifier.bodytube.thickness.desc = Optimiiert die Wandstärke des Körperrohrs.\r
+\r
+optimization.modifier.trapezoidfinset.rootChord = Blatttiefe\r
+optimization.modifier.trapezoidfinset.rootChord.desc = Optimiert die Blatttiefe der Leitwerke (Länge der Leitwerke am Körperrohr).\r
+optimization.modifier.trapezoidfinset.tipChord = Blatttiefe (Spitze)\r
+optimization.modifier.trapezoidfinset.tipChord.desc = Optimiert die Blatttiefe (Spitze) der Leitwerke (Außenlänge der Leitwerke).\r
+optimization.modifier.trapezoidfinset.sweep  = Pfeilung\r
+optimization.modifier.trapezoidfinset.sweep.desc = Optimiert die Pfeilung der Leitwerke (Abstand, um den die Leitwerke nach hinten überragen).\r
+optimization.modifier.trapezoidfinset.height = Höhe\r
+optimization.modifier.trapezoidfinset.height.desc = Optimiert die Höhe der Leitwerke.\r
+\r
+optimization.modifier.ellipticalfinset.length = Blatttiefe\r
+optimization.modifier.ellipticalfinset.length.desc = Optimiert die Blatttiefe der Leitwerke.\r
+optimization.modifier.ellipticalfinset.height = Höhe\r
+optimization.modifier.ellipticalfinset.height.desc = Optimiert die Höhe der Leitwerke.\r
+\r
+optimization.modifier.finset.cant = Neigungswinkel\r
+optimization.modifier.finset.cant.desc = Optimiert den Neigungswinkel der Leitwerke.\r
 optimization.modifier.finset.position = Position\r
-optimization.modifier.finset.position.desc = Optimize the fin set position along the rocket body.\r
-\r
-optimization.modifier.launchlug.length = Length\r
-optimization.modifier.launchlug.length.desc = Optimize the launch lug length.\r
-optimization.modifier.launchlug.outerDiameter = Outer diameter\r
-optimization.modifier.launchlug.outerDiameter.desc = Optimize the outer diameter of the launch lug.\r
-optimization.modifier.launchlug.thickness = Thickness\r
-optimization.modifier.launchlug.thickness.desc = Optimize the launch lug thickness while keeping the outer diameter constant.\r
+optimization.modifier.finset.position.desc = Optimiert die Position der Leitwerke entlang des Körperrohrs.\r
+\r
+optimization.modifier.launchlug.length = Länge\r
+optimization.modifier.launchlug.length.desc = Optimiert die Länge des Leitröhrchens.\r
+optimization.modifier.launchlug.outerDiameter = Außendurchmesser\r
+optimization.modifier.launchlug.outerDiameter.desc = Optimiert den Außendurchmesser des Leitröhrchens\r
+optimization.modifier.launchlug.thickness = Wandstärke\r
+optimization.modifier.launchlug.thickness.desc = Optimiert die Wandstärke des Leitröhrchens bei konstantem Außendurchmesser.\r
 optimization.modifier.launchlug.position = Position\r
-optimization.modifier.launchlug.position.desc = Optimize the launch lug position along the rocket body.\r
+optimization.modifier.launchlug.position.desc = Optimiert die Position des Leitröhrchens entlang des Körperrohrs.\r
 \r
 \r
 optimization.modifier.internalcomponent.position = Position\r
-optimization.modifier.internalcomponent.position.desc = Optimize the position of the component relative to the parent component.\r
+optimization.modifier.internalcomponent.position.desc = Optimiert die Position der Komponente relativ zur Überkomponente.\r
 \r
-optimization.modifier.masscomponent.mass = Mass\r
-optimization.modifier.masscomponent.mass.desc = Optimize the mass of the mass component.\r
+optimization.modifier.masscomponent.mass = Masse\r
+optimization.modifier.masscomponent.mass.desc = Optimiert die Masse eines Masseobjektes.\r
 \r
-optimization.modifier.parachute.diameter = Diameter\r
-optimization.modifier.parachute.diameter.desc = Optimize the parachute canopy diameter.\r
-optimization.modifier.parachute.coefficient = Drag coefficient\r
-optimization.modifier.parachute.coefficient.desc = Optimize the drag coefficient of the parachute.  Typical parachutes have a drag coefficient of about 0.8.\r
+optimization.modifier.parachute.diameter = Durchmesser\r
+optimization.modifier.parachute.diameter.desc = Optimiert den Fallschirmkappendurchmesser.\r
+optimization.modifier.parachute.coefficient = Luftwiderstandskoeffizient\r
+optimization.modifier.parachute.coefficient.desc = Optimiert den Luftwiderstandskoeffizient des Fallschirms. Typische Fallschirme haben einen Luftwiderstandskoeffizient von 0.8.\r
 \r
-optimization.modifier.streamer.length = Length\r
-optimization.modifier.streamer.length.desc = Optimize the length of the streamer.\r
-optimization.modifier.streamer.width = Width\r
-optimization.modifier.streamer.width.desc = Optimize the width of the streamer.\r
-optimization.modifier.streamer.aspectRatio = Aspect ratio\r
-optimization.modifier.streamer.aspectRatio.desc = Optimize the aspect ratio of the streamer (length/width).  You should NOT select streamer length or width at the same time with the aspect ratio.\r
-optimization.modifier.streamer.coefficient = Drag coefficient\r
-optimization.modifier.streamer.coefficient.desc = Optimize the drag coefficient of the streamer.\r
+optimization.modifier.streamer.length = Länge\r
+optimization.modifier.streamer.length.desc = Optimiert die Länge des Strömers.\r
+optimization.modifier.streamer.width = Breite\r
+optimization.modifier.streamer.width.desc = Optimiert die Breite des Strömers.\r
+optimization.modifier.streamer.aspectRatio = Seitenverhältnis\r
+optimization.modifier.streamer.aspectRatio.desc = Optimiert das Seitenverhältnis des Strömers (Länge/Breite). Länge oder Breite des Strömers sollten NICHT gleichzeitig mit dem Seitenverhältnis ausgewählt werden.\r
+optimization.modifier.streamer.coefficient = Luftwiderstandskoeffizient\r
+optimization.modifier.streamer.coefficient.desc = Optimiert den Luftwiderstandskoeffizient des Strömers.\r
 \r
-optimization.modifier.recoverydevice.deployDelay = Deployment delay\r
-optimization.modifier.recoverydevice.deployDelay.desc = Optimize the deployment delay of the recovery device.\r
-optimization.modifier.recoverydevice.deployAltitude = Deployment altitude\r
-optimization.modifier.recoverydevice.deployAltitude.desc = Optimize the deployment altitude of the recovery device.\r
+optimization.modifier.recoverydevice.deployDelay = Ausstoß-Verzögerung\r
+optimization.modifier.recoverydevice.deployDelay.desc = Optimiert die Austoß-Verzögerung des Bergungssystems.\r
+optimization.modifier.recoverydevice.deployAltitude = Ausstoßhöhe\r
+optimization.modifier.recoverydevice.deployAltitude.desc = Optimiert Ausstoßhöhe des Bergungssystems.\r
 \r
-optimization.modifier.rocketcomponent.overrideMass = Override mass\r
-optimization.modifier.rocketcomponent.overrideMass.desc = Optimize the overridden mass of the component.\r
-optimization.modifier.rocketcomponent.overrideCG = Override CG\r
-optimization.modifier.rocketcomponent.overrideCG.desc = Optimize the overridden center of gravity of the component.\r
+optimization.modifier.rocketcomponent.overrideMass = Überschriebene Masse\r
+optimization.modifier.rocketcomponent.overrideMass.desc = Optimiert die überschriebene Masse einer Komponente.\r
+optimization.modifier.rocketcomponent.overrideCG = Überschriebener Druckpunkt\r
+optimization.modifier.rocketcomponent.overrideCG.desc = Optimiert den überschriebenen Druckpunkt einer Komponente.\r
 \r
-optimization.modifier.motormount.overhang = Motor overhang\r
-optimization.modifier.motormount.overhang.desc = Optimize the motor overhang.\r
-optimization.modifier.motormount.delay = Motor ignition delay\r
-optimization.modifier.motormount.delay.desc = Optimize the motor ignition delay.\r
+optimization.modifier.motormount.overhang = Motorüberhang\r
+optimization.modifier.motormount.overhang.desc = Optimiert den Motorüberhang.\r
+optimization.modifier.motormount.delay = Motorzündverzögerung\r
+optimization.modifier.motormount.delay.desc = Optimiert die Motorzündverzögerung.\r
 \r
 \r
 \r
 \r
 ! General rocket design optimization dialog\r
 \r
-GeneralOptimizationDialog.title = Rocket optimization\r
-GeneralOptimizationDialog.goal.maximize = Maximize value\r
-GeneralOptimizationDialog.goal.minimize = Minimize value\r
-GeneralOptimizationDialog.goal.seek = Seek value of\r
-GeneralOptimizationDialog.btn.start = Start optimization\r
-GeneralOptimizationDialog.btn.stop = Stop optimization\r
-GeneralOptimizationDialog.lbl.paramsToOptimize = Parameters to optimize:\r
-GeneralOptimizationDialog.btn.add = Add\r
-GeneralOptimizationDialog.btn.add.ttip = Add the selected parameter to the optimization\r
-GeneralOptimizationDialog.btn.remove = Remove\r
-GeneralOptimizationDialog.btn.remove.ttip = Remove the selected parameter from the optimization\r
-GeneralOptimizationDialog.btn.removeAll = Remove all\r
-GeneralOptimizationDialog.btn.removeAll.ttip = Remove all parameters from the optimization\r
-GeneralOptimizationDialog.lbl.availableParams = Available parameters:\r
-GeneralOptimizationDialog.lbl.optimizationOpts = Optimization options\r
-GeneralOptimizationDialog.lbl.optimizeSim = Optimize simulation:\r
-GeneralOptimizationDialog.lbl.optimizeSim.ttip = Select which simulation to optimize\r
-GeneralOptimizationDialog.lbl.optimizeValue = Optimized value:\r
-GeneralOptimizationDialog.lbl.optimizeValue.ttip = Select what value is to be optimized\r
-GeneralOptimizationDialog.lbl.optimizeGoal = Optimization goal:\r
-GeneralOptimizationDialog.lbl.optimizeGoal.ttip = Select the goal of the optimization\r
-GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip = Custom value to seek\r
-GeneralOptimizationDialog.lbl.requireStability = Required stability\r
-GeneralOptimizationDialog.lbl.requireMinStability = Minimum stability:\r
-GeneralOptimizationDialog.lbl.requireMinStability.ttip = Require a minimum static stability margin for the design\r
-GeneralOptimizationDialog.lbl.requireMaxStability = Maximum stability:\r
-GeneralOptimizationDialog.lbl.requireMaxStability.ttip = Require a maximum static stability margin for the design\r
-GeneralOptimizationDialog.status.bestValue = Best value:\r
-GeneralOptimizationDialog.status.bestValue.ttip = Best optimization value found so far.\r
-GeneralOptimizationDialog.status.stepCount = Step count:\r
-GeneralOptimizationDialog.status.stepCount.ttip = Number of optimization steps that have been performed.\r
-GeneralOptimizationDialog.status.evalCount = Evaluations:\r
-GeneralOptimizationDialog.status.evalCount.ttip = Total number of function evaluations (simulations) that have been performed.\r
-GeneralOptimizationDialog.status.stepSize = Step size:\r
-GeneralOptimizationDialog.status.stepSize.ttip = Current optimization step size (relative to the optimization parameter ranges)\r
-GeneralOptimizationDialog.btn.plotPath = Plot path\r
-GeneralOptimizationDialog.btn.plotPath.ttip = Plot the optimization path (one and two dimensional optimization only)\r
-GeneralOptimizationDialog.btn.save = Save path\r
-GeneralOptimizationDialog.btn.save.ttip = Save the results of the function evaluations (simulations) as a CSV file.\r
-GeneralOptimizationDialog.btn.apply = Apply optimization\r
-GeneralOptimizationDialog.btn.apply.ttip = Apply the optimization results to the rocket design\r
-GeneralOptimizationDialog.btn.reset = Reset\r
-GeneralOptimizationDialog.btn.reset.ttip = Reset the rocket design to the current rocket design\r
-GeneralOptimizationDialog.btn.close = Close\r
-GeneralOptimizationDialog.btn.close.ttip = Close the dialog without modifying the rocket design\r
-GeneralOptimizationDialog.error.selectParams.text = First select some parameters to optimize from the available parameters.\r
-GeneralOptimizationDialog.error.selectParams.title = Select optimization parameters\r
-GeneralOptimizationDialog.error.optimizationFailure.text = The optimization failed to run:\r
-GeneralOptimizationDialog.error.optimizationFailure.title = Optimization failed\r
-GeneralOptimizationDialog.undoText = Apply optimization\r
-GeneralOptimizationDialog.basicSimulationName = Basic simulation\r
-GeneralOptimizationDialog.noSimulationName = No simulation\r
+GeneralOptimizationDialog.title = Raketenoptimierung\r
+GeneralOptimizationDialog.goal.maximize = Wert maximieren\r
+GeneralOptimizationDialog.goal.minimize = Wert minimieren\r
+GeneralOptimizationDialog.goal.seek = Wert suchen von\r
+GeneralOptimizationDialog.btn.start = Optimierung starten\r
+GeneralOptimizationDialog.btn.stop = Optimierung stoppen\r
+GeneralOptimizationDialog.lbl.paramsToOptimize = Zu optimierende Parameter:\r
+GeneralOptimizationDialog.btn.add = Hinzufügen\r
+GeneralOptimizationDialog.btn.add.ttip = Fügt den ausgewählten Parameter der Optimierung hinzu.\r
+GeneralOptimizationDialog.btn.remove = Entfernen\r
+GeneralOptimizationDialog.btn.remove.ttip = Entfernt den ausgewählten Parameter aus der Optimierung\r
+GeneralOptimizationDialog.btn.removeAll = Alle entfernen\r
+GeneralOptimizationDialog.btn.removeAll.ttip = Entfernt alle Parameter aus der Optimierung\r
+GeneralOptimizationDialog.lbl.availableParams = Verfügbare Parameter:\r
+GeneralOptimizationDialog.lbl.optimizationOpts = Optimierungsoptionen\r
+GeneralOptimizationDialog.lbl.optimizeSim = Simulation optimieren:\r
+GeneralOptimizationDialog.lbl.optimizeSim.ttip = Auswählen, welche Simualtion optimiert werden soll.\r
+GeneralOptimizationDialog.lbl.optimizeValue = Optimierter Wert:\r
+GeneralOptimizationDialog.lbl.optimizeValue.ttip = Auswählen, welcher Wert optimiert werden soll\r
+GeneralOptimizationDialog.lbl.optimizeGoal = Optimierungsziel:\r
+GeneralOptimizationDialog.lbl.optimizeGoal.ttip = Ziel der Optimierung auswählen.\r
+GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip = Benutzerdefinierter Wert, der gesucht werden soll.\r
+GeneralOptimizationDialog.lbl.requireStability = Benötigte Stabilität\r
+GeneralOptimizationDialog.lbl.requireMinStability = Minimale Stabilität:\r
+GeneralOptimizationDialog.lbl.requireMinStability.ttip = Minimale statische Stabilitätsreserve für das Design\r
+GeneralOptimizationDialog.lbl.requireMaxStability = Maximale Stabilität:\r
+GeneralOptimizationDialog.lbl.requireMaxStability.ttip = Maximale statische Stabilitätsreserve für das Design\r
+GeneralOptimizationDialog.status.bestValue = Bester Wert:\r
+GeneralOptimizationDialog.status.bestValue.ttip = Bester Optimierungswert, der bisher gefunden wurde.\r
+GeneralOptimizationDialog.status.stepCount = Anzahl der Schritte:\r
+GeneralOptimizationDialog.status.stepCount.ttip = Anzahl der Optimierungsschritte, die bisher durchgeführt wurden.\r
+GeneralOptimizationDialog.status.evalCount = Berechnungen:\r
+GeneralOptimizationDialog.status.evalCount.ttip = Gesamtzahl der Berechnungen (Simulationen) die durchgeführt wurden.\r
+GeneralOptimizationDialog.status.stepSize = Schrittgröße:\r
+GeneralOptimizationDialog.status.stepSize.ttip = Aktuelle Optimierungsschrittgröße (relativ zum Wertebereich der Optimierungsparameter)\r
+GeneralOptimizationDialog.btn.plotPath = Pfad zeichnen\r
+GeneralOptimizationDialog.btn.plotPath.ttip = Zeichnet den Optimierungsspfad (nur für ein- und zweidimensionale Optimierungen)\r
+GeneralOptimizationDialog.btn.save = Pfad speichern\r
+GeneralOptimizationDialog.btn.save.ttip = Speichert die Werte der Berechnungen (Simulationen) als CSV-Datei.\r
+GeneralOptimizationDialog.btn.apply = Optimierung anwenden\r
+GeneralOptimizationDialog.btn.apply.ttip = Wendet die Ergebnisse der Optimierung auf das Raketendesign an.\r
+GeneralOptimizationDialog.btn.reset = Zurücksetzen\r
+GeneralOptimizationDialog.btn.reset.ttip = Setzt das Design auf das aktuelle Design zurück.\r
+GeneralOptimizationDialog.btn.close = Schließen\r
+GeneralOptimizationDialog.btn.close.ttip = Schließt das Dialogfenster ohne die Änderungen auf das Design anzuwenden.\r
+GeneralOptimizationDialog.error.selectParams.text = Erst einige Parameter zur Optimierung aus den verfügbaren Parametern auswählen.\r
+GeneralOptimizationDialog.error.selectParams.title = Optimierungsparameter auswählen.\r
+GeneralOptimizationDialog.error.optimizationFailure.text = Optimierung gescheitert:\r
+GeneralOptimizationDialog.error.optimizationFailure.title = Optimierung gescheitert\r
+GeneralOptimizationDialog.undoText = Optimierung anwenden\r
+GeneralOptimizationDialog.basicSimulationName = einfache Simulation\r
+GeneralOptimizationDialog.noSimulationName = keine Simulation\r
 GeneralOptimizationDialog.table.col.parameter = Parameter\r
-GeneralOptimizationDialog.table.col.current = Current\r
+GeneralOptimizationDialog.table.col.current = aktuell\r
 GeneralOptimizationDialog.table.col.min = Minimum\r
 GeneralOptimizationDialog.table.col.max = Maximum\r
-GeneralOptimizationDialog.export.header = Include header line\r
-GeneralOptimizationDialog.export.header.ttip = Include a header line as the first line containing the field descriptions.\r
-GeneralOptimizationDialog.export.stability = Stability\r
+GeneralOptimizationDialog.export.header = Kopfzeile ausgeben\r
+GeneralOptimizationDialog.export.header.ttip = Fügt eine Kopfzeile als erste Zeile ein, die eine Beschreibung der Felder enthält.\r
+GeneralOptimizationDialog.export.stability = Stabilität\r
 \r
 \r
 ! Dialog for plotting optimization results\r
-OptimizationPlotDialog.title = Optimization results\r
-OptimizationPlotDialog.lbl.zoomInstructions = Click and drag down+right to zoom in, up+left to zoom out\r
-OptimizationPlotDialog.plot1d.title = Optimization result\r
-OptimizationPlotDialog.plot1d.series = Optimization result\r
-OptimizationPlotDialog.plot2d.title = Optimization path\r
-OptimizationPlotDialog.plot2d.path = Optimization path\r
-OptimizationPlotDialog.plot2d.evals = Evaluations\r
-OptimizationPlotDialog.plot.ttip.stability = Stability:\r
+OptimizationPlotDialog.title = Optimierungsergebnisse\r
+OptimizationPlotDialog.lbl.zoomInstructions = Klicken und nach unten+rechts ziehen zum reinzoomen, oben+links zum herauszoomen\r
+OptimizationPlotDialog.plot1d.title = Optimierungsergebnis\r
+OptimizationPlotDialog.plot1d.series = Optimierungsergebnis\r
+OptimizationPlotDialog.plot2d.title = Optimierungspfad\r
+OptimizationPlotDialog.plot2d.path = Optimierungspfad\r
+OptimizationPlotDialog.plot2d.evals = Berechnungen\r
+OptimizationPlotDialog.plot.ttip.stability = Stabilität:\r
 OptimizationPlotDialog.plot.label.optimum = Optimum\r
 \r
 ! Optimization parameters\r
-MaximumAltitudeParameter.name = Apogee altitude\r
-MaximumVelocityParameter.name = Maximum velocity\r
-MaximumAccelerationParameter.name = Maximum acceleration\r
-StabilityParameter.name = Stability\r
-GroundHitVelocityParameter.name = Ground hit speed\r
-LandingDistanceParameter.name = Landing distance\r
-TotalFlightTimeParameter.name = Total flight time\r
-DeploymentVelocityParameter.name = Velocity at parachute deployment\r
+MaximumAltitudeParameter.name = Apogäumshöhe\r
+MaximumVelocityParameter.name = Maximale Geschwindigkeit\r
+MaximumAccelerationParameter.name = Maximale Beschleunigung\r
+StabilityParameter.name = Stabilität\r
+GroundHitVelocityParameter.name = Landegeschwindigkeit\r
+LandingDistanceParameter.name = Landeentfernung\r
+TotalFlightTimeParameter.name = Gesamtflugzeit\r
+DeploymentVelocityParameter.name = Geschwindigkeit bei Fallschirmauswurf\r
 \r
 \r
 ! Compass directions drawn on a compass rose.\r
 CompassRose.lbl.north = N\r
-CompassRose.lbl.east  = E\r
+CompassRose.lbl.east  = O\r
 CompassRose.lbl.south = S\r
 CompassRose.lbl.west  = W\r
 \r
 ! Compass directions with subdirections.  These might not be localized even if the directions on the compass rose are.\r
 CompassSelectionButton.lbl.N = N\r
-CompassSelectionButton.lbl.NE = NE\r
-CompassSelectionButton.lbl.E = E\r
-CompassSelectionButton.lbl.SE = SE\r
+CompassSelectionButton.lbl.NE = NO\r
+CompassSelectionButton.lbl.E = O\r
+CompassSelectionButton.lbl.SE = SO\r
 CompassSelectionButton.lbl.S = S\r
 CompassSelectionButton.lbl.SW = SW\r
 CompassSelectionButton.lbl.W = W\r
 CompassSelectionButton.lbl.NW = NW\r
 \r
 \r
-SlideShowDialog.btn.next = Next\r
-SlideShowDialog.btn.prev = Previous\r
+SlideShowDialog.btn.next = Nächster\r
+SlideShowDialog.btn.prev = Vorheriger\r
+\r
+SlideShowLinkListener.error.title = Geführte Touren nicht gefunden\r
+SlideShowLinkListener.error.msg = Entschuldigung, die geführte Tour wurde noch nicht nicht geschrieben.\r
+\r
+GuidedTourSelectionDialog.title = Geführte Touren\r
+GuidedTourSelectionDialog.lbl.selectTour = Geführte Tour auswählen:\r
+GuidedTourSelectionDialog.lbl.description = Beschreibung:\r
+GuidedTourSelectionDialog.lbl.length = Anzahl der Folien:\r
+GuidedTourSelectionDialog.btn.start = Tour starten!\r
+\r
+! Custom Fin BMP Importer\r
+CustomFinImport.button.label = Importieren aus Bild\r
+CustomFinImport.badFinImage = Ungültiges Leitwerksbild. Sicherstellen, dass das Leitwerk schwarz oder sehr dunkel ist und das untere Ende des Bildes berührt.\r
+CustomFinImport.errorLoadingFile = Fehler beim Laden der Datei: \r
+CustomFinImport.errorParsingFile = Fehler beim Verarbeiten des Leitwerksbildes: \r
+CustomFinImport.undo = Importieren eines Freiform-Leitwerks\r
+CustomFinImport.error.title = Fehler beim Laden eines Leitwerkprofils\r
+CustomFinImport.error.badimage = Konnte keine Leitwerksform aus dem Bild erzeugen.\r
+CustomFinImport.description = Das Bild wird intern in ein Schwarz-Weiß-Bild konvertiert (Leitwerk: schwarz). Bitte sicherstellen, dass das Leitwerk in einer dichten, dunklen Farbe ist, während der Hintergrund weiß oder sehr hell sein sollte. Das Leitwerk muss das untere Bildende berühren, da dies die Verbindungsstelle zur Rakete wird.\r
+\r
+\r
+PresetModel.lbl.select = Voreinstellung auswählen:\r
+PresetModel.lbl.database = Aus Datenbank...\r
+\r
+\r
+! Component Preset Chooser Dialog\r
+ComponentPresetChooserDialog.title = Komponentenvoreinstellung auswählen:\r
+ComponentPresetChooserDialog.filter.label = Nach Text filtern:\r
+ComponentPresetChooserDialog.checkbox.filterAftDiameter = Hinterer Durchmesser stimmt überein\r
+ComponentPresetChooserDialog.checkbox.filterForeDiameter = Vorderer Durchmesser stimmt überein\r
+ComponentPresetChooserDialog.menu.sortAsc = Aufsteigend sortieren\r
+ComponentPresetChooserDialog.menu.sortDesc = Absteigend sortieren\r
+ComponentPresetChooserDialog.menu.units = Einheiten\r
+ComponentPresetChooserDialog.checkbox.showAllCompatible = Alle kompatiblen anzeigen\r
+table.column.Favorite = Favorit\r
+table.column.Manufacturer = Hersteller\r
+table.column.PartNo = Teile-Nummer\r
+table.column.Description = Beschreibung\r
+table.column.Type = Typ\r
+table.column.Length = Länge\r
+table.column.Width = Breite\r
+table.column.InnerDiameter = Innendurchmesser\r
+table.column.OuterDiameter = Außendurchmesser\r
+table.column.AftOuterDiameter = Außendurchmesser (hinten)\r
+table.column.AftShoulderLength = Schulterlänge (hinten)\r
+table.column.AftShoulderDiameter = Schulterdurchmesser (hinten)\r
+table.column.ForeShoulderLength = Schulterlänge (vorne)\r
+table.column.ForeShoulderDiameter = Schulterdruchmesser (vorne)\r
+table.column.ForeOuterDiameter = Außendurchmesser (vorne)\r
+table.column.Shape = Form\r
+table.column.Material = Material\r
+table.column.Finish = Oberfläche\r
+table.column.thickness = Wandstärke\r
+table.column.Filled = gefüllt\r
+table.column.Mass = Masse\r
+table.column.Diameter = Duchmesser\r
+table.column.Sides = Seiten\r
+table.column.LineCount = Leinenanzahl\r
+table.column.LineLength = Leinenlänge\r
+table.column.LineMaterial = Leinenmaterial\r
 \r
-GuidedTourSelectionDialog.title = Guided tours\r
-GuidedTourSelectionDialog.lbl.selectTour = Select guided tour:\r
-GuidedTourSelectionDialog.lbl.description = Tour description:\r
-GuidedTourSelectionDialog.lbl.length = Number of slides:\r
-GuidedTourSelectionDialog.btn.start = Start tour!\r
index b52ee93db03f6ff9655a213511a165641bff9dae..36ea24e564e1f2c138c8ef95934d6e5d98f90f91 100644 (file)
-#
-# Spanish base translation file
-# translations provided by Tripoli Spain
-#
-# Should you need to add new logical keys here is the proposed method
-#
-# className.ComponantType.componantName
-#
-#
-# Text tokens within braces should not be translated, e.g.
-#    "The file '{filename}' exists."
-# They are pieces that are inserted dynamically.
-# 
-
-
-! Set to the name of the current translation file (used for debugging purposes)
-debug.currentFile = messages_es.properties
-
-! RocketActions
-RocketActions.checkbox.Donotaskmeagain = No volver a preguntarme
-RocketActions.lbl.Youcanchangedefop = Puede modificar la operación por defecto con sus preferencias
-RocketActions.showConfirmDialog.lbl1 = ¿Borrar las simulaciones seleccionadas?
-RocketActions.showConfirmDialog.lbl2 = <html><i>Esta operación no puede deshacerse.</i>
-RocketActions.showConfirmDialog.title = Borrar simulaciones
-RocketActions.DelCompAct.Delete = Borrar
-RocketActions.DelCompAct.ttip.Delete = Borrar el componente seleccionado
-RocketActions.DelSimuAct.Delete = Borrar
-RocketActions.DelSimuAct.ttip.Delete = Borrar la simulación seleccionada
-RocketActions.DelAct.Delete = Borrar
-RocketActions.DelAct.ttip.Delete = Eliminar elemento seleccionado
-RocketActions.CutAction.Cut = Cortar
-RocketActions.CutAction.ttip.Cut = Quitar y copiar al portapapeles
-RocketActions.CopyAct.Copy = Copiar
-RocketActions.CopyAct.ttip.Copy = Copiar al portapapeles
-RocketActions.PasteAct.Paste = Pegar
-RocketActions.PasteAct.ttip.Paste = Pegar al portapapeles
-RocketActions.EditAct.Edit = Editar componente
-RocketActions.EditAct.ttip.Edit = Editar valores del componente seleccionado
-RocketActions.NewStageAct.Newstage = Nueva etapa
-RocketActions.NewStageAct.ttip.Newstage = Añadir una nueva etapa al diseño del cohete
-RocketActions.ActBoosterstage = Etapa booster
-RocketActions.MoveUpAct.Moveup = Mover hacia arriba
-RocketActions.MoveUpAct.ttip.Moveup = Mover este componente hacia arriba
-RocketActions.MoveDownAct.Movedown = Mover hacia abajo
-RocketActions.MoveDownAct.ttip.Movedown = Mover este componente hacia abajo
-
-! RocketPanel
-RocketPanel.FigTypeAct.Sideview = Vista lateral
-RocketPanel.FigTypeAct.ttip.Sideview = Vista desde un lateral
-RocketPanel.FigTypeAct.Backview = Vista trasera
-RocketPanel.FigTypeAct.ttip.Backview = Vista desde atrás
-RocketPanel.FigViewAct.2D = 2D View
-RocketPanel.FigViewAct.ttip.2D = 2D View
-RocketPanel.FigViewAct.3D = 3D View
-RocketPanel.FigViewAct.ttip.3D = 3D View
-RocketPanel.lbl.Motorcfg = Configuración del motor
-RocketPanel.lbl.infoMessage = <html>Click para seleccionar&nbsp;&nbsp; Mayúsculas+click para seleccionar otro&nbsp;&nbsp; Doble-click para mostrar &nbsp;&nbsp; Click+arrastrar para mover
-
-! BasicFrame
-BasicFrame.SimpleFileFilter1 = Todos los diseños de cohete(*.ork; *.rkt)
-BasicFrame.SimpleFileFilter2 = Diseños OpenRocket (*.ork)
-BasicFrame.SimpleFileFilter3 = Diseños RockSim (*.rkt)
-BasicFrame.tab.Rocketdesign = Diseño del cohete
-BasicFrame.tab.Flightsim = Simulaciones de vuelo
-BasicFrame.title.Addnewcomp = Añadir un nuevo componente
-!BasicFrame.item.Openrocketdesign = Abrir un diseño de cohete
-!BasicFrame.item.Openexamplerocketdesign = Abrir un ejemplo de diseño de cohete
-!BasicFrame.item.SavecurRocketdesign = Guardar el diseño actual
-!BasicFrame.item.SavecurRocketdesnewfile = Guardar el diseño actual como un nuevo documento
-!BasicFrame.item.Printpart = Imprimir un listado de componentes y un esquema de aleta
-!BasicFrame.item.Closedesign = Cerrar el diseño actual
-!BasicFrame.item.Quitprogram = Abandonar el programa
-!BasicFrame.menu.Rocketedt = Mostrando el cohete
-BasicFrame.dlg.lbl1 = Diseño
-BasicFrame.dlg.lbl2 = No se ha guardado
-BasicFrame.dlg.lbl3 = ¿Quiere guardarlo?
-BasicFrame.dlg.title = Diseño no guardado
-BasicFrame.StageName.Sustainer = Etapa principal
-BasicFrame.WarningDialog.txt1 = Mientras se abría, se encontraron los siguiente problemas
-BasicFrame.WarningDialog.txt2 = Algunas configuraciones de diseño no pudieron cargarse correctamente.
-BasicFrame.WarningDialog.title = Precauciones mientras se abre el archivo
-
-
-! General error messages used in multiple contexts
-error.fileExists.title = El archivo ya existe
-error.fileExists.desc = El archivo con el nombre '{filename}' ya existe. ¿Desea sobrescribir la versión anterior?
-
-error.writing.title = Error al guardar el archivo
-error.writing.desc = Ha ocurrido un error al guardar el archivo:
-
-
-! Labels used in buttons of dialog windows
-# TODO: Rename these to "btn.xxx"
-button.ok = OK
-button.cancel = Cancelar
-button.close = Cerrar
-
-! Common labels used in buttons of dialog windows
-dlg.but.ok = OK
-dlg.but.cancel = Cancelar
-dlg.but.close = Cerrar
-
-! General file type names
-filetypes.pdf = Archivos PDF
-
-
-! About Dialog
-AboutDialog.lbl.version = Versión
-! The texts below provide additional credits for the translation maintainer
-! - In AboutDialog.lbl.translation replace "English" with the current language.
-! - AboutDialog.lbl.translator is the translator / group name (may be empty)
-! - AboutDialog.lbl.translatorWebsite is a URL to the translator / group (may be empty)
-! - AboutDialog.lbl.translatorIcon is the file name of an icon under pix/translators/ (may be empty)
-AboutDialog.lbl.translation = Traducido al español por:
-AboutDialog.lbl.translator = Tripoli Spain
-AboutDialog.lbl.translatorWebsite = http://www.tripoli-spain.org/
-AboutDialog.lbl.translatorIcon = logoTripoliSpain.png
-
-
-! Print dialog
-PrintDialog.title = Imprimir o exportar
-PrintDialog.but.previewAndPrint = Vista previa e Imprimir
-PrintDialog.checkbox.showByStage = Mostrar por etapas
-PrintDialog.lbl.selectElements = Seleccionar elementos a incluir:
-printdlg.but.saveaspdf = Guardar como PDF
-printdlg.but.preview = Previsualizar
-printdlg.but.settings = Configuración
-PrintDialog.error.preview.title = Imposible abrir vista previa
-PrintDialog.error.preview.desc1 = Imposible abrir vista previa en PDF.
-PrintDialog.error.preview.desc2 = Por favor use la opción Guardar como PDF.
-
-
-!PrintSettingsDialog
-PrintSettingsDialog.title = Configuración de la impresión
-PrintSettingsDialog.lbl.Templatefillcolor = Plantilla de colores:
-PrintSettingsDialog.lbl.Templatebordercolor = Color del borde de la plantilla:
-PrintSettingsDialog.lbl.Papersize = Tamaño del papel:
-PrintSettingsDialog.lbl.Paperorientation = Orientación del papel:
-PrintSettingsDialog.but.Reset = Reiniciar
-PrintSettingsDialog.but.Close = Cerrar
-
-
-! Bug Report dialog
-bugreport.dlg.title = Informe de errores
-bugreport.dlg.but.Sendbugreport = Enviar informe de error
-bugreport.dlg.but.Sendbugreport.Ttip = Enviar automáticamente un informe de error a los creadores de Open Rocket
-bugreport.dlg.successmsg1 = Informe de error enviado con éxito
-bugreport.dlg.successmsg2 = ¡Gracias por ayudar a mejorar Open Rocket!
-bugreport.dlg.successmsg3 = Informe de error enviado
-bugreport.dlg.connectedInternet = <html>Si está conectado a Internet, haga Clik en <em>Enviar informe de errores</em>.
-bugreport.dlg.otherwise = De otro modo, también puede copiar y enviar el texto a la dirección:
-bugreport.lbl.Theinformation = La información que ha detallado se incluirá en un informe de error público. Asegúrese de que no contiene ninguna información que usted no desee hacer pública.
-bugreport.dlg.failedmsg1 = OpenRocket fue incapaz de enviar el informe de error:
-bugreport.dlg.failedmsg2 = Por favor envíe manualmente el informe a
-bugreport.dlg.failedmsg3 = Error al enviar el informe
-bugreport.reportDialog.txt = <html><b>Puede realizar un informe de errores escribiendo en el formulario de abajo y enviarlo.</b><br>También puede informar de los errores adjuntando el archivo de su proyecto por email.
-bugreport.reportDialog.txt2 = <html><b>Por favor incluya una breve descripción de lo que estaba haciendo cuando ocurrió el error.</b>
-bugreport.dlg.provideDescription = Por favor, primero proporcione una descripción del error.
-bugreport.dlg.provideDescription.title = Descripción del error omitida
-
-
-! Debug log dialog
-debuglogdlg.but.clear = Limpiar
-debuglogdlg.OpenRocketdebuglog = Registro de sucesos
-debuglogdlg.Displayloglines = Mostrar líneas de registro:
-debuglogdlg.Follow = Seguir
-debuglogdlg.col.Time = Hora
-debuglogdlg.col.Level = Nivel
-debuglogdlg.col.Location = Localización
-debuglogdlg.col.Message = Mensaje
-debuglogdlg.lbl.Loglinenbr = Número de línea de registro:
-debuglogdlg.lbl.Time = Hora:
-debuglogdlg.lbl.Level = Nivel:
-debuglogdlg.lbl.Location = Localización:
-debuglogdlg.lbl.Logmessage = Texto del mensaje:
-debuglogdlg.lbl.Stacktrace = Trazabilidad de la pila:
-
-
-! Edit Motor configuration dialog
-edtmotorconfdlg.but.removemotor = Quitar motor
-edtmotorconfdlg.but.Selectmotor = Seleccionar motor
-edtmotorconfdlg.but.Removeconfiguration = Quitar configuración
-edtmotorconfdlg.but.Newconfiguration = Nueva configuración
-edtmotorconfdlg.lbl.Motormounts = <html><b>Porta motor:</b>
-edtmotorconfdlg.title.Editmotorconf = Mostrar las configuraciones de motor
-edtmotorconfdlg.selectcomp = <html>Seleccionar qué componentes tienen la función de porta motor:
-edtmotorconfdlg.lbl.Motorconfig = <html><b>Configuraciones del motor:</b>
-edtmotorconfdlg.lbl.Configname = Nombre de la configuración:
-edtmotorconfdlg.lbl.Leavenamedefault = Dejar el nombre por defecto.
-
-! Example design dialog
-exdesigndlg.but.open = Abrir
-exdesigndlg.lbl.Selectexample = Diseños de ejemplo:
-exdesigndlg.lbl.Openexampledesign = Abrir un ejemplo de diseño
-exdesigndlg.lbl.Exampledesignsnotfound = Los ejemplos de diseño podrían no encontrarse.
-exdesigndlg.lbl.Examplesnotfound = Ejemplos no encontrados
-
-
-! Material edit panel
-matedtpan.but.new = Nuevo
-matedtpan.but.edit = Editar
-matedtpan.but.delete = Borrar
-matedtpan.but.revertall = Borrar todo
-matedtpan.col.Material = Material
-matedtpan.col.Type = Tipo
-matedtpan.col.Density = Densidad
-matedtpan.col.but.ttip.New = Añadir un nuevo material
-matedtpan.title.Addcustmaterial = Añadir un material personalizado
-matedtpan.but.ttip.edit = Editar un material existente
-matedtpan.title.Editmaterial = Editar material
-matedtpan.title2.Editmaterial = Los materiales básicos no se pueden modificar, se añadirá como nuevo material personalizado
-matedtpan.but.ttip.delete = Borrar un material personalizado
-matedtpan.but.ttip.revertall = Borrar todos los materiales personalizados
-matedtpan.title.Deletealluser-defined = ¿Borrar todos los materiales personalizados?
-matedtpan.title.Revertall = ¿Revertir todo?
-matedtpan.lbl.edtmaterials = La edición de los materiales no afecta a los diseños ya existentes.
-
-!MaterialModel
-MaterialModel.title.Material = Material
-MaterialModel.title.Defcustmat = Definir nuevo material personalizado
-
-
-! Preference dialog
-pref.dlg.but.add = Agregar
-pref.dlg.but.reset = Reiniciar
-pref.dlg.but.checknow = Comprobar ahora
-pref.dlg.but.defaultmetric = Sistema Métrico por defecto
-pref.dlg.but.defaultimperial = Sistema Imperial por defecto
-pref.dlg.title.Preferences = Preferencias 
-pref.dlg.tab.Units = Unidades
-pref.dlg.tab.Defaultunits = Unidades por defecto
-pref.dlg.tab.Materials = Materiales
-pref.dlg.tab.Custommaterials = Materiales personalizados
-pref.dlg.tab.Options = Opciones
-pref.dlg.tab.Miscellaneousoptions = Otras opciones
-pref.dlg.lbl.Positiontoinsert = Posición para introducir nuevos componentes del fuselaje: 
-pref.dlg.lbl.Confirmdeletion = Confirmar borrar simulaciones: 
-pref.dlg.lbl.User-definedthrust = Curvas de potencia definidas por el usuario: 
-pref.dlg.Allthrustcurvefiles = Todos los ficheros de curvas de potencia (*.eng; *.rse; *.zip; directorios)
-pref.dlg.RASPfiles = Ficheros de motor RASP (*.eng)
-pref.dlg.RockSimfiles = Ficheros de motor Rocksim (*.rse)
-pref.dlg.ZIParchives = Archivos ZIP (*.zip)
-pref.dlg.checkbox.Checkupdates = Comprobar actualizaciones de software al arrancar
-pref.dlg.ttip.Checkupdatesnow = Comprobar actualizaciones de software ahora
-pref.dlg.lbl.Selectprefunits = Seleccione sus unidades preferidas:
-pref.dlg.lbl.Rocketdimensions = Dimensiones del cohete: 
-pref.dlg.lbl.Linedensity = Densidad: 
-pref.dlg.lbl.Motordimensions = Dimensiones del motor: 
-pref.dlg.lbl.Surfacedensity = Densidad superficial: 
-pref.dlg.lbl.Distance = Distancia:
-pref.dlg.lbl.Bulkdensity = Densidad media: 
-pref.dlg.lbl.Velocity = Velocidad: 
-pref.dlg.lbl.Surfaceroughness = Rugosidad de la superficie: 
-pref.dlg.lbl.Acceleration = Aceleración: 
-pref.dlg.lbl.Area = Área: 
-pref.dlg.lbl.Mass = Masa: 
-pref.dlg.lbl.Angle = Ángulo: 
-pref.dlg.lbl.Force = Fuerza: 
-pref.dlg.lbl.Rollrate = Valor de rotación: 
-pref.dlg.lbl.Totalimpulse = Impulso total: 
-pref.dlg.lbl.Temperature = Temperatura: 
-pref.dlg.lbl.Momentofinertia = Momento de inercia: 
-pref.dlg.lbl.Pressure = Presión: 
-pref.dlg.lbl.Stability = Estabilidad: 
-pref.dlg.lbl.FlightTime = Tiempo de vuelo: 
-pref.dlg.lbl.effect1 = Los cambios tendrán efecto cuando se abra nuevamente el proyecto.
-pref.dlg.lbl.Checkingupdates = Comprobando actualizaciones...
-pref.dlg.lbl.msg1 = Ocurrió un error mientras se comunicaba con el servidor.
-pref.dlg.lbl.msg2 = Incapaz de recuperar la información de las actualizaciones
-pref.dlg.lbl.msg3 = Usted está utilizando la última versión de Open Rocket.
-pref.dlg.lbl.msg4 = No hay actualizaciones disponibles
-pref.dlg.PrefChoiseSelector1 = Preguntar siempre
-pref.dlg.PrefChoiseSelector2 = Insertar en medio
-pref.dlg.PrefChoiseSelector3 = Añadir al final
-pref.dlg.PrefBooleanSelector1 = Borrar
-pref.dlg.PrefBooleanSelector2 = Confirmar
-pref.dlg.Add = Añadir
-pref.dlg.DescriptionArea.Adddirectories = Añadir directorios, archivos de motor RASP (*.eng), archivos de motor RockSim (*.rse) o archivos ZIP separados por punto y coma (;) para cargar curvas de empuje externas.  Los cambios tendrán efecto la próxima vez que abra OpenRocket.
-
-PreferencesDialog.lbl.language = Idioma de la interfaz:
-PreferencesDialog.languages.default = Idioma por defecto
-PreferencesDialog.lbl.languageEffect = El idioma cambiará la próxima vez que abra OpenRocket.
-
-! Simulation edit dialog
-simedtdlg.but.runsimulation = Lanzar la simulación
-simedtdlg.but.resettodefault = Restaurar por defecto
-simedtdlg.but.add = Agregar
-simedtdlg.but.remove = Quitar
-simedtdlg.title.Editsim = Mostrar la simulación
-simedtdlg.lbl.Simname = Nombre de la simulación
-simedtdlg.tab.Launchcond = Condiciones del lanzamiento
-simedtdlg.tab.Simopt = Opciones de simulación
-simedtdlg.tab.Plotdata = Datos del gráfico
-simedtdlg.tab.Exportdata = Exportar datos
-simedtdlg.lbl.Motorcfg = Configuración del motor:
-simedtdlg.lbl.ttip.Motorcfg = Seleccionar la configuración del motor a usar
-simedtdlg.combo.ttip.motorconf = Seleccione la configuración del motor a usar
-simedtdlg.lbl.Wind = Viento
-simedtdlg.lbl.Averwindspeed = Velocidad media del viento
-simedtdlg.lbl.ttip.Averwindspeed = Velocidad media del viento en relación al suelo
-simedtdlg.lbl.Stddeviation = Desviación estándar
-simedtdlg.lbl.ttip.Stddeviation = <html>Desviación estándar de la velocidad del viento.<br>La velocidad del viento se encuentra dentro del doble de la desviación media en un 95% del tiempo.
-simedtdlg.lbl.Turbulenceintensity = Intensidad de la turbulencia
-simedtdlg.lbl.ttip.Turbulenceintensity1 = <html>La intensidad de la turbulencia es la desviación estándar dividida por la velocidad media del viento.<br>
-simedtdlg.lbl.ttip.Turbulenceintensity2 = Valores típicos en el campo
-simedtdlg.lbl.ttip.Turbulenceintensity3 = a
-simedtdlg.border.Atmoscond = Condiciones atmosféricas
-simedtdlg.checkbox.InterStdAtmosphere = Usar los patrones de Atmosfera Internacional
-simedtdlg.checkbox.ttip.InterStdAtmosphere1 = <html>Seleccionar para usar el modelo de la International Standard Atmosphere.<br>Este modelo tiene una temperatura de
-simedtdlg.checkbox.ttip.InterStdAtmosphere2 = Y una presión de
-simedtdlg.checkbox.ttip.InterStdAtmosphere3 = A nivel del mar.
-simedtdlg.lbl.Temperature = Temperatura:
-simedtdlg.lbl.ttip.Temperature = Temperatura en el campo de lanzamiento.
-simedtdlg.lbl.Pressure = Presión:
-simedtdlg.lbl.ttip.Pressure = Presión atmosférica en el campo de lanzamiento
-simedtdlg.lbl.Launchsite = Lugar de lanzamiento
-simedtdlg.lbl.Latitude = Latitud:
-simedtdlg.lbl.ttip.Latitude = <html>La latitud del campo de lanzamiento afecta a la atracción terrestre.<br>Los valores positivos se dan en el hemisferio Norte, los negativos en el hemisferio Sur.
-
-simedtdlg.lbl.Longitude = Longitud:
-simedtdlg.lbl.ttip.Longitude = <html>Requerido para modelos de elevación y predicción meteorológica.
-
-simedtdlg.lbl.Altitude = Altitud:
-simedtdlg.lbl.ttip.Altitude = <html>Los valores por encima del nivel del mar <br>afectan al modelado de las condicones atmosféricas.
-simedtdlg.border.Launchrod = Varilla para lanzar
-simedtdlg.lbl.Length = Longitud:
-simedtdlg.lbl.ttip.Length = Longitud de la varilla de lanzamiento
-simedtdlg.lbl.Angle = Ángulo:
-simedtdlg.lbl.ttip.Angle = El ángulo de la varilla de lanzamiento con respecto a la vertical.
-simedtdlg.lbl.Direction = Dirección:
-simedtdlg.lbl.ttip.Direction1 = <html>Dirección de la varilla de lanzamiento relativa al viento.<br>
-simedtdlg.lbl.ttip.Direction2 = Contra el viento
-simedtdlg.lbl.ttip.Direction3 = A favor del viento
-simedtdlg.border.Simopt = Opciones del simulador
-simedtdlg.lbl.Calcmethod = Método de cálculo
-simedtdlg.lbl.ttip.Calcmethod = <html>El método Barrowman extendido considera las fuerzas aerodinámicas <br>que actúan sobre cuerpos cilíndricos en cohetes que vuelan con un <br>ángulo de ataque (AOA) superior a 10 grados.
-simedtdlg.lbl.ExtBarrowman = Barrowman Extendido
-simedtdlg.lbl.Simmethod = Método de simulación:
-simedtdlg.lbl.ttip.Simmethod1 = <html>El simulador de seis-grados-de-libertad permite al cohete una total libertad durante el vuelo.<br>
-simedtdlg.lbl.ttip.Simmethod2 = La integración mejora usando el método de integración numérica Runge-Kutta de cuarto orden.
-simedtdlg.lbl.GeodeticMethod = Cálculos geodésicos:
-simedtdlg.lbl.ttip.GeodeticMethodTip = En relación al cálculo de las coordenadas terrestres. Esto también activa los cálculos del Efecto Coriolis.
-simedtdlg.lbl.Timestep = Duración de la etapa
-simedtdlg.lbl.ttip.Timestep1 = <html>Tiempo entre etapas de simulación.<br>Un tiempo mas corto de etapa origina una simulación mas exacta pero mas lenta.<br>
-simedtdlg.lbl.ttip.Timestep2 = Con 4<sup>th</sup> el método de ordenar en la simulación es bastante preciso con un tiempo de etapa de
-simedtdlg.but.ttip.resettodefault = Restituir el tiempo de etapa a su valor por defecto (
-simedtdlg.border.Simlist = Extensiones del simulador
-simedtdlg.txt.longA1 = <html><i>Extensiones del simulador</i> es una característica avanzada que permite que el código escrito por un usuario pueda conectar e interactuar con la simulación mientras ésta se está ejecutando.  
-simedtdlg.txt.longA2 = Para más detalles sobre las Extensiones, vea la documentación técnica de Open Rocket.
-simedtdlg.lbl.Curlist = Extensiones actuales
-simedtdlg.lbl.Addsimlist = Añadir una Extensión al simulador
-simedtdlg.lbl.Noflightdata = No hay datos disponibles del vuelo.
-simedtdlg.lbl.runsimfirst = Por favor accione la simulación primero.
-simedtdlg.chart.Simflight = Vuelo simulado
-simedtdlg.dlg.Simres = Resultados de la simulación
-simedtdlg.IntensityDesc.None = Ninguno
-simedtdlg.IntensityDesc.Verylow = Muy pesado
-simedtdlg.IntensityDesc.Low = Pesado
-simedtdlg.IntensityDesc.Medium = Medio
-simedtdlg.IntensityDesc.High = Alto
-simedtdlg.IntensityDesc.Veryhigh = Muy alto
-simedtdlg.IntensityDesc.Extreme = Extremo
-
-GeodeticComputationStrategy.none.name = Ninguna
-GeodeticComputationStrategy.none.desc = No incluir computaciones geodésicas.
-GeodeticComputationStrategy.spherical.name = Aproximación esférica
-GeodeticComputationStrategy.spherical.desc = <html>Al incluir las computaciones geodésicas se considera una Tierra esférica.<br>Este aspecto es bastante preciso en la mayoría de los proyectos.
-GeodeticComputationStrategy.wgs84.name = Elipsoidal WGS84
-GeodeticComputationStrategy.wgs84.desc = <html>Incluye las computaciones geodésicas sobre la referencia elipsoidal WGS84 utilizando el método de Vicenty.<br>Este aspecto es lento e innecesario en la mayoría de los casos.
-
-
-
-
-! Simulation Panel
-simpanel.but.newsimulation = Nueva simulación
-simpanel.but.editsimulation = Editar la simulación
-simpanel.but.runsimulations = Lanzar las simulaciones
-simpanel.but.deletesimulations = Borrar las simulaciones
-simpanel.but.plotexport = Exportar / Gráfica
-simpanel.but.ttip.newsimulation = Añadir una nueva simulación
-simpanel.but.ttip.editsim = Mostrar la simulación seleccionada
-simpanel.but.ttip.runsimu = Ejecutar de nuevo las simulaciones seleccionadas
-simpanel.but.ttip.deletesim = Borrar las simulaciones seleccionadas
-simpanel.checkbox.donotask = No preguntarme de nuevo
-simpanel.lbl.defpref = Puede cambiar la operación por defecto por las preferencias
-simpanel.dlg.lbl.DeleteSim1 = ¿Borrar las simulaciones seleccionadas?
-simpanel.dlg.lbl.DeleteSim2 = <html><i>Esta operación no puede deshacerse.</i>
-simpanel.dlg.lbl.DeleteSim3 = Borrar las simulaciones
-simpanel.col.Name = Nombre
-simpanel.col.Motors = Motores
-simpanel.col.Apogee = Apogeo
-simpanel.col.Maxvelocity = Velocidad máxima
-simpanel.col.Maxacceleration = Aceleración máxima
-simpanel.col.Timetoapogee = Tiempo hasta el apogeo
-simpanel.col.Flighttime = Duración del vuelo
-simpanel.col.Groundhitvelocity = Velocidad de llegada a tierra
-
-! SimulationRunDialog
-SimuRunDlg.title.RunSim = Ejecutar simulaciones
-SimuRunDlg.lbl.Running = Ejecutar
-SimuRunDlg.lbl.Simutime = Duración de la simulación:
-SimuRunDlg.lbl.Altitude = Altitud:
-SimuRunDlg.lbl.Velocity = Velocidad:
-SimuRunDlg.msg.Unabletosim = Incapaz de simular:
-SimuRunDlg.msg.errorOccurred = Ha ocurrido un error durante la simulación:
-SimuRunDlg.msg.AnException1 = Ha ocurrido una excepción durante la simulación:
-SimuRunDlg.msg.AnException2 = Por favor anote esto debajo como un error con todos los detalles.
-SimuRunDlg.msg.AssertionError1 = Se ha producido un error informático durante la simulación.
-SimuRunDlg.msg.AssertionError2 = Por favor anote esto debajo como un error con todos los detalles.
-SimuRunDlg.msg.unknownerror1 = Se ha detectado un error desconocido durante la simulación.
-SimuRunDlg.msg.unknownerror2 = El programa puede ser inestable, Guarde todos sus diseños y reinicie OpenRocket
-
-
-! SimulationExportPanel
-SimExpPan.desc = Documentos separados por comas (*.csv)
-SimExpPan.border.Vartoexport = Variables para exportar
-SimExpPan.but.Selectall = Seleccionar todo
-SimExpPan.but.Selectnone = No seleccionar nada
-SimExpPan.border.Fieldsep = Separador de campo
-SimExpPan.lbl.Fieldsepstr = Caracter separador de campo
-SimExpPan.lbl.longA1 = <html>Caracter para separar campos en el documento exportado.<br>
-SimExpPan.lbl.longA2 = Para valores separados en archivo (CSV) use comas ','.
-SimExpPan.checkbox.Includesimudesc = Incluir descripción de la simulación
-SimExpPan.checkbox.ttip.Includesimudesc = Incluye un comentario en el inicio del documento describiendo la simulación.
-SimExpPan.border.Comments = Comentarios
-SimExpPan.checkbox.Includefielddesc = Incluir descripciones del campo
-SimExpPan.checkbox.ttip.Includefielddesc = Incluye una línea de comentario con las descripciones de las variables exportadas.
-SimExpPan.checkbox.Incflightevents = Incluir los eventos del vuelo
-SimExpPan.checkbox.ttip.Incflightevents = Incluye una línea de comentario para cada evento del vuelo
-SimExpPan.lbl.Commentchar = Carácter de comentario
-SimExpPan.lbl.ttip.Commentchar = Características que marcan una línea de comentario.
-SimExpPan.but.Exporttofile = Exportar al documento ...
-SimExpPan.Fileexists.desc1 = Archivo \"
-SimExpPan.Fileexists.desc2 = \" ya existe.  ¿Desea sobrescribirlo?
-SimExpPan.Fileexists.title = El archivo ya existe
-SimExpPan.ExportingVar.desc1 = Exportar variables
-SimExpPan.ExportingVar.desc2 = Exportar
-SimExpPan.ExportingVar.desc3 = variables de
-SimExpPan.Col.Variable = Variable
-SimExpPan.Col.Unit = Unidad
-
-
-CsvOptionPanel.separator.space = SPACE
-CsvOptionPanel.separator.tab = TAB
-
-
-
-! MotorPlot
-MotorPlot.title.Motorplot = Curva del motor
-MotorPlot.but.Select = Seleccionar la configuración del motor a usar
-MotorPlot.Chart.Motorthrustcurve = Curva de empuje del motor
-MotorPlot.Chart.Time = Tiempo / s
-MotorPlot.Chart.Thrust = Empuje / N
-MotorPlot.txt.Designation = Designación:
-MotorPlot.txt.Manufacturer = Fabricante:
-MotorPlot.txt.Type = Tipo:
-MotorPlot.txt.Delays = Retardos:
-MotorPlot.txt.Comment = Comentario:\n
-
-
-
-! Simulation plot panel
-simplotpanel.lbl.Presetplotconf = Configuración de la gráfica:
-simplotpanel.lbl.Xaxistype = Tipo de eje X:
-simplotpanel.lbl.Unit = Unidad:
-simplotpanel.lbl.Yaxistypes = Tipo de eje Y:
-simplotpanel.lbl.Flightevents = Eventos del vuelo:
-simplotpanel.but.All = Todo
-simplotpanel.but.None = Ninguno
-simplotpanel.but.NewYaxisplottype = Añadir nuevo eje Y en la gráfica
-simplotpanel.but.Plotflight = Ver gráfica
-simplotpanel.lbl.Axis = Ejes:
-simplotpanel.but.ttip.Removethisplot = Eliminar esta curva
-simplotpanel.Desc = Si no hay línea de tiempo, los datos aparecerán en el eje X según el instante en que se producen. 
-simplotpanel.OptionPane.lbl1 = Se permite un máximo de 15 impresiones
-simplotpanel.OptionPane.lbl2 = No puede añadirse la curva
-simplotpanel.AUTO_NAME = Auto
-simplotpanel.LEFT_NAME = Izquierda
-simplotpanel.RIGHT_NAME = Derecha
-simplotpanel.CUSTOM = Personalizado
-
-! Component add buttons
-compaddbuttons.Bodycompandfinsets = Componentes del fuselaje y aletas
-compaddbuttons.Nosecone = Ojiva
-compaddbuttons.Bodytube = Cuerpo\ntubular
-compaddbuttons.Transition = Transición
-compaddbuttons.Trapezoidal = Trapezoidal
-compaddbuttons.Elliptical = Elíptica
-compaddbuttons.Freeform = Forma libre
-compaddbuttons.Launchlug = Soporte\npara guía
-compaddbuttons.Innercomponent = Componentes internos
-compaddbuttons.Innertube = Tubo\ninterior
-compaddbuttons.Coupler = Acoplador
-compaddbuttons.Centeringring = Anillo\nde centrado
-compaddbuttons.Bulkhead = Disco\nde enganche
-compaddbuttons.Engineblock = Retén\nde motor
-compaddbuttons.Massobjects = Accesorios
-compaddbuttons.Parachute = Paracaídas
-compaddbuttons.Streamer = Banderola
-compaddbuttons.Shockcord = Tirante de\nsuspensión
-compaddbuttons.Masscomponent = Componente\nmasa
-compaddbuttons.Donotaskmeagain = No me pregunte de nuevo
-compaddbuttons.Selectcomppos = Seleccionar la posición del componente
-compaddbuttons.lbl.Youcanchange = Puede cambiar la operación con las preferencias por defecto
-compaddbuttons.lbl.insertcomp = ¿Insertar el componente después del actual o al final?
-compaddbuttons.askPosition.Inserthere = Insertar aquí
-compaddbuttons.askPosition.Addtotheend = Añadir al final
-compaddbuttons.askPosition.Cancel = Cancelar
-
-! Component Analysis Dialog
-componentanalysisdlg.componentanalysis = Análisis de los componentes
-componentanalysisdlg.lbl.winddir = Dirección del viento:
-componentanalysisdlg.TitledBorder.warnings = Advertencias:
-componentanalysisdlg.ToggleBut.worst = Peor
-componentanalysisdlg.lbl.angleofattack = Ángulo de ataque:
-componentanalysisdlg.lbl.machnumber = Número Mach:
-componentanalysisdlg.lbl.rollrate = Valor de rotación:
-componentanalysisdlg.lbl.activestages = Etapas activas:
-componentanalysisdlg.lbl.motorconf = Configuración del Motor:
-componentanalysisdlg.TabStability.Col = Componente
-componentanalysisdlg.TabStability = Estabilidad
-componentanalysisdlg.TabStability.ttip = Información de Estabilidad
-componentanalysisdlg.dragTableModel.Col.Component = Componente
-componentanalysisdlg.dragTableModel.Col.Pressure = <html>Presión C<sub>D</sub>
-componentanalysisdlg.dragTableModel.Col.Base = <html>Base C<sub>D</sub>
-componentanalysisdlg.dragTableModel.Col.friction = <html>Rozamiento C<sub>D</sub>
-componentanalysisdlg.dragTableModel.Col.total = <html>Total C<sub>D</sub>
-componentanalysisdlg.dragTabchar = Características de rozamiento
-componentanalysisdlg.dragTabchar.ttip = Coeficientes de arrastre de los componentes.
-componentanalysisdlg.rollTableModel.Col.component = Componente
-componentanalysisdlg.rollTableModel.Col.rollforc = Coeficiente de rotación
-componentanalysisdlg.rollTableModel.Col.rolldamp = Coeficiente de corrección
-componentanalysisdlg.rollTableModel.Col.total = <html>Total C<sub>l</sub>
-componentanalysisdlg.rollTableModel = Dinámica de rotación
-componentanalysisdlg.rollTableModel.ttip = Dinámica del movimiento de rotación del cohete (spin)
-componentanalysisdlg.println.closingmethod = Llamar al método de cierre:
-componentanalysisdlg.println.settingnam = CONFIGURANDO VALORES NAN
-componentanalysisdlg.lbl.reflenght = Diámetro de referencia: 
-componentanalysisdlg.lbl.refarea = Área de referencia: 
-!componentanalysisdlg.But.close = Cerrar
-componentanalysisdlg.TabStability.Col.Component = Componente
-
-! Custom Material dialog
-custmatdlg.title.Custommaterial = Material personalizado
-custmatdlg.lbl.Materialname = Nombre del material: 
-custmatdlg.lbl.Materialtype = Tipo de material:
-custmatdlg.lbl.Materialdensity = Densidad del material:
-custmatdlg.checkbox.Addmaterial = Agregar este material a la base de datos
-
-
-! Ring Component Config
-ringcompcfg.OuterRadius = Radio exterior:
-ringcompcfg.Automatic = Automático
-ringcompcfg.InnerRadius = Radio interior:
-ringcompcfg.Thickness = Espesor:
-ringcompcfg.Length = Longitud:
-ringcompcfg.Positionrelativeto = Posición relativa a:
-ringcompcfg.plus = Localización:
-ringcompcfg.PositionValue = Valor de posición:
-ringcompcfg.Radialdistance = Distancia radial:
-ringcompcfg.Distancefrom = Distancia desde la línea central del cohete:
-ringcompcfg.Radialdirection = Dirección radial:
-ringcompcfg.radialdirectionfrom = En dirección radial desde la línea central del cohete
-ringcompcfg.but.Reset = Reiniciar
-ringcompcfg.but.Resetcomponant = Reubicar el componente en la línea central del cohete
-ringcompcfg.EngineBlock.desc = <html>Un <b>retén de motor</b> impide que el motor se desplace hacia delante, por dentro del tubo porta motor.<br><br>Para añadir un motor, cree un <b>Cuerpo tubular</b> o <b>Tubo interior</b> y desígnelo como porta motor en la pestaña <em>Motor</em>.
-ringcompcfg.note.desc = Nota: El tubo interior no afectará a la aerodinámica del cohete salvo que esté situado fuera del fuselaje.
-
-
-! Body Tube Config
-BodyTubecfg.lbl.Bodytubelength = Longitud del tubo:
-BodyTubecfg.lbl.Outerdiameter = Diámetro exterior:
-BodyTubecfg.lbl.Innerdiameter = Diámetro interior:
-BodyTubecfg.lbl.Wallthickness = Espesor de la pared:
-BodyTubecfg.tab.General = General
-BodyTubecfg.tab.Generalproperties = Propiedades generales
-BodyTubecfg.tab.Motor = Motor
-BodyTubecfg.tab.Motormountconf = Configuración del porta motor
-BodyTubecfg.checkbox.Automatic = Automático
-BodyTubecfg.checkbox.Filled = Sólido
-
-! FinSetConfig
-FinSetConfig.tab.Fintabs = Raíz de aleta
-FinSetConfig.tab.Through-the-wall = Parte de la aleta por dentro del fuselaje
-FinSetConfig.but.Converttofreeform = Convertir a forma libre
-FinSetConfig.but.Converttofreeform.ttip = Convertir esta forma de aleta a una forma libre
-FinSetConfig.Convertfinset = Convertir la configuración de aleta
-FinSetConfig.but.Splitfins = Separar las aletas
-FinSetConfig.but.Splitfins.ttip = Dividir la configuración de aleta en varias separadas
-FinSetConfig.lbl.Through-the-wall  = Raíces de aleta a través de la pared: 
-FinSetConfig.lbl.Tablength = Longitud de la raíz:
-FinSetConfig.ttip.Tablength = La longitud de la raíz de aleta.
-FinSetConfig.lbl.Tabheight = Altura de la raíz: 
-FinSetConfig.ttip.Tabheight = Envergadura en altura de la raíz de aleta.
-FinSetConfig.lbl.Tabposition = Posición de la raíz:
-FinSetConfig.ttip.Tabposition = Posición de la raíz de aleta.
-FinSetConfig.lbl.relativeto = Relativo a
-
-! MotorDatabaseLoadingDialog
-MotorDbLoadDlg.title = Carga de motores
-MotorDbLoadDlg.Loadingmotors = Cargando motores...
-
-! RocketConfig
-RocketCfg.lbl.Designname = Nombre del proyecto:
-RocketCfg.lbl.Designer = Proyectista:
-RocketCfg.lbl.Comments = Comentarios:
-RocketCfg.lbl.Revisionhistory = Histórico de la revisión:
-RocketCfg.lbl.Material = Material:
-
-! ShockCordConfig
-ShockCordCfg.lbl.Shockcordlength = Longitud del tirante de suspensión
-
-! RocketComponentConfig
-RocketCompCfg.lbl.Componentname = Nombre del componente:
-RocketCompCfg.ttip.Thecomponentname = El nombre del componente.
-RocketCompCfg.tab.Override = Masa y CG
-RocketCompCfg.tab.MassandCGoverride = Especificar la Masa y el CG del componente.
-RocketCompCfg.tab.Figure = Estilo
-RocketCompCfg.tab.Figstyleopt = Opciones de estilo de la figura
-RocketCompCfg.tab.Comment = Comentarios
-RocketCompCfg.tab.Specifyacomment = Especifique un comentario para el componente
-RocketCompCfg.lbl.Mass = Masa:
-RocketCompCfg.lbl.Componentmass = Masa del componente:
-RocketCompCfg.lbl.overriddento = (Elegido para
-RocketCompCfg.lbl.overriddenby = (Elegido por
-RocketCompCfg.lbl.Componentmaterial = Material del componente:
-RocketCompCfg.lbl.Componentfinish = Acabado:
-RocketCompCfg.lbl.ttip.componentmaterialaffects = El material del componente afecta a la masa total del modelo.
-RocketCompCfg.combo.ttip.componentmaterialaffects = El material del componente afecta su peso.
-RocketCompCfg.lbl.longA1 = <html>El acabado del componente afecta a su coeficiente de rozamiento.<br>
-RocketCompCfg.lbl.longA2 = El valor indicado es el promedio de la rugosidad en altura de la superficie.
-RocketCompCfg.but.Setforall = Aplicar a todos
-RocketCompCfg.but.ttip.Setforall = Aplicar este acabado a todos los componentes del cohete.
-RocketCompCfg.lbl.Overridemassorcenter = Especificar la masa y el CG del componente 
-RocketCompCfg.checkbox.Overridemass = Especificar la masa:
-RocketCompCfg.checkbox.Overridecenterofgrav = Especificar el CG:
-RocketCompCfg.checkbox.OverridemassandCG = Incluir la masa y el CG de todos los subcomponentes
-RocketCompCfg.lbl.longB1 = <html>En la masa especificada no se incluye la de los motores.<br>
-RocketCompCfg.lbl.longB2 = El CG se mide desde el extremo frontal del componente  
-RocketCompCfg.lbl.Commentsonthe = Comentarios sobre
-RocketCompCfg.lbl.Figurestyle = Estilo de dibujo:
-RocketCompCfg.lbl.Componentcolor = Color del componente:
-RocketCompCfg.lbl.Choosecolor = Elija color
-RocketCompCfg.checkbox.Usedefaultcolor = Usar color por defecto
-RocketCompCfg.lbl.Complinestyle = Estilo de línea del componente:
-RocketCompCfg.but.Saveasdefstyle = Guardar como estilo por defecto
-RocketCompCfg.lbl.Diameter = Diámetro:
-RocketCompCfg.lbl.Length = Longitud:
-RocketCompCfg.lbl.Thickness = Espesor:
-RocketCompCfg.checkbox.Endcapped = Extremo truncado
-RocketCompCfg.ttip.Endcapped = Si el extremo del soporte está truncado.
-RocketCompCfg.title.Noseconeshoulder = Acople de la ojiva
-RocketCompCfg.title.Aftshoulder = Trasera del acople
-RocketCompCfg.border.Foreshoulder = Delantera del acople
-!RocketCompCfg.lbl.Length = Longitud:
-
-! BulkheadConfig
-BulkheadCfg.tab.Diameter = Diámetro:
-BulkheadCfg.tab.Thickness = Espesor:
-BulkheadCfg.tab.General = General
-BulkheadCfg.tab.Generalproperties = Propiedades generales
-
-!CenteringRingConfig
-CenteringRingCfg.tab.Outerdiam = Diámetro exterior:
-CenteringRingCfg.tab.Innerdiam = Diámetro interior:
-CenteringRingCfg.tab.Thickness = Espesor:
-CenteringRingCfg.tab.General = General
-CenteringRingCfg.tab.Generalproperties = Propiedades generales
-
-!ComponentConfigDialog
-ComponentCfgDlg.configuration = 
-ComponentCfgDlg.configuration1 = Configuración
-ComponentCfgDlg.Modify = Modificar
-
-!EllipticalFinSetConfig
-EllipticalFinSetCfg.Nbroffins = Número de aletas:
-EllipticalFinSetCfg.Rotation = Rotación de las aletas:
-EllipticalFinSetCfg.Fincant = Inclinación de las aletas:
-EllipticalFinSetCfg.Rootchord = Longitud línea base:
-EllipticalFinSetCfg.Height = Altura:
-EllipticalFinSetCfg.Positionrelativeto = Posición relativa a:
-EllipticalFinSetCfg.plus = Localización:
-EllipticalFinSetCfg.FincrossSection = Borde de la aleta:
-EllipticalFinSetCfg.Thickness = Espesor:
-EllipticalFinSetCfg.General = General
-EllipticalFinSetCfg.Generalproperties = Propiedades generales
-EllipticalFinSetCfg.ttip.Fincant = El ángulo de inclinación de las aletas respecto al eje central del fuselaje.
-
-!FreeformFinSetConfig
-FreeformFinSetCfg.tab.General = General
-FreeformFinSetCfg.tab.ttip.General = Propiedades generales
-FreeformFinSetCfg.tab.Shape = Forma
-FreeformFinSetCfg.tab.ttip.Finshape = Forma de la aleta
-FreeformFinSetCfg.lbl.Numberoffins = Número de aletas:
-FreeformFinSetCfg.lbl.Finrotation = Rotación de las aletas:
-FreeformFinSetCfg.lbl.Fincant = Inclinación de las aletas:
-FreeformFinSetCfg.lbl.ttip.Fincant = El ángulo de inclinación de las aletas respecto al eje central del fuselaje.
-FreeformFinSetCfg.lbl.Posrelativeto = Posición relativa a:
-FreeformFinSetCfg.lbl.plus = Localización:
-FreeformFinSetCfg.lbl.FincrossSection = Borde de la aleta:
-FreeformFinSetCfg.lbl.Thickness = Espesor:
-!DobleClic 1 + 2 en el mensaje "Doble-Click para editar", corta aproximadamente por la mitad
-FreeformFinSetConfig.lbl.doubleClick1 = Doble Click en la lista
-FreeformFinSetConfig.lbl.doubleClick2 = para editar
-FreeformFinSetConfig.lbl.clickDrag = Click (sobre línea)+arrastrar: Agregar punto
-FreeformFinSetConfig.lbl.ctrlClick = Control+Click (sobre punto): Eliminar punto
-FreeformFinSetConfig.lbl.scaleFin = Scale Fin
-
-!InnerTubeConfig
-InnerTubeCfg.tab.Motor = Motor
-InnerTubeCfg.tab.ttip.Motor = Configuración del porta motor
-InnerTubeCfg.tab.Cluster = Cluster
-InnerTubeCfg.tab.ttip.Cluster = Configuración del cluster
-InnerTubeCfg.tab.Radialpos = Posición radial
-InnerTubeCfg.tab.ttip.Radialpos = Posición radial
-InnerTubeCfg.lbl.Selectclustercfg = Elija la configuración del cluster:
-InnerTubeCfg.lbl.TubeSep = Separación del tubo:
-InnerTubeCfg.lbl.ttip.TubeSep = Una separación de los tubos con valor 1.0 indica que están tocándose unos con otros
-InnerTubeCfg.lbl.Rotation = Rotación:
-InnerTubeCfg.lbl.ttip.Rotation = Configuración del ángulo de rotación del cluster
-InnerTubeCfg.lbl.Rotangle = Angulo de rotación del cluster
-InnerTubeCfg.but.Splitcluster = Tubos independientes
-InnerTubeCfg.lbl.longA1 = <html>Separar los tubos del cluster para convertirlos en componentes internos independientes.<br>
-InnerTubeCfg.lbl.longA2 = Esto también duplica todos los componentes unidos a este tubo interior.
-InnerTubeCfg.but.Resetsettings = Reiniciar configuración
-InnerTubeCfg.but.ttip.Resetsettings = Reiniciar la separación y la rotación con los valores predeterminados
-
-! LaunchLugConfig
-LaunchLugCfg.lbl.Length = Longitud:
-LaunchLugCfg.lbl.Outerdiam = Diámetro exterior:
-LaunchLugCfg.lbl.Innerdiam = Diámetro interior:
-LaunchLugCfg.lbl.Thickness = Espesor:
-LaunchLugCfg.lbl.Radialpos = Posición radial:
-LaunchLugCfg.lbl.Posrelativeto = Posición relativa a:
-LaunchLugCfg.lbl.plus = Localización:
-LaunchLugCfg.tab.General = General
-LaunchLugCfg.tab.Generalprop = Propiedades generales
-
-! MassComponentConfig
-MassComponentCfg.lbl.Mass = Masa:
-MassComponentCfg.lbl.Length = Longitud:
-MassComponentCfg.lbl.Diameter = Diámetro:
-MassComponentCfg.lbl.PosRelativeto = Posición relativa a:
-MassComponentCfg.lbl.plus = Localización:
-MassComponentCfg.tab.General = General
-MassComponentCfg.tab.ttip.General = Propiedades generales
-MassComponentCfg.tab.Radialpos = Posición radial
-MassComponentCfg.tab.ttip.Radialpos = Configuración de la posición radial
-MassComponentCfg.lbl.Radialdistance = Distancia radial:
-MassComponentCfg.lbl.Radialdirection = Dirección radial:
-MassComponentCfg.but.Reset = Reiniciar
-
-! MotorConfig
-MotorCfg.checkbox.compmotormount = Este componente es un porta motor
-MotorCfg.lbl.Motorcfg = Configuración del motor:
-MotorCfg.but.New = Nuevo
-MotorCfg.lbl.Currentmotor = Motor actual:
-MotorCfg.lbl.Motoroverhang = Sobresalida del motor:
-MotorCfg.lbl.Ignitionat = Encendido en:
-MotorCfg.lbl.plus = Retardo:
-MotorCfg.lbl.seconds = segundos.
-MotorCfg.lbl.longA1 = El diseño actual tiene una sola etapa.
-MotorCfg.lbl.longA2 = Pueden agregarse etapas haciendo Click en \"Nueva etapa\".
-MotorCfg.lbl.longB1 = El diseño actual tiene
-MotorCfg.lbl.longB2 = etapas.
-MotorCfg.but.Selectmotor = Seleccionar motor
-MotorCfg.but.Removemotor = Quitar motor
-MotorCfg.lbl.motorLabel = Ninguno
-
-! NoseConeConfig
-NoseConeCfg.lbl.Noseconeshape = Forma:
-NoseConeCfg.lbl.Shapeparam = Valor de forma:
-NoseConeCfg.lbl.Noseconelength = Longitud:
-NoseConeCfg.lbl.Basediam = Diámetro de la base:
-NoseConeCfg.checkbox.Automatic = Automático
-NoseConeCfg.lbl.Wallthickness = Espesor de la pared:
-NoseConeCfg.checkbox.Filled = Sólido
-NoseConeCfg.tab.General = General
-NoseConeCfg.tab.ttip.General = Propiedades generales
-NoseConeCfg.tab.Shoulder = Acoplamiento
-NoseConeCfg.tab.ttip.Shoulder = Propiedades del acople
-
-! ParachuteConfig
-ParachuteCfg.lbl.Canopy = Pabellón
-ParachuteCfg.lbl.Diameter = Diámetro:
-ParachuteCfg.lbl.Material = Material:
-ParachuteCfg.combo.MaterialModel = El material del componente afecta a su peso.
-ParachuteCfg.lbl.longA1 = <html>Coeficiente de arrastre C<sub>D</sub>:
-ParachuteCfg.lbl.longB1 = <html>Coeficiente de rozamiento relativo al área total del paracaídas.<br>
-ParachuteCfg.lbl.longB2 = Un mayor coeficiente de rozamiento genera un valor de descenso más lento.  
-ParachuteCfg.lbl.longB3 = Un valor típico para los paracaídas es 0,8.
-ParachuteCfg.but.Reset = Reiniciar
-ParachuteCfg.lbl.Shroudlines = Cuerdas:
-ParachuteCfg.lbl.Numberoflines = Número de cuerdas:
-ParachuteCfg.lbl.Linelength = Longitud de cuerda:
-ParachuteCfg.lbl.Material = Material:
-ParachuteCfg.lbl.Posrelativeto = Posición relativa a:
-ParachuteCfg.lbl.plus = Localización:
-ParachuteCfg.lbl.Packedlength = Longitud empaquetado:
-ParachuteCfg.lbl.Packeddiam = Diámetro del empaquetado:
-ParachuteCfg.lbl.Deploysat = Despliegue en:
-ParachuteCfg.lbl.seconds = segundos.
-ParachuteCfg.lbl.Altitude = Altitud:
-ParachuteCfg.tab.General = General
-ParachuteCfg.tab.ttip.General = Propiedades generales
-ParachuteCfg.tab.Radialpos = Posición radial
-ParachuteCfg.tab.ttip.Radialpos = Configuración de la posición radial
-ParachuteCfg.lbl.Radialdistance = Distancia radial:
-ParachuteCfg.lbl.Radialdirection = Dirección radial:
-ParachuteCfg.but.Reset = Reiniciar
-ParachuteCfg.lbl.plusdelay = Retardo:
-
-
-! ShockCordConfig 
-ShockCordCfg.lbl.Shockcordlength = Longitud del tirante de suspensión
-ShockCordCfg.lbl.Shockcordmaterial = Material del tirante de suspensión:
-ShockCordCfg.lbl.Posrelativeto = Posición relativa a:
-ShockCordCfg.lbl.plus = Localización:
-ShockCordCfg.lbl.Packedlength = Longitud del empaquetado:
-ShockCordCfg.lbl.Packeddiam = Diámetro del empaquetado:
-ShockCordCfg.tab.General = General
-ShockCordCfg.tab.ttip.General = Propiedades generales
-
-!SleeveConfig
-SleeveCfg.tab.Outerdiam = Diámetro exterior:
-SleeveCfg.tab.Innerdiam = Diámetro interior:
-SleeveCfg.tab.Wallthickness = Espesor de la pared:
-SleeveCfg.tab.Length = Longitud:
-SleeveCfg.tab.General = General
-SleeveCfg.tab.Generalproperties = Propiedades generales
-
-! StreamerConfig
-StreamerCfg.lbl.Striplength = Longitud de la cinta:
-StreamerCfg.lbl.Stripwidth = Ancho de la cinta:
-StreamerCfg.lbl.Striparea = Área de la cinta:
-StreamerCfg.lbl.Aspectratio = Relación de aspecto:
-StreamerCfg.lbl.Material = Material:
-StreamerCfg.combo.ttip.MaterialModel = El material del componente afecta a su peso.
-StreamerCfg.lbl.longA1 = <html>Coeficiente de rozamiento C<sub>D</sub>:
-StreamerCfg.lbl.longB1 = <html>Coeficiente de rozamiento relativo al área total de la banderola.<br>
-StreamerCfg.lbl.longB2 = Un mayor coeficiente de rozamiento genera un valor de descenso más lento.
-StreamerCfg.lbl.Automatic = Automático
-StreamerCfg.lbl.longC1 = El coeficiente de rozamiento depende del área de la banderola.
-StreamerCfg.lbl.Posrelativeto = Posición relativa a:
-StreamerCfg.lbl.plus = Localización:
-StreamerCfg.lbl.Packedlength = Longitud de empaquetado:
-StreamerCfg.lbl.Packeddiam = Diámetro de empaquetado:
-StreamerCfg.lbl.Deploysat = Despliegue en:
-StreamerCfg.lbl.seconds = segundos.
-StreamerCfg.lbl.Altitude = Altitud:
-StreamerCfg.tab.General = General
-StreamerCfg.tab.ttip.General = Propiedades generales
-StreamerCfg.tab.Radialpos = Posición radial
-StreamerCfg.tab.ttip.Radialpos = Configuración de posición radial
-StreamerCfg.lbl.Radialdistance = Distancia radial:
-StreamerCfg.lbl.Radialdirection = Dirección radial:
-StreamerCfg.but.Reset = Reiniciar
-StreamerCfg.lbl.plusdelay = Retardo:
-
-! ThicknessRingComponentConfig
-ThicknessRingCompCfg.tab.Outerdiam = Diámetro exterior:
-ThicknessRingCompCfg.tab.Innerdiam = Diámetro Interior:
-ThicknessRingCompCfg.tab.Wallthickness = Espesor de la pared:
-ThicknessRingCompCfg.tab.Length = Longitud:
-ThicknessRingCompCfg.tab.General = General
-ThicknessRingCompCfg.tab.Generalprop = Propiedades generales
-
-! TransitionConfig
-TransitionCfg.lbl.Transitionshape = Forma de la transición:
-TransitionCfg.checkbox.Clipped = Acortado
-TransitionCfg.lbl.Shapeparam = Valor de forma:
-TransitionCfg.lbl.Transitionlength = Longitud de la transición:
-TransitionCfg.lbl.Forediam = Diámetro delantero:
-TransitionCfg.checkbox.Automatic = Automático
-TransitionCfg.lbl.Aftdiam = Diámetro trasero:
-TransitionCfg.lbl.Wallthickness = Espesor de la pared:
-TransitionCfg.checkbox.Filled = Sólido
-TransitionCfg.tab.General = General
-TransitionCfg.tab.Generalproperties = Propiedades generales
-TransitionCfg.tab.Shoulder = Acoplamiento
-TransitionCfg.tab.Shoulderproperties = Propiedades del acople
-
-! TrapezoidFinSetConfig
-TrapezoidFinSetCfg.lbl.Nbroffins = Número de aletas:
-TrapezoidFinSetCfg.lbl.ttip.Nbroffins = Número de aletas en la base de aletas.
-TrapezoidFinSetCfg.lbl.Finrotation = Rotación de las aletas:
-TrapezoidFinSetCfg.lbl.ttip.Finrotation = Posición de las aletas alrededor del fuselaje.
-TrapezoidFinSetCfg.lbl.Fincant = Inclinación de las aletas:
-TrapezoidFinSetCfg.lbl.ttip.Fincant = El ángulo de inclinación de las aletas respecto al eje central del fuselaje.
-TrapezoidFinSetCfg.lbl.Rootchord = Longitud de la línea base:
-TrapezoidFinSetCfg.lbl.Tipchord = Longitud del borde superior:
-TrapezoidFinSetCfg.lbl.Height = Altura:
-TrapezoidFinSetCfg.lbl.Sweeplength = Desplazamiento borde superior:
-TrapezoidFinSetCfg.lbl.Sweepangle = Ángulo del borde de ataque:
-TrapezoidFinSetCfg.lbl.FincrossSection = Borde de la aleta:
-TrapezoidFinSetCfg.lbl.Thickness = Espesor:
-TrapezoidFinSetCfg.lbl.Posrelativeto = Posición relativa a:
-TrapezoidFinSetCfg.lbl.plus = Localización:
-TrapezoidFinSetCfg.tab.General = General
-TrapezoidFinSetCfg.tab.Generalproperties = Propiedades generales
-
-!MotorConfigurationModel
-MotorCfgModel.Editcfg = Editar configuraciones
-
-! StorageOptionChooser
-StorageOptChooser.lbl.Simdatatostore = Almacenar datos simulados
-StorageOptChooser.rdbut.Allsimdata = Todos los datos simulados
-StorageOptChooser.lbl.longA1 = <html>Almacenar todos los datos simulados.<br>
-StorageOptChooser.lbl.longA2 = puede generar archivos muy grandes
-StorageOptChooser.rdbut.Every = Cada
-StorageOptChooser.lbl.longB1 = <html>Almacenar los valores de impresión de este apartado.<br>
-StorageOptChooser.lbl.longB2 = Genera valores grandes en archivos más pequeños.
-StorageOptChooser.lbl.seconds = Segundos
-StorageOptChooser.rdbut.Onlyprimfig = Sólo figuras principales
-StorageOptChooser.lbl.longC1 = <html>Almacenar sólo los valores en la tabla resumen.<br>
-StorageOptChooser.lbl.longC2 = Estos resultados se guardan en archivos mas pequeños.
-StorageOptChooser.checkbox.Compfile = Archivo comprimido
-StorageOptChooser.lbl.UsingComp = Usando la compresión reducimos el tamaño de los archivos. 
-StorageOptChooser.lbl.longD1 = Con las opciones actuales puede realizarse una estamción del tamaño final del archivo.
-StorageOptChooser.ttip.Saveopt = Guardar opciones
-StorageOptChooser.lbl.Estfilesize = Estimación del tamaño del archivo:
-StorageOptChooser.lbl.Saveopt = Guardar opciones
-
-! ThrustCurveMotorSelectionPanel
-TCMotorSelPan.lbl.Selrocketmotor = Seleccione el motor del cohete:
-TCMotorSelPan.checkbox.hideSimilar = Borrar las curvas muy similares
-TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = Mostrar todos los motores
-TCMotorSelPan.SHOW_DESCRIPTIONS.desc2 = Mostrar motores con diámetro inferior al del tubo portamotor
-TCMotorSelPan.SHOW_DESCRIPTIONS.desc3 = Mostrar motores con diámetro igual al del tubo portamotor
-TCMotorSelPan.lbl.Motormountdia = Diámetro del portamotor:
-TCMotorSelPan.lbl.Search = Buscar:
-TCMotorSelPan.lbl.Selectthrustcurve = Seleccione curva de empuje:
-TCMotorSelPan.lbl.Ejectionchargedelay = Retardo de la carga de eyección:
-TCMotorSelPan.equalsIgnoreCase.None = Ninguno
-TCMotorSelPan.lbl.NumberofsecondsorNone = (Número de segundos o \"Ninguno\")
-TCMotorSelPan.lbl.Totalimpulse = Impulso total:
-TCMotorSelPan.lbl.Avgthrust = Empuje medio:
-TCMotorSelPan.lbl.Maxthrust = Empuje máximo:
-TCMotorSelPan.lbl.Burntime = Tiempo de quemado:
-TCMotorSelPan.lbl.Launchmass = Masa total:
-TCMotorSelPan.lbl.Emptymass = Masa carcasa:
-TCMotorSelPan.lbl.Datapoints = Datos de los puntos:
-TCMotorSelPan.lbl.Digest = Resumen:
-TCMotorSelPan.title.Thrustcurve = Curva de empuje:
-TCMotorSelPan.title.Thrust = Empuje
-TCMotorSelPan.delayBox.None = Ninguno
-
-
-! PlotDialog
-PlotDialog.title.Flightdataplot = Representar los datos de vuelo
-PlotDialog.Chart.Simulatedflight = Vuelo simulado
-PlotDialog.CheckBox.Showdatapoints = Mostrar los datos de los puntos
-PlotDialog.lbl.Chart = Click+bajar el rozamiento+derecha ampliar, arriba+izquierda disminuir
-
-
-! "main" prefix is used for the main application dialog
-
-# FIXME: Rename the description keys 
-
-main.menu.file = Archivo
-main.menu.file.desc = Tareas relacionadas con el manejo de archivos
-main.menu.file.new = Nuevo
-main.menu.file.new.desc = Crear un nuevo diseño de cohete
-main.menu.file.open = Abrir ...
-BasicFrame.item.Openrocketdesign = Abrir un diseño de cohete
-main.menu.file.openExample = Abrir ejemplo ...
-BasicFrame.item.Openexamplerocketdesign = Abrir un ejemplo de diseño de cohete
-main.menu.file.save = Guardar
-BasicFrame.item.SavecurRocketdesign = Guardar el diseño actual
-main.menu.file.saveAs = Guardar como ...
-BasicFrame.item.SavecurRocketdesnewfile = Guardar el diseño actual como un nuevo documento
-main.menu.file.print = Imprimir ...
-BasicFrame.item.Printpart = Imprimir un listado de componentes y un esquema de aleta
-main.menu.file.close = Cerrar
-BasicFrame.item.Closedesign = Cerrar el diseño actual
-main.menu.file.quit = Salir
-BasicFrame.item.Quitprogram = Salir del programa
-
-main.menu.edit = Edición 
-BasicFrame.menu.Rocketedt = Mostrar el cohete
-main.menu.edit.undo = Deshacer
-main.menu.edit.undo.desc = Deshacer la operación anterior
-main.menu.edit.redo = Rehacer
-main.menu.edit.redo.desc = Rehacer la operación anterior
-main.menu.edit.cut = Cortar
-main.menu.edit.copy = Copiar
-main.menu.edit.paste = Pegar
-main.menu.edit.delete = Borrar
-main.menu.edit.resize = Dimensionar...
-main.menu.edit.resize.desc = Dimensionar las partes del diseño del cohete
-main.menu.edit.preferences = Preferencias
-main.menu.edit.preferences.desc = Configurar las preferencias de la aplicación
-
-main.menu.analyze = Analizar
-main.menu.analyze.desc = Análisis del cohete
-main.menu.analyze.componentAnalysis = Análisis de los componentes
-main.menu.analyze.componentAnalysis.desc = Analiza los componentes del cohete por separado
-main.menu.analyze.optimization = Optimización del diseño
-main.menu.analyze.optimization.desc = Optimización global del diseño del cohete
-main.menu.help = Ayuda
-main.menu.help.desc = Información acerca del cohete
-main.menu.help.tours = Visita guiada
-main.menu.help.license = Licencia
-main.menu.help.license.desc = Información de la licencia de OpenRocket
-main.menu.help.bugReport = Informe de errores
-main.menu.help.bugReport.desc = Informar sobre errores encontrados en OpenRocket
-main.menu.help.debugLog = Registro de sucesos
-main.menu.help.debugLog.desc = Visualizar el registro de depuración de OpenRocket
-main.menu.help.about = Acerca de
-main.menu.help.about.desc = Detalles del Copyright de OpenRocket
-
-main.menu.debug = Recuperación
-main.menu.debug.whatisthismenu = ¿Que es este menú?
-main.menu.debug.createtestrocket = Crear una prueba de modelo
-
-! database
-! Translate here all material database
-!
-
-! Material database
-! BULK_MATERIAL
-Databases.materials.Acrylic = Acrílico
-Databases.materials.Balsa = Balsa
-Databases.materials.Birch = Abedul
-Databases.materials.Cardboard = Cartón
-Databases.materials.Carbonfiber = Fibra de Carbono
-Databases.materials.Cork = Corcho
-Databases.materials.DepronXPS = Depron (XPS)
-Databases.materials.Fiberglass = Fibra de vidrio
-Databases.materials.Kraftphenolic = Cartón fenólico
-Databases.materials.Maple = Arce
-Databases.materials.Paperoffice = Papel (oficina)
-Databases.materials.Pine = Pino
-Databases.materials.Plywoodbirch = Contrachapado
-Databases.materials.PolycarbonateLexan = Policarbonato (Lexan)
-Databases.materials.Polystyrene = Poliestireno
-Databases.materials.PVC = PVC
-Databases.materials.Spruce = Pícea (Abeto común)
-Databases.materials.StyrofoamgenericEPS = Porex (generico EPS)
-Databases.materials.StyrofoamBluefoamXPS = Porex \"Foam azul\" (XPS)
-Databases.materials.Quantumtubing = Quantum tubing
-Databases.materials.BlueTube = Tubo azul (PML)
-!SURFACE_MATERIAL
-Databases.materials.Ripstopnylon = Ripstop nylon
-Databases.materials.Mylar = Mylar
-Databases.materials.Polyethylenethin = Polietileno (delgado)
-Databases.materials.Polyethyleneheavy = Polietileno (grueso)
-Databases.materials.Silk = Seda
-Databases.materials.Paperoffice = Papel (oficina)
-Databases.materials.Cellophane = Celofán
-Databases.materials.Crepepaper = Crespón de papel
-! LINE_MATERIAL
-Databases.materials.Threadheavy-duty = Trenzado (Alta resistencia)
-Databases.materials.Elasticcordround2mm = Cordón elástico (aprox. 2mm, 1/16 in)
-Databases.materials.Elasticcordflat6mm = Cordón elástico plano (6mm, 1/4 in)
-Databases.materials.Elasticcordflat12mm = Cordón elástico plano (12mm, 1/2 in)
-Databases.materials.Elasticcordflat19mm = Cordón elástico plano (19mm, 3/4 in)
-Databases.materials.Elasticcordflat25mm = Cordón elástico plano (25mm, 1 in)
-Databases.materials.Braidednylon2mm = Nylon trenzado (2 mm, 1/16 in)
-Databases.materials.Braidednylon3mm = Nylon trenzado (3 mm, 1/8 in)
-Databases.materials.Tubularnylon11mm = Nylon tubular (11 mm, 7/16 in)
-Databases.materials.Tubularnylon14mm = Nylon tubular (14 mm, 9/16 in)
-Databases.materials.Tubularnylon25mm = Nylon tubular (25 mm, 1 in)
-
-! ExternalComponent
-ExternalComponent.Rough = Rugoso
-ExternalComponent.Unfinished = Inacabado
-ExternalComponent.Regularpaint = Pintura normal
-ExternalComponent.Smoothpaint = Pintura fina
-ExternalComponent.Polished = Pulido
-
-! LineStyle
-LineStyle.Solid = Sólido
-LineStyle.Dashed = Discontinuo
-LineStyle.Dotted = Punteado
-LineStyle.Dash-dotted = Discontinuo con puntos
-LineStyle.Defaultstyle = Estilo por defecto
-
-! Shape
-Shape.Conical = Cónico
-Shape.Conical.desc1 = Una ojiva cónica de perfil triangular
-Shape.Conical.desc2 = Transición cónica de lados rectos
-Shape.Ogive = Ojival
-Shape.Ogive.desc1 = Ojiva con perfil de arco de circunferencia. Un valor de forma igual a 1 produce una <b>Ojiva tangente</b>, mientras que un valor inferior a 1 produce una <b>Ojiva secante</b> con un perfil más afilado.
-Shape.Ogive.desc2 = Transición con perfil de arco de circunferencia. Un valor de forma igual a 1 produce una <b>Transición tangente</b>, mientras que un valor inferior a 1 produce una <b>Transición secante</b> con un perfil más afilado.
-Shape.Ellipsoid = Elíptica
-Shape.Ellipsoid.desc1 = Ojiva con perfil de media elipse. Por defecto, una elipse de <i>longitud</i> igual al triple de su <i>diámetro</i>.
-Shape.Ellipsoid.desc2 = Transición con perfil de media elipse. Por defecto, una elipse de <i>longitud</i> igual al triple de su <i>diámetro</i>.
-Shape.Powerseries = Serie potencial 
-Shape.Powerseries.desc1 = Ojiva cuyo perfil es una curva obtenida a partir de una función potencial f(<i>x</i>)<sup><i>k</i></sup>. Un valor de forma k=0.5 produce una ojiva con perfil de parábola, para k=0.75 se produce una ojiva con <b>perfil potencial</b>, y para k=1 se produce una ojiva con perfil recto u <b>Ojiva cónica</b>.
-Shape.Powerseries.desc2 = Transición cuyo perfil es una curva obtenida a partir de una función potencial de <i>Radio</i>&nbsp; =;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>L</i>)<sup><i>k</i></sup> donde <i>k</i> es el parámetro de forma.  Para <i>k</i>=0.5 la transición es <b>\u00BD-potencial</b> o <b>parabólica</b>, para <i>k</i>=0.75 a <b>\u00BE-potencia</b>, y para <i>k</i>=1 <b>cónica</b>.
-Shape.Parabolicseries = Serie parabólica
-Shape.Parabolicseries.desc1 = Ojiva con perfil de arco de parábola. Un valor de forma igual a 1 produce una <b>Ojiva tangente</b>, un valor igual a 0.75 produce una <b>parábola de 3/4</b>, un valor igual a 0.5 produce una <b>parábola de 1/2</b>, y un valor igual a 0 produce un perfil recto u <b>Ojiva cónica</b>.
-Shape.Parabolicseries.desc2 = Una transición de serie parabólica tiene un perfil de parábola. El valor de forma defien el tipo de parábola a utilizar. Un valor de forma de 1.0 produce una parábola completa que es tangente al cuerpo tubular en el extremo trasero, un valor de 0.75 produce una <b>parábola de 3/4</b>, un valor de 0.5 produce una <b>parábola de 1/2</b>, y un valor de 0 produce una transición cónica.
-Shape.Haackseries = Haack series
-Shape.Haackseries.desc1 = Ojiva con perfil de mínimo arrastre aerodinámico recomendado para vuelos supersónicos. Un valor de forma igual a 0 produce una <b>Ojiva LD Haack</b> u <b>Ojiva Von Karman</b> que minimiza el arrastre aerodinámico para una determinada longitud y diámetro de la base, mientras que un valor igual a 0.333 produce una <b>Ojiva LV-Haack</b> que minimiza el arrastre aerodinámico para una determinada longitud y volumen de la ojiva.
-Shape.Haackseries.desc2 = Las transiciones Haack series están diseñadas para minimizar el arrastre aerodinámico. Estas transiciones poseen sus equivalentes, pero no necesariamente producen un arrastre óptimo.  Un valor de forma 0 produce una transición <b>LD-Haack</b> o <b>Von Karman</b>, mientras que un valor de 0.333 produce una forma <b>LV-Haack</b>.            
-
-
-! RocketComponent
-RocketComponent.Position.TOP = Parte superior del componente
-RocketComponent.Position.MIDDLE = Parte media del componente
-RocketComponent.Position.BOTTOM = Extremo inferior del componente
-RocketComponent.Position.AFTER = Después del componente
-RocketComponent.Position.ABSOLUTE = Extremo de la ojiva
-
-! LaunchLug
-LaunchLug.Launchlug = Soporte para Guía
-! NoseCone
-NoseCone.NoseCone = Ojiva
-! Transition
-Transition.Transition = Transición
-!Stage
-Stage.Stage = Etapa
-! BodyTube
-BodyTube.BodyTube = Cuerpo tubular
-! TubeCoupler
-TubeCoupler.TubeCoupler = Acoplador
-!InnerTube
-InnerTube.InnerTube = Tubo interior
-! TrapezoidFinSet
-TrapezoidFinSet.TrapezoidFinSet = Aleta trapezoidal
-! FreeformFinSet
-FreeformFinSet.FreeformFinSet = Aleta de forma libre
-!MassComponent
-MassComponent.MassComponent = Masa
-! Parachute
-Parachute.Parachute = Paracaídas
-! ShockCord
-ShockCord.ShockCord = Tirante de suspensión
-! Bulkhead
-Bulkhead.Bulkhead = Disco de enganche
-
-!Rocket
-Rocket.motorCount.Nomotor = [Sin motores]
-Rocket.compname.Rocket = Cohete
-
-!MotorMount
-MotorMount.IgnitionEvent.AUTOMATIC = Automático (Lanzamiento o carga de eyección)
-MotorMount.IgnitionEvent.LAUNCH = Lanzamiento
-MotorMount.IgnitionEvent.EJECTION_CHARGE = Primera carga de eyección de la etapa previa
-MotorMount.IgnitionEvent.BURNOUT = Primer encendido de la etapa previa
-MotorMount.IgnitionEvent.NEVER = Nunca
-
-!ComponentIcons 
-ComponentIcons.Nosecone = Ojiva
-ComponentIcons.Bodytube = Cuerpo tubular
-ComponentIcons.Transition = Transición
-ComponentIcons.Trapezoidalfinset = Aleta trapezoidal
-ComponentIcons.Ellipticalfinset = Aleta elíptica
-ComponentIcons.Freeformfinset = Aleta de forma libre
-ComponentIcons.Launchlug = Tubo para Guía
-ComponentIcons.Innertube = Tubo interior
-ComponentIcons.Tubecoupler = Tubo de acoplamiento
-ComponentIcons.Centeringring = Anillo de centrado
-ComponentIcons.Bulkhead = Disco de enganche
-ComponentIcons.Engineblock = Retén de motor
-ComponentIcons.Parachute = Paracaídas
-ComponentIcons.Streamer = Banderola
-ComponentIcons.Shockcord = Tirante de suspensión
-ComponentIcons.Masscomponent = Componente masa
-ComponentIcons.disabled = (Desconectado)
-
-! StageAction
-StageAction.Stage = Etapa
-
-! RecoveryDevice
-RecoveryDevice.DeployEvent.LAUNCH = Lanzamiento (NN segundos)
-RecoveryDevice.DeployEvent.EJECTION = Primera carga de eyección de esta etapa
-RecoveryDevice.DeployEvent.APOGEE = Apogeo
-RecoveryDevice.DeployEvent.ALTITUDE = Altura específica durante el descenso
-RecoveryDevice.DeployEvent.NEVER = Nunca
-
-! FlightEvent
-FlightEvent.Type.LAUNCH = Lanzamiento
-FlightEvent.Type.IGNITION = Encendido del motor
-FlightEvent.Type.LIFTOFF = Despegue
-FlightEvent.Type.LAUNCHROD = Abandono de la Guía de lanzamiento
-FlightEvent.Type.BURNOUT = Apagado del motor
-FlightEvent.Type.EJECTION_CHARGE = Carga de eyección
-FlightEvent.Type.STAGE_SEPARATION = Separación de etapa
-FlightEvent.Type.APOGEE = Apogeo
-FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT = Despliegue del sistema de recuperación
-FlightEvent.Type.GROUND_HIT = Contacto con el suelo
-FlightEvent.Type.SIMULATION_END = Fin de la simulación
-FlightEvent.Type.ALTITUDE = Altitud
-
-! ThrustCurveMotorColumns
-TCurveMotorCol.MANUFACTURER = Fabricante
-TCurveMotorCol.DESIGNATION = Designación
-TCurveMotorCol.TYPE = Tipo
-TCurveMotorCol.DIAMETER = Diámetro
-TCurveMotorCol.LENGTH = Longitud
-
-! RocketInfo
-RocketInfo.lengthLine.Length = Longitud: 
-RocketInfo.lengthLine.maxdiameter = , Diámetro máximo: 
-RocketInfo.massText1 = Masa con motores: 
-RocketInfo.massText2 = Masa sin motores: 
-RocketInfo.at = a M=
-RocketInfo.cgText = CG:
-RocketInfo.cpText = CP:
-RocketInfo.stabText = Estabilidad: 
-RocketInfo.Warning = Peligro, cohete inestable.
-RocketInfo.Calculating = Calculando...
-RocketInfo.Apogee = Apogeo:
-RocketInfo.Maxvelocity = Velocidad Máx.: 
-RocketInfo.Maxacceleration = Aceleración Máx.: 
-RocketInfo.apogeeValue = N/A
-RocketInfo.Mach = , (Número Mach: 
-RocketInfo.velocityValue = N/A
-RocketInfo.accelerationValue = N/A
-
-! FinSet
-FinSet.CrossSection.SQUARE = Cuadrado
-FinSet.CrossSection.ROUNDED = Redondeado
-FinSet.CrossSection.AIRFOIL = Aerodinámico
-FinSet.TabRelativePosition.FRONT = Borde principal del extremo de anclaje
-FinSet.TabRelativePosition.CENTER = Borde principal del anclaje
-FinSet.TabRelativePosition.END = Borde principal de tracción
-
-! FlightDataType
-FlightDataType.TYPE_TIME = Tiempo
-FlightDataType.TYPE_ALTITUDE = Altitud
-FlightDataType.TYPE_VELOCITY_Z = Velocidad vertical
-FlightDataType.TYPE_ACCELERATION_Z = Aceleración vertical
-FlightDataType.TYPE_VELOCITY_TOTAL = Velocidad total
-FlightDataType.TYPE_ACCELERATION_TOTAL = Aceleración total
-FlightDataType.TYPE_POSITION_X = Posición contra el viento
-FlightDataType.TYPE_POSITION_Y = Posición a favor del viento
-FlightDataType.TYPE_POSITION_XY = Distancia lateral
-FlightDataType.TYPE_POSITION_DIRECTION = Dirección lateral
-FlightDataType.TYPE_VELOCITY_XY = Velocidad lateral
-FlightDataType.TYPE_ACCELERATION_XY = Aceleración lateral
-FlightDataType.TYPE_AOA = Ángulo de ataque
-FlightDataType.TYPE_ROLL_RATE = Relación de rotación
-FlightDataType.TYPE_PITCH_RATE = Relación de pico
-FlightDataType.TYPE_YAW_RATE = Relación de desvío
-FlightDataType.TYPE_MASS = Masa
-FlightDataType.TYPE_LONGITUDINAL_INERTIA = Momento de inercia longitudinal
-FlightDataType.TYPE_ROTATIONAL_INERTIA = Momento de inercia rotacional
-FlightDataType.TYPE_CP_LOCATION = Situación del CP
-FlightDataType.TYPE_CG_LOCATION = Situación del CG
-FlightDataType.TYPE_STABILITY = Calibración del margen de estabilidad
-FlightDataType.TYPE_MACH_NUMBER = Número Mach
-FlightDataType.TYPE_REYNOLDS_NUMBER = Número de Reynolds
-FlightDataType.TYPE_THRUST_FORCE = Empuje
-FlightDataType.TYPE_DRAG_FORCE = Fuerza de rozamiento
-FlightDataType.TYPE_DRAG_COEFF = Coeficiente de rozamiento
-FlightDataType.TYPE_AXIAL_DRAG_COEFF = Coeficiente de rozamiento axial
-FlightDataType.TYPE_FRICTION_DRAG_COEFF = Coeficiente de rozamiento por fricción
-FlightDataType.TYPE_PRESSURE_DRAG_COEFF = Presión del coeficiente de rozamiento
-FlightDataType.TYPE_BASE_DRAG_COEFF = Coeficiente de rozamiento base
-FlightDataType.TYPE_NORMAL_FORCE_COEFF = Coeficiente de rozamiento normal
-FlightDataType.TYPE_PITCH_MOMENT_COEFF = Pico del coeficiente de rozamiento
-FlightDataType.TYPE_YAW_MOMENT_COEFF = Coeficiente de rozamiento de desviación
-FlightDataType.TYPE_SIDE_FORCE_COEFF = Coeficiente de fuerza lateral
-FlightDataType.TYPE_ROLL_MOMENT_COEFF = Coeficiente del momento de rotación
-FlightDataType.TYPE_ROLL_FORCING_COEFF = Fuerza del coeficiente de rotación
-FlightDataType.TYPE_ROLL_DAMPING_COEFF = Disminución del coeficiente de rotación
-FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF = Disminución del coeficiente de pico
-FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF = Disminución del coeficiente de desviación
-FlightDataType.TYPE_REFERENCE_LENGTH = Longitud de referencia 
-FlightDataType.TYPE_REFERENCE_AREA = Área de referencia
-FlightDataType.TYPE_ORIENTATION_THETA = Orientación vertical (zenit)
-FlightDataType.TYPE_ORIENTATION_PHI = Orientación lateral (azimut)
-FlightDataType.TYPE_WIND_VELOCITY = Velocidad del viento
-FlightDataType.TYPE_AIR_TEMPERATURE = Temperatura del aire
-FlightDataType.TYPE_AIR_PRESSURE = Presión del aire
-FlightDataType.TYPE_SPEED_OF_SOUND = Velocidad del sonido
-FlightDataType.TYPE_TIME_STEP = Simulación del tiempo de etapa
-FlightDataType.TYPE_COMPUTATION_TIME = Cálculo del tiempo
-FlightDataType.TYPE_LATITUDE = Latitud
-FlightDataType.TYPE_LONGITUDE = Longitud
-FlightDataType.TYPE_CORIOLIS_ACCELERATION = Aceleración Coriolis
-
-! PlotConfiguration
-PlotConfiguration.Verticalmotion = Movimiento vertical vs. Tiempo
-PlotConfiguration.Totalmotion = Movimiento total vs. Tiempo
-PlotConfiguration.Flightside = Perfil lateral de vuelo
-PlotConfiguration.Stability = Estabilidad vs. Tiempo
-PlotConfiguration.Dragcoef = Coeficiente de rozamiento vs. Número Mach
-PlotConfiguration.Rollcharacteristics = Características de rotación
-PlotConfiguration.Angleofattack = Ángulo de orientación y ataque vs. Tiempo
-PlotConfiguration.Simulationtime = Simulación del tiempo de etapa y cálculo del tiempo
-
-! Warning
-Warning.LargeAOA.str1 = Evaluación de la amplitud del ángulo de ataque.
-Warning.LargeAOA.str2 = La amplitud del ángulo de ataque es excesiva (
-Warning.DISCONTINUITY = Discontinuidad en el diámetro del fuselaje.
-Warning.THICK_FIN = Las aletas gruesas no están correctamente modeladas.
-Warning.JAGGED_EDGED_FIN = El perfil afilado de las aletas puede ser inexacto.
-Warning.LISTENERS_AFFECTED = Las Extensiones se ejecutaron con la simulación del vuelo
-Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING = Sistema de recuperación abierto en fase de impulso, mientras el motor aún empujaba
-Warning.FILE_INVALID_PARAMETER = Parámetro encontrado no válido. Ignorado.
-
-
-! Scale dialog
-ScaleDialog.lbl.scaleRocket = El Cohete entero
-ScaleDialog.lbl.scaleSubselection = Todos los componentes seleccionados
-ScaleDialog.lbl.scaleSelection = Sólo el componente seleccionado
-ScaleDialog.title = Dimensión del diseño
-ScaleDialog.lbl.scale = Dimensión:
-ScaleDialog.lbl.scale.ttip = Indique si desea dimensionar el diseño completo o sólo los componentes seleccionados
-ScaleDialog.lbl.scaling = Dimensión a aplicar:
-ScaleDialog.lbl.scaling.ttip = Tamaño resultante, valores por encima del 100% aumentan el tamaño, y valores por debajo de 100% reduce el diseño.
-! The scaleFrom/scaleTo pair creates a phrase "Scale from [...] to [...]"
-ScaleDialog.lbl.scaleFrom = Dimensionar desde
-ScaleDialog.lbl.scaleTo = hasta
-ScaleDialog.lbl.scaleFromTo.ttip = Definir la dimensión en base a una longitud conocida u original.
-ScaleDialog.checkbox.scaleMass = Actualizar valores de Masa especificada
-ScaleDialog.checkbox.scaleMass.ttip = Dimensionar la Masa del componente y recalcular los valores de Masa por el cubo del factor de la escala
-ScaleDialog.button.scale = Dimensionar
-ScaleDialog.undo.scaleRocket = Dimensionar el cohete
-ScaleDialog.undo.scaleComponent = Dimensionar el componente
-ScaleDialog.undo.scaleComponents = Dimensionar los componentes
-
-!icons
-Icons.Undo = Deshacer
-Icons.Redo = Rehacer
-
-OpenRocketPrintable.Partsdetail = Detalle de las partes
-OpenRocketPrintable.Fintemplates = Plantilla de las aletas
-OpenRocketPrintable.DesignReport = Informe del Diseño
-
-OpenRocketDocument.Redo = Rehacer
-OpenRocketDocument.Undo = Deshacer
-
-!EllipticalFinSet
-EllipticalFinSet.Ellipticalfinset = Grupo de aletas elípticas
-
-! Optimization
-
-! Modifiers
-
-optimization.modifier.nosecone.length = Longitud de la ojiva
-optimization.modifier.nosecone.length.desc = Optimizar la longitud de la ojiva.
-optimization.modifier.nosecone.diameter = Diámetro de la ojiva optimization.modifier.nosecone.diameter.desc = Optimizar el diámetro de la base de la ojiva.
-optimization.modifier.nosecone.thickness = Grosor de la ojiva
-optimization.modifier.nosecone.thickness.desc = Optimizar el grosor de la pared de la ojiva.
-optimization.modifier.nosecone.shapeparameter = Parámetro de forma
-optimization.modifier.nosecone.shapeparameter.desc = Optimiza el parámetro de forma de la ojiva.
-               
-optimization.modifier.transition.length = Longitud
-optimization.modifier.transition.length.desc = Optimiza la longitud de la transición.
-optimization.modifier.transition.forediameter = Diámetro delantero
-optimization.modifier.transition.forediameter.desc = Optimiza el diámetro delantero de la transición.
-optimization.modifier.transition.aftdiameter = Diámetro trasero
-optimization.modifier.transition.aftdiameter.desc = Optimiza el diámetro trasero de la transición.
-optimization.modifier.transition.thickness = Grosor
-optimization.modifier.transition.thickness.desc = Optimiza el grosor de la pared de la transición.
-optimization.modifier.transition.shapeparameter = Parámetro de forma
-optimization.modifier.transition.shapeparameter.desc = Optimizar el parámetro de forma de la transición.
-
-optimization.modifier.bodytube.length = Longitud
-optimization.modifier.bodytube.length.desc = Optimizar la longitud del cuerpo.
-optimization.modifier.bodytube.outerDiameter = Diámetro exterior
-optimization.modifier.bodytube.outerDiameter.desc = Optimizar el diámetro exterior del cuerpo manteniendo el grosor de la pared.
-optimization.modifier.bodytube.thickness = Grosor
-optimization.modifier.bodytube.thickness.desc = Optimizar el grosor de la pared del cuerpo.
-
-optimization.modifier.trapezoidfinset.rootChord = Longitud línea base
-optimization.modifier.trapezoidfinset.rootChord.desc = Optiminizar la longitud de la línea base de las aletas (longitud de la aleta sobre la superficie del cuerpo).
-optimization.modifier.trapezoidfinset.tipChord = Longitud borde superior
-optimization.modifier.trapezoidfinset.tipChord.desc = Optimizar la longitud del borde superior de las aletas (longitd del borde exterior de la aleta).
-optimization.modifier.trapezoidfinset.sweep = Desplazamiento borde superior
-optimization.modifier.trapezoidfinset.sweep.desc = Optimiza el desplazamiento del borde superior de las aletas (desplazamiento del borde superior de la aleta respecto del extremo delantero de la línea base).
-optimization.modifier.trapezoidfinset.height = Altura
-optimization.modifier.trapezoidfinset.height.desc = Optimizar la altura de las aletas (semi-spam).
-
-optimization.modifier.ellipticalfinset.length = Longitud línea base
-optimization.modifier.ellipticalfinset.length.desc = Optiminizar la longitud de la línea base de las aletas
-optimization.modifier.ellipticalfinset.height = Altura
-optimization.modifier.ellipticalfinset.height.desc = Optimizar la altura de las aletas (semi-spam).
-
-optimization.modifier.finset.cant = Angulo de ataque
-optimization.modifier.finset.cant.desc = Optimiza el ángulo de ataque de las aletas.
-optimization.modifier.finset.position = Posición
-optimization.modifier.finset.position.desc = Optimiza la posición de las aletas a lo largo del cuerpo del cohete.
-
-optimization.modifier.launchlug.length = Longitud
-optimization.modifier.launchlug.length.desc = Optimiza la longitud del tubo para la Guía.
-optimization.modifier.launchlug.outerDiameter = Diámetro exterior
-optimization.modifier.launchlug.outerDiameter.desc = Optimiza el diámetro exterior del tubo para la Guía.
-optimization.modifier.launchlug.thickness = Grosor
-optimization.modifier.launchlug.thickness.desc = Optimiza el grosor del tubo para la Guía manteniendo el diámetro exterior.
-optimization.modifier.launchlug.position = Posición
-optimization.modifier.launchlug.position.desc = Optimiza la posición del soporte para la guía a lo largo del cuerpo del cohete.
-
-
-optimization.modifier.internalcomponent.position = Posición
-optimization.modifier.internalcomponent.position.desc = Optimiza la posición del componente interno respecto del componente que lo contiene.
-
-optimization.modifier.masscomponent.mass = Masa
-optimization.modifier.masscomponent.mass.desc = Optimiza la masa del componente Masa.
-
-optimization.modifier.parachute.diameter = Diámetro
-optimization.modifier.parachute.diameter.desc = Optimiza el diámetro del pabellón del paracaídas.
-optimization.modifier.parachute.coefficient = Coeficiente de rozamiento
-optimization.modifier.parachute.coefficient.desc = Optimiza el coeficiente de rozamiento del paracaídas. Un paracaídas típico posee un coeficiente de 0.8.
-
-optimization.modifier.streamer.length = Longitud
-optimization.modifier.streamer.length.desc = Optimiza la longitud de la banderola.
-optimization.modifier.streamer.width = Anchura
-optimization.modifier.streamer.width.desc = Optimiza la anchura de la banderola.
-optimization.modifier.streamer.aspectRatio = Relación de aspecto
-optimization.modifier.streamer.aspectRatio.desc = Optimiza la relación de aspecto de la banderola (longitud/anchura). Usted NO debe seleccionar una longitud o anchura de la banderola al mismo tiempo que una relación de aspecto.
-optimization.modifier.streamer.coefficient = Coeficiente de rozamiento
-optimization.modifier.streamer.coefficient.desc = Optimiza el coeficiente de rozamiento de la banderola.
-
-optimization.modifier.recoverydevice.deployDelay = Retardo de eyección
-optimization.modifier.recoverydevice.deployDelay.desc = Optimiza el tiempo de retardo de eyección del sistema de recuperación.
-optimization.modifier.recoverydevice.deployAltitude = Altitud de eyección
-optimization.modifier.recoverydevice.deployAltitude.desc = Optimiza la altitud de la eyección del sistema de recuperación.
-
-optimization.modifier.rocketcomponent.overrideMass = Masa especificada
-optimization.modifier.rocketcomponent.overrideMass.desc = Optimiza la Masa especificada del componente.
-optimization.modifier.rocketcomponent.overrideCG = CG especificado
-optimization.modifier.rocketcomponent.overrideCG.desc = Optimiza la localización del Centro de Gravedad especificado en el componente.
-
-optimization.modifier.motormount.overhang = Sobresalida del motor
-optimization.modifier.motormount.overhang.desc = Optimiza la sobresalida del motor hacia el exterior.
-optimization.modifier.motormount.delay = Retardo de ignición
-optimization.modifier.motormount.delay.desc = Optimiza el retardo de la ingnición del motor.
-
-
-
-
-! General rocket design optimization dialog
-
-GeneralOptimizationDialog.title = Optimización del cohete
-GeneralOptimizationDialog.goal.maximize = Maximizar el valor
-GeneralOptimizationDialog.goal.minimize = Minimizar el valor
-GeneralOptimizationDialog.goal.seek = Buscar el valor de
-GeneralOptimizationDialog.btn.start = Iniciar optimización
-GeneralOptimizationDialog.btn.stop = Detener optimización
-GeneralOptimizationDialog.lbl.paramsToOptimize = Parámetros de optimización:
-GeneralOptimizationDialog.btn.add = Agregar
-GeneralOptimizationDialog.btn.add.ttip = Agregar el parámetro de optimizacaión
-GeneralOptimizationDialog.btn.remove = Eliminar
-GeneralOptimizationDialog.btn.remove.ttip = Eliminar el parámetro seleccionado de la optimización. 
-GeneralOptimizationDialog.btn.removeAll = Eliminar todo
-GeneralOptimizationDialog.btn.removeAll.ttip = Eliminar todos los parámetros de optimización.
-GeneralOptimizationDialog.lbl.availableParams = Parámetros disponibles:
-GeneralOptimizationDialog.lbl.optimizationOpts = Opciones de optimización
-GeneralOptimizationDialog.lbl.optimizeSim = Optimizar simulación:
-GeneralOptimizationDialog.lbl.optimizeSim.ttip = Seleccionar la simulación a optimizar.
-GeneralOptimizationDialog.lbl.optimizeValue = Valor optimizado:
-GeneralOptimizationDialog.lbl.optimizeValue.ttip = Seleccionar el valor a optimizar.
-GeneralOptimizationDialog.lbl.optimizeGoal = Objetivo de optimización:
-GeneralOptimizationDialog.lbl.optimizeGoal.ttip = Seleccionar el objetivo de la optimización.
-GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip = Buscar valor personalizado
-GeneralOptimizationDialog.lbl.requireStability = Estabilidad requerida
-GeneralOptimizationDialog.lbl.requireMinStability = Mínima estabilidad:
-GeneralOptimizationDialog.lbl.requireMinStability.ttip = Requerir un margen mínimo de estabilidad para el diseño.
-GeneralOptimizationDialog.lbl.requireMaxStability = Máxima estabilidad:
-GeneralOptimizationDialog.lbl.requireMaxStability.ttip = Requerir un margen máximo de estabilidad para el diseño.
-GeneralOptimizationDialog.status.bestValue = El mejor valor:
-GeneralOptimizationDialog.status.bestValue.ttip = El mejor valor de optimización encontrado.
-GeneralOptimizationDialog.status.stepCount = Número de pasos:
-GeneralOptimizationDialog.status.stepCount.ttip = Número de pasos que deben realizarse para la optimización.
-GeneralOptimizationDialog.status.evalCount = Evaluaciones:
-GeneralOptimizationDialog.status.evalCount.ttip = Número total de evaluaciones (simulaciones) que deben realizarse.
-GeneralOptimizationDialog.status.stepSize = Tamaño del paso:
-GeneralOptimizationDialog.status.stepSize.ttip = Tamaño actual del paso de optimización (respecto al rango de parámetros de optimización).
-GeneralOptimizationDialog.btn.plotPath = Gráfica del proceso
-GeneralOptimizationDialog.btn.plotPath.ttip = Gráfica del proceso de optimización (sólo para 1 o 2 dimensiones).
-GeneralOptimizationDialog.btn.save = Guardar resultados
-GeneralOptimizationDialog.btn.save.ttip = Guardar los resultados de las evaluaciones (simulaciones) en un archivo CSV.
-GeneralOptimizationDialog.btn.apply = Aplicar optimización
-GeneralOptimizationDialog.btn.apply.ttip = Aplicar los resultados de la optimización al diseño del cohete.
-GeneralOptimizationDialog.btn.reset = Reiniciar
-GeneralOptimizationDialog.btn.reset.ttip = Reiniciar el diseño actual del cohete con el diseño optimizado.
-GeneralOptimizationDialog.btn.close = Cerrar
-GeneralOptimizationDialog.btn.close.ttip = Cerrar el cuadro de diálogo sin modificar el diseño actual del cohete.
-GeneralOptimizationDialog.error.selectParams.text = Primero seleccione algunos parámetros a optimizar de entre todos los parámetros disponibles.
-GeneralOptimizationDialog.error.selectParams.title = Seleccionar los parámetros de optimización
-GeneralOptimizationDialog.error.optimizationFailure.text = Falló la ejecución de la optimización:
-GeneralOptimizationDialog.error.optimizationFailure.title = Fallo de la optimización
-GeneralOptimizationDialog.undoText = Aplicar la optimización
-GeneralOptimizationDialog.basicSimulationName = Simulación básica
-GeneralOptimizationDialog.noSimulationName = Sin simulación
-GeneralOptimizationDialog.table.col.parameter = Parámetro
-GeneralOptimizationDialog.table.col.current = Actual
-GeneralOptimizationDialog.table.col.min = Mínimo
-GeneralOptimizationDialog.table.col.max = Máximo
-GeneralOptimizationDialog.export.header = Incluir línea de cabecera
-GeneralOptimizationDialog.export.header.ttip = Incluir una línea de cabecera en la que se indican las descripciones.
-GeneralOptimizationDialog.export.stability = Estabilidad
-
-
-! Dialog for plotting optimization results
-OptimizationPlotDialog.title = Resultados de la optimización
-OptimizationPlotDialog.lbl.zoomInstructions = Click y arrastrar abajo+derecha para acercar Zoom, arriba+izquierda para alejar Zoom
-OptimizationPlotDialog.plot1d.title = Resultado de la optimización
-OptimizationPlotDialog.plot1d.series = Resultado de la optimización
-OptimizationPlotDialog.plot2d.title = Trazabilidad de la optimización
-OptimizationPlotDialog.plot2d.path = Trazabilidad de la optimización
-OptimizationPlotDialog.plot2d.evals = Evaluaciones
-OptimizationPlotDialog.plot.ttip.stability = Estabilidad:
-OptimizationPlotDialog.plot.label.optimum = Óptimo
-
-! Optimization parameters
-MaximumAltitudeParameter.name = Altitud en apogeo
-MaximumVelocityParameter.name = Velocidad máxima
-MaximumAccelerationParameter.name = Aceleración máxima
-StabilityParameter.name = Estabilidad
-GroundHitVelocityParameter.name = Velocidad de aterrizaje
-LandingDistanceParameter.name = Distancia de aterrizaje
-TotalFlightTimeParameter.name = Tiempo total de vuelo
-DeploymentVelocityParameter.name = Velocidad durante la eyección
-
-
-! Compass directions drawn on a compass rose.
-CompassRose.lbl.north = N
-CompassRose.lbl.east  = E
-CompassRose.lbl.south = S
-CompassRose.lbl.west  = O
-
-! Compass directions with subdirections.  These might not be localized even if the directions on the compass rose are.
-CompassSelectionButton.lbl.N = N
-CompassSelectionButton.lbl.NE = NE
-CompassSelectionButton.lbl.E = E
-CompassSelectionButton.lbl.SE = SE
-CompassSelectionButton.lbl.S = S
-CompassSelectionButton.lbl.SW = SO
-CompassSelectionButton.lbl.W = O
-CompassSelectionButton.lbl.NW = NO
-
-
-SlideShowDialog.btn.next = Siguiente
-SlideShowDialog.btn.prev = Anterior
-
-SlideShowLinkListener.error.title = Guided tour not found
-SlideShowLinkListener.error.msg = Sorry, the selected tour has not yet been written.
-
-GuidedTourSelectionDialog.title = Visita guiada
-GuidedTourSelectionDialog.lbl.selectTour = Seleccione un tema:
-GuidedTourSelectionDialog.lbl.description = Descripción del tema:
-GuidedTourSelectionDialog.lbl.length = Número de diapositivas:
-GuidedTourSelectionDialog.btn.start = ¡Empezar el Tour!
-
-
-! Custom Fin BMP Importer
-CustomFinImport.button.label = Import from BMP
-CustomFinImport.filter = Bitmap Files (*.bmp)
-CustomFinImport.badFinImage = Invalid fin image. Must be a black and white image (black for the fin), not touching any side, except the bottom of the image, which is the base of the fin.
-CustomFinImport.errorLoadingFile = Error loading file: 
-CustomFinImport.errorParsingFile = Error parsing fin image: 
-CustomFinImport.undo = Import freeform fin set
-CustomFinImport.error.title = Error loading fin profile
-CustomFinImport.error.badimage = Could not deduce fin shape from image.
+#\r
+# Spanish base translation file\r
+# translations provided by Tripoli Spain\r
+#\r
+# Should you need to add new logical keys here is the proposed method\r
+#\r
+# className.ComponantType.componantName\r
+#\r
+#\r
+# Text tokens within braces should not be translated, e.g.\r
+#    "The file '{filename}' exists."\r
+# They are pieces that are inserted dynamically.\r
+# \r
+\r
+\r
+! Set to the name of the current translation file (used for debugging purposes)\r
+debug.currentFile = messages_es.properties\r
+\r
+! RocketActions\r
+RocketActions.checkbox.Donotaskmeagain = No volver a preguntarme\r
+RocketActions.lbl.Youcanchangedefop = Puede modificar la operación por defecto con sus preferencias\r
+RocketActions.showConfirmDialog.lbl1 = ¿Borrar las simulaciones seleccionadas?\r
+RocketActions.showConfirmDialog.lbl2 = <html><i>Esta operación no puede deshacerse.</i>\r
+RocketActions.showConfirmDialog.title = Borrar simulaciones\r
+RocketActions.DelCompAct.Delete = Borrar\r
+RocketActions.DelCompAct.ttip.Delete = Borrar el componente seleccionado\r
+RocketActions.DelSimuAct.Delete = Borrar\r
+RocketActions.DelSimuAct.ttip.Delete = Borrar la simulación seleccionada\r
+RocketActions.DelAct.Delete = Borrar\r
+RocketActions.DelAct.ttip.Delete = Eliminar elemento seleccionado\r
+RocketActions.CutAction.Cut = Cortar\r
+RocketActions.CutAction.ttip.Cut = Quitar y copiar al portapapeles\r
+RocketActions.CopyAct.Copy = Copiar\r
+RocketActions.CopyAct.ttip.Copy = Copiar al portapapeles\r
+RocketActions.PasteAct.Paste = Pegar\r
+RocketActions.PasteAct.ttip.Paste = Pegar al portapapeles\r
+RocketActions.EditAct.Edit = Editar componente\r
+RocketActions.EditAct.ttip.Edit = Editar valores del componente seleccionado\r
+RocketActions.NewStageAct.Newstage = Nueva etapa\r
+RocketActions.NewStageAct.ttip.Newstage = Añadir una nueva etapa al diseño del cohete\r
+RocketActions.ActBoosterstage = Etapa booster\r
+RocketActions.MoveUpAct.Moveup = Mover hacia arriba\r
+RocketActions.MoveUpAct.ttip.Moveup = Mover este componente hacia arriba\r
+RocketActions.MoveDownAct.Movedown = Mover hacia abajo\r
+RocketActions.MoveDownAct.ttip.Movedown = Mover este componente hacia abajo\r
+\r
+! RocketPanel\r
+RocketPanel.FigTypeAct.Sideview = Vista lateral\r
+RocketPanel.FigTypeAct.ttip.Sideview = Vista desde un lateral\r
+RocketPanel.FigTypeAct.Backview = Vista trasera\r
+RocketPanel.FigTypeAct.ttip.Backview = Vista desde atrás\r
+RocketPanel.FigViewAct.2D = Vista 2D\r
+RocketPanel.FigViewAct.ttip.2D = Vista en 2D\r
+RocketPanel.FigViewAct.3D = Vista 3D\r
+RocketPanel.FigViewAct.ttip.3D = Vista en 3D\r
+RocketPanel.lbl.Motorcfg = Configuración del motor\r
+RocketPanel.lbl.infoMessage = <html>Click para seleccionar&nbsp;&nbsp; Mayúsculas+click para seleccionar otro&nbsp;&nbsp; Doble-click para mostrar &nbsp;&nbsp; Click+arrastrar para mover\r
+\r
+\r
+! BasicFrame\r
+BasicFrame.tab.Rocketdesign = Diseño del cohete\r
+BasicFrame.tab.Flightsim = Simulaciones de vuelo\r
+BasicFrame.title.Addnewcomp = Añadir un nuevo componente\r
+!BasicFrame.item.Openrocketdesign = Abrir un diseño de cohete\r
+!BasicFrame.item.Openexamplerocketdesign = Abrir un ejemplo de diseño de cohete\r
+!BasicFrame.item.SavecurRocketdesign = Guardar el diseño actual\r
+!BasicFrame.item.SavecurRocketdesnewfile = Guardar el diseño actual como un nuevo documento\r
+!BasicFrame.item.Printpart = Imprimir un listado de componentes y un esquema de aleta\r
+!BasicFrame.item.Closedesign = Cerrar el diseño actual\r
+!BasicFrame.item.Quitprogram = Abandonar el programa\r
+!BasicFrame.menu.Rocketedt = Mostrando el cohete\r
+BasicFrame.dlg.lbl1 = Diseño\r
+BasicFrame.dlg.lbl2 = No se ha guardado\r
+BasicFrame.dlg.lbl3 = ¿Quiere guardarlo?\r
+BasicFrame.dlg.title = Diseño no guardado\r
+BasicFrame.StageName.Sustainer = Etapa principal\r
+BasicFrame.WarningDialog.txt1 = Mientras se abría, se encontraron los siguiente problemas\r
+BasicFrame.WarningDialog.txt2 = Algunas configuraciones de diseño no pudieron cargarse correctamente.\r
+BasicFrame.WarningDialog.title = Precauciones mientras se abre el archivo\r
+\r
+\r
+! General error messages used in multiple contexts\r
+error.fileExists.title = El archivo ya existe\r
+error.fileExists.desc = El archivo con el nombre '{filename}' ya existe. ¿Desea sobrescribir la versión anterior?\r
+\r
+error.writing.title = Error al guardar el archivo\r
+error.writing.desc = Ha ocurrido un error al guardar el archivo:\r
+\r
+\r
+! Labels used in buttons of dialog windows\r
+# TODO: Rename these to "btn.xxx"\r
+button.ok = OK\r
+button.cancel = Cancelar\r
+button.close = Cerrar\r
+\r
+! Common labels used in buttons of dialog windows\r
+dlg.but.ok = OK\r
+dlg.but.cancel = Cancelar\r
+dlg.but.close = Cerrar\r
+\r
+! General file type names\r
+filetypes.pdf = Archivos PDF\r
+BasicFrame.SimpleFileFilter1 = Todos los diseños de cohete(*.ork; *.rkt)\r
+BasicFrame.SimpleFileFilter2 = Diseños OpenRocket (*.ork)\r
+BasicFrame.SimpleFileFilter3 = Diseños RockSim (*.rkt)\r
+BasicFrame.SimpleFileFilter4 = OpenRocket presets (*.orc)\r
+filetypes.images = Image files\r
+\r
+\r
+! About Dialog\r
+AboutDialog.lbl.version = Versión\r
+! The texts below provide additional credits for the translation maintainer\r
+! - In AboutDialog.lbl.translation replace "English" with the current language.\r
+! - AboutDialog.lbl.translator is the translator / group name (may be empty)\r
+! - AboutDialog.lbl.translatorWebsite is a URL to the translator / group (may be empty)\r
+! - AboutDialog.lbl.translatorIcon is the file name of an icon under pix/translators/ (may be empty)\r
+AboutDialog.lbl.translation = Traducido al español por:\r
+AboutDialog.lbl.translator = Tripoli Spain\r
+AboutDialog.lbl.translatorWebsite = http://www.tripoli-spain.org/\r
+AboutDialog.lbl.translatorIcon = logoTripoliSpain.png\r
+\r
+\r
+! Print dialog\r
+PrintDialog.title = Imprimir o exportar\r
+PrintDialog.but.previewAndPrint = Vista previa e Imprimir\r
+PrintDialog.checkbox.showByStage = Mostrar por etapas\r
+PrintDialog.lbl.selectElements = Seleccionar elementos a incluir:\r
+printdlg.but.saveaspdf = Guardar como PDF\r
+printdlg.but.preview = Previsualizar\r
+printdlg.but.settings = Configuración\r
+PrintDialog.error.preview.title = Imposible abrir vista previa\r
+PrintDialog.error.preview.desc1 = Imposible abrir vista previa en PDF.\r
+PrintDialog.error.preview.desc2 = Por favor use la opción Guardar como PDF.\r
+\r
+!PrintSettingsDialog\r
+PrintSettingsDialog.title = Configuración de la impresión\r
+PrintSettingsDialog.lbl.Templatefillcolor = Plantilla de colores:\r
+PrintSettingsDialog.lbl.Templatebordercolor = Color del borde de la plantilla:\r
+PrintSettingsDialog.lbl.Papersize = Tamaño del papel:\r
+PrintSettingsDialog.lbl.Paperorientation = Orientación del papel:\r
+PrintSettingsDialog.but.Reset = Reiniciar\r
+PrintSettingsDialog.but.Close = Cerrar\r
+\r
+\r
+! Bug Report dialog\r
+bugreport.dlg.title = Informe de errores\r
+bugreport.dlg.but.Sendbugreport = Enviar informe de error\r
+bugreport.dlg.but.Sendbugreport.Ttip = Enviar automáticamente un informe de error a los creadores de Open Rocket\r
+bugreport.dlg.successmsg1 = Informe de error enviado con éxito\r
+bugreport.dlg.successmsg2 = ¡Gracias por ayudar a mejorar Open Rocket!\r
+bugreport.dlg.successmsg3 = Informe de error enviado\r
+bugreport.dlg.connectedInternet = <html>Si está conectado a Internet, haga Clik en <em>Enviar informe de errores</em>.\r
+bugreport.dlg.otherwise = De otro modo, también puede copiar y enviar el texto a la dirección:\r
+bugreport.lbl.Theinformation = La información que ha detallado se incluirá en un informe de error público. Asegúrese de que no contiene ninguna información que usted no desee hacer pública.\r
+bugreport.dlg.failedmsg1 = OpenRocket fue incapaz de enviar el informe de error:\r
+bugreport.dlg.failedmsg2 = Por favor envíe manualmente el informe a\r
+bugreport.dlg.failedmsg3 = Error al enviar el informe\r
+bugreport.reportDialog.txt = <html><b>Puede realizar un informe de errores escribiendo en el formulario de abajo y enviarlo.</b><br>También puede informar de los errores adjuntando el archivo de su proyecto por email.\r
+bugreport.reportDialog.txt2 = <html><b>Por favor incluya una breve descripción de lo que estaba haciendo cuando ocurrió el error.</b>\r
+bugreport.dlg.provideDescription = Por favor, primero proporcione una descripción del error.\r
+bugreport.dlg.provideDescription.title = Descripción del error omitida\r
+\r
+\r
+! Debug log dialog\r
+debuglogdlg.but.clear = Limpiar\r
+debuglogdlg.OpenRocketdebuglog = Registro de sucesos\r
+debuglogdlg.Displayloglines = Mostrar líneas de registro:\r
+debuglogdlg.Follow = Seguir\r
+debuglogdlg.col.Time = Hora\r
+debuglogdlg.col.Level = Nivel\r
+debuglogdlg.col.Location = Localización\r
+debuglogdlg.col.Message = Mensaje\r
+debuglogdlg.lbl.Loglinenbr = Número de línea de registro:\r
+debuglogdlg.lbl.Time = Hora:\r
+debuglogdlg.lbl.Level = Nivel:\r
+debuglogdlg.lbl.Location = Localización:\r
+debuglogdlg.lbl.Logmessage = Texto del mensaje:\r
+debuglogdlg.lbl.Stacktrace = Trazabilidad de la pila:\r
+\r
+\r
+! Edit Motor configuration dialog\r
+edtmotorconfdlg.but.removemotor = Quitar motor\r
+edtmotorconfdlg.but.Selectmotor = Seleccionar motor\r
+edtmotorconfdlg.but.Removeconfiguration = Quitar configuración\r
+edtmotorconfdlg.but.Newconfiguration = Nueva configuración\r
+edtmotorconfdlg.lbl.Motormounts = <html><b>Porta motor:</b>\r
+edtmotorconfdlg.title.Editmotorconf = Mostrar las configuraciones de motor\r
+edtmotorconfdlg.selectcomp = <html>Seleccionar qué componentes tienen la función de porta motor:\r
+edtmotorconfdlg.lbl.Motorconfig = <html><b>Configuraciones del motor:</b>\r
+edtmotorconfdlg.lbl.Configname = Nombre de la configuración:\r
+edtmotorconfdlg.lbl.Leavenamedefault = Dejar el nombre por defecto.\r
+\r
+! Example design dialog\r
+exdesigndlg.but.open = Abrir\r
+exdesigndlg.lbl.Selectexample = Diseños de ejemplo:\r
+exdesigndlg.lbl.Openexampledesign = Abrir un ejemplo de diseño\r
+exdesigndlg.lbl.Exampledesignsnotfound = Los ejemplos de diseño podrían no encontrarse.\r
+exdesigndlg.lbl.Examplesnotfound = Ejemplos no encontrados\r
+\r
+\r
+! Material edit panel\r
+matedtpan.but.new = Nuevo\r
+matedtpan.but.edit = Editar\r
+matedtpan.but.delete = Borrar\r
+matedtpan.but.revertall = Borrar todo\r
+matedtpan.col.Material = Material\r
+matedtpan.col.Type = Tipo\r
+matedtpan.col.Density = Densidad\r
+matedtpan.col.but.ttip.New = Añadir un nuevo material\r
+matedtpan.title.Addcustmaterial = Añadir un material personalizado\r
+matedtpan.but.ttip.edit = Editar un material existente\r
+matedtpan.title.Editmaterial = Editar material\r
+matedtpan.title2.Editmaterial = Los materiales básicos no se pueden modificar, se añadirá como nuevo material personalizado\r
+matedtpan.but.ttip.delete = Borrar un material personalizado\r
+matedtpan.but.ttip.revertall = Borrar todos los materiales personalizados\r
+matedtpan.title.Deletealluser-defined = ¿Borrar todos los materiales personalizados?\r
+matedtpan.title.Revertall = ¿Revertir todo?\r
+matedtpan.lbl.edtmaterials = La edición de los materiales no afecta a los diseños ya existentes.\r
+\r
+!MaterialModel\r
+MaterialModel.title.Material = Material\r
+MaterialModel.title.Defcustmat = Definir nuevo material personalizado\r
+\r
+\r
+! Preference dialog\r
+pref.dlg.but.add = Agregar\r
+pref.dlg.but.reset = Reiniciar\r
+pref.dlg.but.checknow = Comprobar ahora\r
+pref.dlg.but.defaultmetric = Sistema Métrico por defecto\r
+pref.dlg.but.defaultimperial = Sistema Imperial por defecto\r
+pref.dlg.title.Preferences = Preferencias \r
+pref.dlg.tab.Units = Unidades\r
+pref.dlg.tab.Defaultunits = Unidades por defecto\r
+pref.dlg.tab.Materials = Materiales\r
+pref.dlg.tab.Custommaterials = Materiales personalizados\r
+pref.dlg.tab.Options = Opciones\r
+pref.dlg.tab.Miscellaneousoptions = Otras opciones\r
+pref.dlg.lbl.Positiontoinsert = Posición para introducir nuevos componentes del fuselaje: \r
+pref.dlg.lbl.Confirmdeletion = Confirmar borrar simulaciones: \r
+pref.dlg.lbl.User-definedthrust = Curvas de potencia definidas por el usuario: \r
+pref.dlg.lbl.Windspeed = Wind speed\r
+pref.dlg.Allthrustcurvefiles = Todos los ficheros de curvas de potencia (*.eng; *.rse; *.zip; directorios)\r
+pref.dlg.RASPfiles = Ficheros de motor RASP (*.eng)\r
+pref.dlg.RockSimfiles = Ficheros de motor Rocksim (*.rse)\r
+pref.dlg.ZIParchives = Archivos ZIP (*.zip)\r
+pref.dlg.checkbox.Checkupdates = Comprobar actualizaciones de software al arrancar\r
+pref.dlg.ttip.Checkupdatesnow = Comprobar actualizaciones de software ahora\r
+pref.dlg.lbl.Selectprefunits = Seleccione sus unidades preferidas:\r
+pref.dlg.lbl.Rocketdimensions = Dimensiones del cohete: \r
+pref.dlg.lbl.Linedensity = Densidad: \r
+pref.dlg.lbl.Motordimensions = Dimensiones del motor: \r
+pref.dlg.lbl.Surfacedensity = Densidad superficial: \r
+pref.dlg.lbl.Distance = Distancia:\r
+pref.dlg.lbl.Bulkdensity = Densidad media: \r
+pref.dlg.lbl.Velocity = Velocidad: \r
+pref.dlg.lbl.Surfaceroughness = Rugosidad de la superficie: \r
+pref.dlg.lbl.Acceleration = Aceleración: \r
+pref.dlg.lbl.Area = Área: \r
+pref.dlg.lbl.Mass = Masa: \r
+pref.dlg.lbl.Angle = Ángulo: \r
+pref.dlg.lbl.Force = Fuerza: \r
+pref.dlg.lbl.Rollrate = Valor de rotación: \r
+pref.dlg.lbl.Totalimpulse = Impulso total: \r
+pref.dlg.lbl.Temperature = Temperatura: \r
+pref.dlg.lbl.Momentofinertia = Momento de inercia: \r
+pref.dlg.lbl.Pressure = Presión: \r
+pref.dlg.lbl.Stability = Estabilidad: \r
+pref.dlg.lbl.FlightTime = Tiempo de vuelo: \r
+pref.dlg.lbl.effect1 = Los cambios tendrán efecto cuando se abra nuevamente el proyecto.\r
+pref.dlg.lbl.Checkingupdates = Comprobando actualizaciones...\r
+pref.dlg.lbl.msg1 = Ocurrió un error mientras se comunicaba con el servidor.\r
+pref.dlg.lbl.msg2 = Incapaz de recuperar la información de las actualizaciones\r
+pref.dlg.lbl.msg3 = Usted está utilizando la última versión de Open Rocket.\r
+pref.dlg.lbl.msg4 = No hay actualizaciones disponibles\r
+pref.dlg.PrefChoiseSelector1 = Preguntar siempre\r
+pref.dlg.PrefChoiseSelector2 = Insertar en medio\r
+pref.dlg.PrefChoiseSelector3 = Añadir al final\r
+pref.dlg.PrefBooleanSelector1 = Borrar\r
+pref.dlg.PrefBooleanSelector2 = Confirmar\r
+pref.dlg.Add = Añadir\r
+pref.dlg.DescriptionArea.Adddirectories = Añadir directorios, archivos de motor RASP (*.eng), archivos de motor RockSim (*.rse) o archivos ZIP separados por punto y coma (;) para cargar curvas de empuje externas.  Los cambios tendrán efecto la próxima vez que abra OpenRocket.\r
+\r
+PreferencesDialog.lbl.language = Idioma de la interfaz:\r
+PreferencesDialog.languages.default = Idioma por defecto\r
+PreferencesDialog.lbl.languageEffect = El idioma cambiará la próxima vez que abra OpenRocket.\r
+\r
+! Simulation edit dialog\r
+simedtdlg.but.runsimulation = Lanzar la simulación\r
+simedtdlg.but.resettodefault = Restaurar por defecto\r
+simedtdlg.but.add = Agregar\r
+simedtdlg.but.remove = Quitar\r
+simedtdlg.title.Editsim = Mostrar la simulación\r
+simedtdlg.lbl.Simname = Nombre de la simulación\r
+simedtdlg.tab.Launchcond = Condiciones del lanzamiento\r
+simedtdlg.tab.Simopt = Opciones de simulación\r
+simedtdlg.tab.Plotdata = Datos del gráfico\r
+simedtdlg.tab.CustomExpressions = Custom expressions\r
+simedtdlg.tab.Exportdata = Exportar datos\r
+simedtdlg.lbl.Motorcfg = Configuración del motor:\r
+simedtdlg.lbl.ttip.Motorcfg = Seleccionar la configuración del motor a usar\r
+simedtdlg.combo.ttip.motorconf = Seleccione la configuración del motor a usar\r
+simedtdlg.lbl.Wind = Viento\r
+simedtdlg.lbl.Averwindspeed = Velocidad media del viento\r
+simedtdlg.lbl.ttip.Averwindspeed = Velocidad media del viento en relación al suelo\r
+simedtdlg.lbl.Stddeviation = Desviación estándar\r
+simedtdlg.lbl.ttip.Stddeviation = <html>Desviación estándar de la velocidad del viento.<br>La velocidad del viento se encuentra dentro del doble de la desviación media en un 95% del tiempo.\r
+simedtdlg.lbl.Turbulenceintensity = Intensidad de la turbulencia\r
+simedtdlg.lbl.ttip.Turbulenceintensity1 = <html>La intensidad de la turbulencia es la desviación estándar dividida por la velocidad media del viento.<br>\r
+simedtdlg.lbl.ttip.Turbulenceintensity2 = Valores típicos en el campo\r
+simedtdlg.lbl.ttip.Turbulenceintensity3 = a\r
+simedtdlg.border.Atmoscond = Condiciones atmosféricas\r
+simedtdlg.checkbox.InterStdAtmosphere = Usar los patrones de Atmosfera Internacional\r
+simedtdlg.checkbox.ttip.InterStdAtmosphere1 = <html>Seleccionar para usar el modelo de la International Standard Atmosphere.<br>Este modelo tiene una temperatura de\r
+simedtdlg.checkbox.ttip.InterStdAtmosphere2 = Y una presión de\r
+simedtdlg.checkbox.ttip.InterStdAtmosphere3 = A nivel del mar.\r
+simedtdlg.lbl.Temperature = Temperatura:\r
+simedtdlg.lbl.ttip.Temperature = Temperatura en el campo de lanzamiento.\r
+simedtdlg.lbl.Pressure = Presión:\r
+simedtdlg.lbl.ttip.Pressure = Presión atmosférica en el campo de lanzamiento\r
+simedtdlg.lbl.Launchsite = Lugar de lanzamiento\r
+simedtdlg.lbl.Latitude = Latitud:\r
+simedtdlg.lbl.ttip.Latitude = <html>La latitud del campo de lanzamiento afecta a la atracción terrestre.<br>Los valores positivos se dan en el hemisferio Norte, los negativos en el hemisferio Sur.\r
+\r
+simedtdlg.lbl.Longitude = Longitud:\r
+simedtdlg.lbl.ttip.Longitude = <html>Requerido para modelos de elevación y predicción meteorológica.\r
+\r
+simedtdlg.lbl.Altitude = Altitud:\r
+simedtdlg.lbl.ttip.Altitude = <html>Los valores por encima del nivel del mar <br>afectan al modelado de las condicones atmosféricas.\r
+simedtdlg.border.Launchrod = Varilla para lanzar\r
+simedtdlg.lbl.Length = Longitud:\r
+simedtdlg.lbl.ttip.Length = Longitud de la varilla de lanzamiento\r
+simedtdlg.lbl.Angle = Ángulo:\r
+simedtdlg.lbl.ttip.Angle = El ángulo de la varilla de lanzamiento con respecto a la vertical.\r
+simedtdlg.lbl.Direction = Dirección:\r
+simedtdlg.lbl.ttip.Direction1 = <html>Dirección de la varilla de lanzamiento relativa al viento.<br>\r
+simedtdlg.lbl.ttip.Direction2 = Contra el viento\r
+simedtdlg.lbl.ttip.Direction3 = A favor del viento\r
+simedtdlg.border.Simopt = Opciones del simulador\r
+simedtdlg.lbl.Calcmethod = Método de cálculo\r
+simedtdlg.lbl.ttip.Calcmethod = <html>El método Barrowman extendido considera las fuerzas aerodinámicas <br>que actúan sobre cuerpos cilíndricos en cohetes que vuelan con un <br>ángulo de ataque (AOA) superior a 10 grados.\r
+simedtdlg.lbl.ExtBarrowman = Barrowman Extendido\r
+simedtdlg.lbl.Simmethod = Método de simulación:\r
+simedtdlg.lbl.ttip.Simmethod1 = <html>El simulador de seis-grados-de-libertad permite al cohete una total libertad durante el vuelo.<br>\r
+simedtdlg.lbl.ttip.Simmethod2 = La integración mejora usando el método de integración numérica Runge-Kutta de cuarto orden.\r
+simedtdlg.lbl.GeodeticMethod = Cálculos geodésicos:\r
+simedtdlg.lbl.ttip.GeodeticMethodTip = En relación al cálculo de las coordenadas terrestres. Esto también activa los cálculos del Efecto Coriolis.\r
+simedtdlg.lbl.Timestep = Duración de la etapa\r
+simedtdlg.lbl.ttip.Timestep1 = <html>Tiempo entre etapas de simulación.<br>Un tiempo mas corto de etapa origina una simulación mas exacta pero mas lenta.<br>\r
+simedtdlg.lbl.ttip.Timestep2 = Con 4<sup>th</sup> el método de ordenar en la simulación es bastante preciso con un tiempo de etapa de\r
+simedtdlg.but.ttip.resettodefault = Restituir el tiempo de etapa a su valor por defecto (\r
+simedtdlg.border.Simlist = Extensiones del simulador\r
+simedtdlg.txt.longA1 = <html><i>Extensiones del simulador</i> es una característica avanzada que permite que el código escrito por un usuario pueda conectar e interactuar con la simulación mientras ésta se está ejecutando.  \r
+simedtdlg.txt.longA2 = Para más detalles sobre las Extensiones, vea la documentación técnica de Open Rocket.\r
+simedtdlg.lbl.Curlist = Extensiones actuales\r
+simedtdlg.lbl.Addsimlist = Añadir una Extensión al simulador\r
+simedtdlg.lbl.Noflightdata = No hay datos disponibles del vuelo.\r
+simedtdlg.lbl.runsimfirst = Por favor ejecute la simulación primero.\r
+simedtdlg.chart.Simflight = Vuelo simulado\r
+simedtdlg.dlg.Simres = Resultados de la simulación\r
+simedtdlg.IntensityDesc.None = Ninguno\r
+simedtdlg.IntensityDesc.Verylow = Muy pesado\r
+simedtdlg.IntensityDesc.Low = Pesado\r
+simedtdlg.IntensityDesc.Medium = Medio\r
+simedtdlg.IntensityDesc.High = Alto\r
+simedtdlg.IntensityDesc.Veryhigh = Muy alto\r
+simedtdlg.IntensityDesc.Extreme = Extremo\r
+\r
+GeodeticComputationStrategy.flat.name = Ninguna\r
+GeodeticComputationStrategy.flat.desc = No incluir computaciones geodésicas.\r
+GeodeticComputationStrategy.spherical.name = Aproximación esférica\r
+GeodeticComputationStrategy.spherical.desc = <html>Al incluir las computaciones geodésicas se considera una Tierra esférica.<br>Este aspecto es bastante preciso en la mayoría de los proyectos.\r
+GeodeticComputationStrategy.wgs84.name = Elipsoidal WGS84\r
+GeodeticComputationStrategy.wgs84.desc = <html>Incluye las computaciones geodésicas sobre la referencia elipsoidal WGS84 utilizando el método de Vicenty.<br>Este aspecto es lento e innecesario en la mayoría de los casos.\r
+\r
+\r
+\r
+\r
+! Simulation Panel\r
+simpanel.but.newsimulation = Nueva simulación\r
+simpanel.but.editsimulation = Editar la simulación\r
+simpanel.but.runsimulations = Lanzar las simulaciones\r
+simpanel.but.deletesimulations = Borrar las simulaciones\r
+simpanel.but.plotexport = Exportar / Gráfica\r
+simpanel.but.ttip.newsimulation = Añadir una nueva simulación\r
+simpanel.but.ttip.editsim = Mostrar la simulación seleccionada\r
+simpanel.but.ttip.runsimu = Ejecutar de nuevo las simulaciones seleccionadas\r
+simpanel.but.ttip.deletesim = Borrar las simulaciones seleccionadas\r
+simpanel.checkbox.donotask = No preguntarme de nuevo\r
+simpanel.lbl.defpref = Puede cambiar la operación por defecto por las preferencias\r
+simpanel.dlg.lbl.DeleteSim1 = ¿Borrar las simulaciones seleccionadas?\r
+simpanel.dlg.lbl.DeleteSim2 = <html><i>Esta operación no puede deshacerse.</i>\r
+simpanel.dlg.lbl.DeleteSim3 = Borrar las simulaciones\r
+simpanel.col.Name = Nombre\r
+simpanel.col.Motors = Motores\r
+simpanel.col.Velocityoffrod = Velocidad al abandonar la guía\r
+simpanel.col.Velocityatdeploy = Velocidad al abrir paracaídas\r
+simpanel.col.Apogee = Apogeo\r
+simpanel.col.Maxvelocity = Velocidad máxima\r
+simpanel.col.Maxacceleration = Aceleración máxima\r
+simpanel.col.Timetoapogee = Tiempo hasta el apogeo\r
+simpanel.col.Flighttime = Duración del vuelo\r
+simpanel.col.Groundhitvelocity = Velocidad de llegada a tierra\r
+\r
+! SimulationRunDialog\r
+SimuRunDlg.title.RunSim = Ejecutar simulaciones\r
+SimuRunDlg.lbl.Running = Ejecutar\r
+SimuRunDlg.lbl.Simutime = Duración de la simulación:\r
+SimuRunDlg.lbl.Altitude = Altitud:\r
+SimuRunDlg.lbl.Velocity = Velocidad:\r
+SimuRunDlg.msg.Unabletosim = Incapaz de simular:\r
+SimuRunDlg.msg.errorOccurred = Ha ocurrido un error durante la simulación:\r
+SimuRunDlg.msg.AnException1 = Ha ocurrido una excepción durante la simulación:\r
+SimuRunDlg.msg.AnException2 = Por favor anote esto debajo como un error con todos los detalles.\r
+SimuRunDlg.msg.AssertionError1 = Se ha producido un error informático durante la simulación.\r
+SimuRunDlg.msg.AssertionError2 = Por favor anote esto debajo como un error con todos los detalles.\r
+SimuRunDlg.msg.unknownerror1 = Se ha detectado un error desconocido durante la simulación.\r
+SimuRunDlg.msg.unknownerror2 = El programa puede ser inestable, Guarde todos sus diseños y reinicie OpenRocket\r
+\r
+\r
+RK4SimulationStepper.error.valuesTooLarge = Los valores de la simulación exceden los límites. Pruebe a seleccionar un intervalo de tiempo más corto.\r
+\r
+\r
+! SimulationExportPanel\r
+SimExpPan.desc = Documentos separados por comas (*.csv)\r
+SimExpPan.border.Vartoexport = Variables para exportar\r
+SimExpPan.but.Selectall = Seleccionar todo\r
+SimExpPan.but.Selectnone = No seleccionar nada\r
+SimExpPan.border.Fieldsep = Separador de campo\r
+SimExpPan.lbl.Fieldsepstr = Caracter separador de campo\r
+SimExpPan.lbl.longA1 = <html>Caracter para separar campos en el documento exportado.<br>\r
+SimExpPan.lbl.longA2 = Para valores separados en archivo (CSV) use comas ','.\r
+SimExpPan.checkbox.Includesimudesc = Incluir descripción de la simulación\r
+SimExpPan.checkbox.ttip.Includesimudesc = Incluye un comentario en el inicio del documento describiendo la simulación.\r
+SimExpPan.border.Comments = Comentarios\r
+SimExpPan.checkbox.Includefielddesc = Incluir descripciones del campo\r
+SimExpPan.checkbox.ttip.Includefielddesc = Incluye una línea de comentario con las descripciones de las variables exportadas.\r
+SimExpPan.checkbox.Incflightevents = Incluir los eventos del vuelo\r
+SimExpPan.checkbox.ttip.Incflightevents = Incluye una línea de comentario para cada evento del vuelo\r
+SimExpPan.lbl.Commentchar = Carácter de comentario\r
+SimExpPan.lbl.ttip.Commentchar = Características que marcan una línea de comentario.\r
+SimExpPan.but.Exporttofile = Exportar al documento ...\r
+SimExpPan.Fileexists.desc1 = Archivo \"\r
+SimExpPan.Fileexists.desc2 = \" ya existe.  ¿Desea sobrescribirlo?\r
+SimExpPan.Fileexists.title = El archivo ya existe\r
+SimExpPan.ExportingVar.desc1 = Exportar variables\r
+SimExpPan.ExportingVar.desc2 = Exportar\r
+SimExpPan.ExportingVar.desc3 = variables de\r
+SimExpPan.Col.Variable = Variable\r
+SimExpPan.Col.Unit = Unidad\r
+\r
+\r
+CsvOptionPanel.separator.space = SPACE\r
+CsvOptionPanel.separator.tab = TAB\r
+\r
+\r
+! Custom expression general stuff\r
+customExpression.Name = Nombre\r
+customExpression.Symbol = Símbolo\r
+customExpression.Expression = Expresión\r
+customExpression.Units = Unidades\r
+customExpression.Operator = Operador\r
+customExpression.Description = Descripción\r
+\r
+! Custom expression panel\r
+customExpressionPanel.but.NewExpression = Nueva expresión\r
+customExpressionPanel.lbl.UpdateNote = Debe ejecutar la simulación antes de que los datos estén disponibles para grafiar.\r
+customExpressionPanel.lbl.CalcNote = Las expresiones serán ejecutadas en el orden indicado.\r
+customExpressionPanel.lbl.CustomExpressions = Expresiones personalizadas :\r
+customExpression.Units.but.ttip.Remove = Eliminar esta expresión\r
+customExpression.Units.but.ttip.Edit = Editar esta expresión\r
+customExpression.Units.but.ttip.MoveUp = Mover la expresión hacia arriba en el orden de cálculo\r
+customExpression.Units.but.ttip.MoveDown = Mover la expresión hacia abajoen el orcen de cálculo\r
+\r
+! Custom expression builder window\r
+ExpressionBuilderDialog.title = Constructor de expresiones\r
+ExpressionBuilderDialog.InsertVariable = Insertar variable\r
+ExpressionBuilderDialog.InsertOperator = Insertar operador\r
+ExpressionBuilderDialog.led.ttip.Name = El nombre no debe haber sido utilizado aún\r
+ExpressionBuilderDialog.led.ttip.Symbol = El símbolo no debe haber sido utilizado aún\r
+ExpressionBuilderDialog.led.ttip.Expression = La expresión debe utilizarse sólo con símbolos y operadores conocidos\r
+ExpressionBuilderDialog.CopyToOtherSimulations = Copiar en otras simulaciones\r
+ExpressionBuilderDialog.CopyToOtherSimulations.ttip = <html>Realice una copia de esta expresión en otras simulaciones de éste documento.<br>Esto no sobreescribirá o modificará las expresiones existentes en el resto de las simulaciones. \r
+\r
+! Custom expression variable selector\r
+CustomVariableSelector.title = Selector de variable\r
+\r
+! Custom operator selector\r
+CustomOperatorSelector.title = Selector de operador\r
+\r
+! Operators\r
+Operator.plus = Suma\r
+Operator.minus = Resta\r
+Operator.star = Producto\r
+Operator.div = Divisón\r
+Operator.mod = Módulo\r
+Operator.pow = Exponenciación\r
+Operator.abs = Valor absoluto\r
+Operator.ceil = Redondeo (al sigiente valor entero \r
+Operator.floor = Redondeo (al valor entero anterior \r
+Operator.sqrt = Raíz cuadrada\r
+Operator.cbrt = Raíz cúbica\r
+Operator.exp = Euler\'s número elevado al valor (e^x)\r
+Operator.ln = Logaritmo Natural\r
+Operator.sin = Seno\r
+Operator.cos = Coseno\r
+Operator.tan = Tangente\r
+Operator.asin = Arcoseno\r
+Operator.acos = Arcocoseno\r
+Operator.atan = Arcotangente\r
+Operator.hsin = Seno hiperbólico\r
+Operator.hcos = Coseno hiperbólico\r
+Operator.htan = Tangente hiperbólica\r
+\r
+! MotorPlot\r
+MotorPlot.title.Motorplot = Curva del motor\r
+MotorPlot.but.Select = Seleccionar la configuración del motor a usar\r
+MotorPlot.Chart.Motorthrustcurve = Curva de empuje del motor\r
+MotorPlot.Chart.Time = Tiempo / s\r
+MotorPlot.Chart.Thrust = Empuje / N\r
+MotorPlot.txt.Designation = Designación:\r
+MotorPlot.txt.Manufacturer = Fabricante:\r
+MotorPlot.txt.Type = Tipo:\r
+MotorPlot.txt.Delays = Retardos:\r
+MotorPlot.txt.Comment = Comentario:\n\r
+\r
+! Simulation plot panel\r
+simplotpanel.lbl.Presetplotconf = Configuración de la gráfica:\r
+simplotpanel.lbl.Xaxistype = Tipo de eje X:\r
+simplotpanel.lbl.Unit = Unidad:\r
+simplotpanel.lbl.Yaxistypes = Tipo de eje Y:\r
+simplotpanel.lbl.Flightevents = Eventos del vuelo:\r
+simplotpanel.but.All = Todo\r
+simplotpanel.but.None = Ninguno\r
+simplotpanel.but.NewYaxisplottype = Añadir nuevo eje Y en la gráfica\r
+simplotpanel.but.Plotflight = Ver gráfica\r
+simplotpanel.lbl.Axis = Ejes:\r
+simplotpanel.but.ttip.Removethisplot = Eliminar esta curva\r
+simplotpanel.Desc = Si no hay línea de tiempo, los datos aparecerán en el eje X según el instante en que se producen. \r
+simplotpanel.OptionPane.lbl1 = Se permite un máximo de 15 impresiones\r
+simplotpanel.OptionPane.lbl2 = No puede añadirse la curva\r
+simplotpanel.AUTO_NAME = Auto\r
+simplotpanel.LEFT_NAME = Izquierda\r
+simplotpanel.RIGHT_NAME = Derecha\r
+simplotpanel.CUSTOM = Personalizado\r
+SimulationPlotPanel.error.noPlotSelected = Por favor agregue una o más variables para el eje Y de la gráfica.\r
+SimulationPlotPanel.error.noPlotSelected.title = No se puede construir un gráfico\r
+\r
+! Component add buttons\r
+compaddbuttons.Bodycompandfinsets = Componentes del fuselaje y aletas\r
+compaddbuttons.Nosecone = Ojiva\r
+compaddbuttons.Bodytube = Cuerpo\ntubular\r
+compaddbuttons.Transition = Transición\r
+compaddbuttons.Trapezoidal = Trapezoidal\r
+compaddbuttons.Elliptical = Elíptica\r
+compaddbuttons.Freeform = Forma libre\r
+compaddbuttons.Launchlug = Soporte\npara guía\r
+compaddbuttons.Innercomponent = Componentes internos\r
+compaddbuttons.Innertube = Tubo\ninterior\r
+compaddbuttons.Coupler = Acoplador\r
+compaddbuttons.Centeringring = Anillo\nde centrado\r
+compaddbuttons.Bulkhead = Disco\nde enganche\r
+compaddbuttons.Engineblock = Retén\nde motor\r
+compaddbuttons.Massobjects = Accesorios\r
+compaddbuttons.Parachute = Paracaídas\r
+compaddbuttons.Streamer = Banderola\r
+compaddbuttons.Shockcord = Tirante de\nsuspensión\r
+compaddbuttons.Masscomponent = Componente\nmasa\r
+compaddbuttons.Donotaskmeagain = No me pregunte de nuevo\r
+compaddbuttons.Selectcomppos = Seleccionar la posición del componente\r
+compaddbuttons.lbl.Youcanchange = Puede cambiar la operación con las preferencias por defecto\r
+compaddbuttons.lbl.insertcomp = ¿Insertar el componente después del actual o al final?\r
+compaddbuttons.askPosition.Inserthere = Insertar aquí\r
+compaddbuttons.askPosition.Addtotheend = Añadir al final\r
+compaddbuttons.askPosition.Cancel = Cancelar\r
+\r
+! Component Analysis Dialog\r
+componentanalysisdlg.componentanalysis = Análisis de los componentes\r
+componentanalysisdlg.lbl.winddir = Dirección del viento:\r
+componentanalysisdlg.TitledBorder.warnings = Advertencias:\r
+componentanalysisdlg.ToggleBut.worst = Peor\r
+componentanalysisdlg.lbl.angleofattack = Ángulo de ataque:\r
+componentanalysisdlg.lbl.machnumber = Número Mach:\r
+componentanalysisdlg.lbl.rollrate = Valor de rotación:\r
+componentanalysisdlg.lbl.activestages = Etapas activas:\r
+componentanalysisdlg.lbl.motorconf = Configuración del Motor:\r
+componentanalysisdlg.TabStability.Col = Componente\r
+componentanalysisdlg.TabStability = Estabilidad\r
+componentanalysisdlg.TabStability.ttip = Información de Estabilidad\r
+componentanalysisdlg.dragTableModel.Col.Component = Componente\r
+componentanalysisdlg.dragTableModel.Col.Pressure = <html>Presión C<sub>D</sub>\r
+componentanalysisdlg.dragTableModel.Col.Base = <html>Base C<sub>D</sub>\r
+componentanalysisdlg.dragTableModel.Col.friction = <html>Rozamiento C<sub>D</sub>\r
+componentanalysisdlg.dragTableModel.Col.total = <html>Total C<sub>D</sub>\r
+componentanalysisdlg.dragTabchar = Características de rozamiento\r
+componentanalysisdlg.dragTabchar.ttip = Coeficientes de arrastre de los componentes.\r
+componentanalysisdlg.rollTableModel.Col.component = Componente\r
+componentanalysisdlg.rollTableModel.Col.rollforc = Coeficiente de rotación\r
+componentanalysisdlg.rollTableModel.Col.rolldamp = Coeficiente de corrección\r
+componentanalysisdlg.rollTableModel.Col.total = <html>Total C<sub>l</sub>\r
+componentanalysisdlg.rollTableModel = Dinámica de rotación\r
+componentanalysisdlg.rollTableModel.ttip = Dinámica del movimiento de rotación del cohete (spin)\r
+componentanalysisdlg.println.closingmethod = Llamar al método de cierre:\r
+componentanalysisdlg.println.settingnam = CONFIGURANDO VALORES NAN\r
+componentanalysisdlg.lbl.reflenght = Diámetro de referencia: \r
+componentanalysisdlg.lbl.refarea = Área de referencia: \r
+!componentanalysisdlg.But.close = Cerrar\r
+componentanalysisdlg.TabStability.Col.Component = Componente\r
+\r
+! Custom Material dialog\r
+custmatdlg.title.Custommaterial = Material personalizado\r
+custmatdlg.lbl.Materialname = Nombre del material: \r
+custmatdlg.lbl.Materialtype = Tipo de material:\r
+custmatdlg.lbl.Materialdensity = Densidad del material:\r
+custmatdlg.checkbox.Addmaterial = Agregar este material a la base de datos\r
+\r
+\r
+! Ring Component Config\r
+ringcompcfg.OuterRadius = Radio exterior:\r
+ringcompcfg.Automatic = Automático\r
+ringcompcfg.InnerRadius = Radio interior:\r
+ringcompcfg.Thickness = Espesor:\r
+ringcompcfg.Length = Longitud:\r
+ringcompcfg.Positionrelativeto = Posición relativa a:\r
+ringcompcfg.plus = Localización:\r
+ringcompcfg.PositionValue = Valor de posición:\r
+ringcompcfg.Radialdistance = Distancia radial:\r
+ringcompcfg.Distancefrom = Distancia desde la línea central del cohete:\r
+ringcompcfg.Radialdirection = Dirección radial:\r
+ringcompcfg.radialdirectionfrom = En dirección radial desde la línea central del cohete\r
+ringcompcfg.but.Reset = Reiniciar\r
+ringcompcfg.but.Resetcomponant = Reubicar el componente en la línea central del cohete\r
+ringcompcfg.EngineBlock.desc = <html>Un <b>retén de motor</b> impide que el motor se desplace hacia delante, por dentro del tubo porta motor.<br><br>Para añadir un motor, cree un <b>Cuerpo tubular</b> o <b>Tubo interior</b> y desígnelo como porta motor en la pestaña <em>Motor</em>.\r
+ringcompcfg.note.desc = Nota: El tubo interior no afectará a la aerodinámica del cohete salvo que esté situado fuera del fuselaje.\r
+\r
+\r
+! Body Tube Config\r
+BodyTubecfg.lbl.Bodytubelength = Longitud del tubo:\r
+BodyTubecfg.lbl.Outerdiameter = Diámetro exterior:\r
+BodyTubecfg.lbl.Innerdiameter = Diámetro interior:\r
+BodyTubecfg.lbl.Wallthickness = Espesor de la pared:\r
+BodyTubecfg.tab.General = General\r
+BodyTubecfg.tab.Generalproperties = Propiedades generales\r
+BodyTubecfg.tab.Motor = Motor\r
+BodyTubecfg.tab.Motormountconf = Configuración del porta motor\r
+BodyTubecfg.checkbox.Automatic = Automático\r
+BodyTubecfg.checkbox.Filled = Sólido\r
+\r
+! FinSetConfig\r
+FinSetConfig.tab.Fintabs = Raíz de aleta\r
+FinSetConfig.tab.Through-the-wall = Parte de la aleta por dentro del fuselaje\r
+FinSetConfig.but.Converttofreeform = Convertir a forma libre\r
+FinSetConfig.but.Converttofreeform.ttip = Convertir esta forma de aleta a una forma libre\r
+FinSetConfig.Convertfinset = Convertir la configuración de aleta\r
+FinSetConfig.but.Splitfins = Separar las aletas\r
+FinSetConfig.but.Splitfins.ttip = Dividir la configuración de aleta en varias separadas\r
+FinSetConfig.but.AutoCalc = Calcular automáticamente\r
+FinSetConfig.lbl.Through-the-wall  = Raíz de aleta a través de la pared: \r
+FinSetConfig.lbl.Tablength = Longitud de la raíz:\r
+FinSetConfig.ttip.Tablength = La longitud de la raíz de aleta.\r
+FinSetConfig.lbl.Tabheight = Altura de la raíz: \r
+FinSetConfig.ttip.Tabheight = Envergadura en altura de la raíz de aleta.\r
+FinSetConfig.lbl.Tabposition = Posición de la raíz:\r
+FinSetConfig.ttip.Tabposition = Posición de la raíz de aleta.\r
+FinSetConfig.lbl.relativeto = Relativo a\r
+\r
+!FinMarkingGuide\r
+FinMarkingGuide.lbl.Front = Frente\r
+\r
+! MotorDatabaseLoadingDialog\r
+MotorDbLoadDlg.title = Carga de motores\r
+MotorDbLoadDlg.Loadingmotors = Cargando motores...\r
+\r
+! RocketConfig\r
+RocketCfg.lbl.Designname = Nombre del proyecto:\r
+RocketCfg.lbl.Designer = Proyectista:\r
+RocketCfg.lbl.Comments = Comentarios:\r
+RocketCfg.lbl.Revisionhistory = Histórico de la revisión:\r
+RocketCfg.lbl.Material = Material:\r
+\r
+! ShockCordConfig\r
+ShockCordCfg.lbl.Shockcordlength = Longitud del tirante de suspensión\r
+\r
+! RocketComponentConfig\r
+RocketCompCfg.lbl.Componentname = Nombre del componente:\r
+RocketCompCfg.ttip.Thecomponentname = El nombre del componente.\r
+RocketCompCfg.tab.Override = Masa y CG\r
+RocketCompCfg.tab.MassandCGoverride = Especificar la Masa y el CG del componente.\r
+RocketCompCfg.tab.Figure = Estilo\r
+RocketCompCfg.tab.Figstyleopt = Opciones de estilo de la figura\r
+RocketCompCfg.tab.Comment = Comentarios\r
+RocketCompCfg.tab.Specifyacomment = Especifique un comentario para el componente\r
+RocketCompCfg.lbl.Mass = Masa:\r
+RocketCompCfg.lbl.Componentmass = Masa del componente:\r
+RocketCompCfg.lbl.overriddento = (Elegido para\r
+RocketCompCfg.lbl.overriddenby = (Elegido por\r
+RocketCompCfg.lbl.Componentmaterial = Material del componente:\r
+RocketCompCfg.lbl.Componentfinish = Acabado:\r
+RocketCompCfg.lbl.ttip.componentmaterialaffects = El material del componente afecta a la masa total del modelo.\r
+RocketCompCfg.combo.ttip.componentmaterialaffects = El material del componente afecta su peso.\r
+RocketCompCfg.lbl.longA1 = <html>El acabado del componente afecta a su coeficiente de rozamiento.<br>\r
+RocketCompCfg.lbl.longA2 = El valor indicado es el promedio de la rugosidad en altura de la superficie.\r
+RocketCompCfg.but.Setforall = Aplicar a todos\r
+RocketCompCfg.but.ttip.Setforall = Aplicar este acabado a todos los componentes del cohete.\r
+RocketCompCfg.lbl.Overridemassorcenter = Especificar la masa y el CG del componente \r
+RocketCompCfg.checkbox.Overridemass = Especificar la masa:\r
+RocketCompCfg.checkbox.Overridecenterofgrav = Especificar el CG:\r
+RocketCompCfg.checkbox.OverridemassandCG = Incluir la masa y el CG de todos los subcomponentes\r
+RocketCompCfg.lbl.longB1 = <html>En la masa especificada no se incluye la de los motores.<br>\r
+RocketCompCfg.lbl.longB2 = El CG se mide desde el extremo frontal del componente  \r
+RocketCompCfg.lbl.Commentsonthe = Comentarios sobre\r
+RocketCompCfg.lbl.Figurestyle = Estilo de dibujo:\r
+RocketCompCfg.lbl.Componentcolor = Color del componente:\r
+RocketCompCfg.lbl.Choosecolor = Elija color\r
+RocketCompCfg.checkbox.Usedefaultcolor = Usar color por defecto\r
+RocketCompCfg.lbl.Complinestyle = Estilo de línea del componente:\r
+RocketCompCfg.but.Saveasdefstyle = Guardar como estilo por defecto\r
+RocketCompCfg.lbl.Diameter = Diámetro:\r
+RocketCompCfg.lbl.Length = Longitud:\r
+RocketCompCfg.lbl.Thickness = Espesor:\r
+RocketCompCfg.checkbox.Endcapped = Extremo truncado\r
+RocketCompCfg.ttip.Endcapped = Si el extremo del soporte está truncado.\r
+RocketCompCfg.title.Noseconeshoulder = Acople de la ojiva\r
+RocketCompCfg.title.Aftshoulder = Trasera del acople\r
+RocketCompCfg.border.Foreshoulder = Delantera del acople\r
+!RocketCompCfg.lbl.Length = Longitud:\r
+\r
+! BulkheadConfig\r
+BulkheadCfg.tab.Diameter = Diámetro:\r
+BulkheadCfg.tab.Thickness = Espesor:\r
+BulkheadCfg.tab.General = General\r
+BulkheadCfg.tab.Generalproperties = Propiedades generales\r
+\r
+!CenteringRingConfig\r
+CenteringRingCfg.tab.Outerdiam = Diámetro exterior:\r
+CenteringRingCfg.tab.Innerdiam = Diámetro interior:\r
+CenteringRingCfg.tab.Thickness = Espesor:\r
+CenteringRingCfg.tab.General = General\r
+CenteringRingCfg.tab.Generalproperties = Propiedades generales\r
+\r
+!ComponentConfigDialog\r
+ComponentCfgDlg.configuration = \r
+ComponentCfgDlg.configuration1 = Configuración\r
+ComponentCfgDlg.Modify = Modificar\r
+\r
+!StageConfig\r
+StageConfig.tab.Separation = Separación\r
+StageConfig.tab.Separation.ttip = Opciones de separación de etapa\r
+StageConfig.separation.lbl.title = Seleccione el instante de separación de esta etapa:\r
+StageConfig.separation.lbl.plus = más\r
+StageConfig.separation.lbl.seconds = segundos\r
+\r
+!EllipticalFinSetConfig\r
+EllipticalFinSetCfg.Nbroffins = Número de aletas:\r
+EllipticalFinSetCfg.Rotation = Rotación de las aletas:\r
+EllipticalFinSetCfg.Fincant = Inclinación de las aletas:\r
+EllipticalFinSetCfg.Rootchord = Longitud línea base:\r
+EllipticalFinSetCfg.Height = Altura:\r
+EllipticalFinSetCfg.Positionrelativeto = Posición relativa a:\r
+EllipticalFinSetCfg.plus = Localización:\r
+EllipticalFinSetCfg.FincrossSection = Borde de la aleta:\r
+EllipticalFinSetCfg.Thickness = Espesor:\r
+EllipticalFinSetCfg.General = General\r
+EllipticalFinSetCfg.Generalproperties = Propiedades generales\r
+EllipticalFinSetCfg.ttip.Fincant = El ángulo de inclinación de las aletas respecto al eje central del fuselaje.\r
+\r
+!FreeformFinSetConfig\r
+FreeformFinSetCfg.tab.General = General\r
+FreeformFinSetCfg.tab.ttip.General = Propiedades generales\r
+FreeformFinSetCfg.tab.Shape = Forma\r
+FreeformFinSetCfg.tab.ttip.Finshape = Forma de la aleta\r
+FreeformFinSetCfg.lbl.Numberoffins = Número de aletas:\r
+FreeformFinSetCfg.lbl.Finrotation = Rotación de las aletas:\r
+FreeformFinSetCfg.lbl.Fincant = Inclinación de las aletas:\r
+FreeformFinSetCfg.lbl.ttip.Fincant = El ángulo de inclinación de las aletas respecto al eje central del fuselaje.\r
+FreeformFinSetCfg.lbl.Posrelativeto = Posición relativa a:\r
+FreeformFinSetCfg.lbl.plus = Localización:\r
+FreeformFinSetCfg.lbl.FincrossSection = Borde de la aleta:\r
+FreeformFinSetCfg.lbl.Thickness = Espesor:\r
+!DobleClic 1 + 2 en el mensaje "Doble-Click para editar", corta aproximadamente por la mitad\r
+FreeformFinSetConfig.lbl.doubleClick1 = Doble Click en la lista\r
+FreeformFinSetConfig.lbl.doubleClick2 = para editar\r
+FreeformFinSetConfig.lbl.clickDrag = Click (sobre línea)+arrastrar: Agregar punto\r
+FreeformFinSetConfig.lbl.ctrlClick = Control+Click (sobre punto): Eliminar punto\r
+FreeformFinSetConfig.lbl.scaleFin = Dimensionar\r
+\r
+\r
+!InnerTubeConfig\r
+InnerTubeCfg.tab.Motor = Motor\r
+InnerTubeCfg.tab.ttip.Motor = Configuración del porta motor\r
+InnerTubeCfg.tab.Cluster = Cluster\r
+InnerTubeCfg.tab.ttip.Cluster = Configuración del cluster\r
+InnerTubeCfg.tab.Radialpos = Posición radial\r
+InnerTubeCfg.tab.ttip.Radialpos = Posición radial\r
+InnerTubeCfg.lbl.Selectclustercfg = Elija la configuración del cluster:\r
+InnerTubeCfg.lbl.TubeSep = Separación del tubo:\r
+InnerTubeCfg.lbl.ttip.TubeSep = Una separación de los tubos con valor 1.0 indica que están tocándose unos con otros\r
+InnerTubeCfg.lbl.Rotation = Rotación:\r
+InnerTubeCfg.lbl.ttip.Rotation = Configuración del ángulo de rotación del cluster\r
+InnerTubeCfg.lbl.Rotangle = Angulo de rotación del cluster\r
+InnerTubeCfg.but.Splitcluster = Tubos independientes\r
+InnerTubeCfg.lbl.longA1 = <html>Separar los tubos del cluster para convertirlos en componentes internos independientes.<br>\r
+InnerTubeCfg.lbl.longA2 = Esto también duplica todos los componentes unidos a este tubo interior.\r
+InnerTubeCfg.but.Resetsettings = Reiniciar configuración\r
+InnerTubeCfg.but.ttip.Resetsettings = Reiniciar la separación y la rotación con los valores predeterminados\r
+\r
+! LaunchLugConfig\r
+LaunchLugCfg.lbl.Length = Longitud:\r
+LaunchLugCfg.lbl.Outerdiam = Diámetro exterior:\r
+LaunchLugCfg.lbl.Innerdiam = Diámetro interior:\r
+LaunchLugCfg.lbl.Thickness = Espesor:\r
+LaunchLugCfg.lbl.Radialpos = Posición radial:\r
+LaunchLugCfg.lbl.Posrelativeto = Posición relativa a:\r
+LaunchLugCfg.lbl.plus = Localización:\r
+LaunchLugCfg.tab.General = General\r
+LaunchLugCfg.tab.Generalprop = Propiedades generales\r
+\r
+! MassComponentConfig\r
+MassComponentCfg.lbl.Mass = Masa:\r
+MassComponentCfg.lbl.Density = Approximate density:\r
+MassComponentCfg.lbl.Length = Longitud:\r
+MassComponentCfg.lbl.Diameter = Diámetro:\r
+MassComponentCfg.lbl.PosRelativeto = Posición relativa a:\r
+MassComponentCfg.lbl.plus = Localización:\r
+MassComponentCfg.tab.General = General\r
+MassComponentCfg.tab.ttip.General = Propiedades generales\r
+MassComponentCfg.tab.Radialpos = Posición radial\r
+MassComponentCfg.tab.ttip.Radialpos = Configuración de la posición radial\r
+MassComponentCfg.lbl.Radialdistance = Distancia radial:\r
+MassComponentCfg.lbl.Radialdirection = Dirección radial:\r
+MassComponentCfg.but.Reset = Reiniciar\r
+\r
+! MotorConfig\r
+MotorCfg.checkbox.compmotormount = Este componente es un porta motor\r
+MotorCfg.lbl.Motorcfg = Configuración del motor:\r
+MotorCfg.but.New = Nuevo\r
+MotorCfg.lbl.Currentmotor = Motor actual:\r
+MotorCfg.lbl.Motoroverhang = Sobresalida del motor:\r
+MotorCfg.lbl.Ignitionat = Encendido en:\r
+MotorCfg.lbl.plus = Retardo:\r
+MotorCfg.lbl.seconds = segundos.\r
+MotorCfg.lbl.longA1 = El diseño actual tiene una sola etapa.\r
+MotorCfg.lbl.longA2 = Pueden agregarse etapas haciendo Click en \"Nueva etapa\".\r
+MotorCfg.lbl.longB1 = El diseño actual tiene\r
+MotorCfg.lbl.longB2 = etapas.\r
+MotorCfg.but.Selectmotor = Seleccionar motor\r
+MotorCfg.but.Removemotor = Quitar motor\r
+MotorCfg.lbl.motorLabel = Ninguno\r
+\r
+! NoseConeConfig\r
+NoseConeCfg.lbl.Noseconeshape = Forma:\r
+NoseConeCfg.lbl.Shapeparam = Valor de forma:\r
+NoseConeCfg.lbl.Noseconelength = Longitud:\r
+NoseConeCfg.lbl.Basediam = Diámetro de la base:\r
+NoseConeCfg.checkbox.Automatic = Automático\r
+NoseConeCfg.lbl.Wallthickness = Espesor de la pared:\r
+NoseConeCfg.checkbox.Filled = Sólido\r
+NoseConeCfg.tab.General = General\r
+NoseConeCfg.tab.ttip.General = Propiedades generales\r
+NoseConeCfg.tab.Shoulder = Acoplamiento\r
+NoseConeCfg.tab.ttip.Shoulder = Propiedades del acople\r
+\r
+! ParachuteConfig\r
+ParachuteCfg.lbl.Canopy = Pabellón\r
+ParachuteCfg.lbl.Diameter = Diámetro:\r
+ParachuteCfg.lbl.Material = Material:\r
+ParachuteCfg.combo.MaterialModel = El material del componente afecta a su peso.\r
+ParachuteCfg.lbl.longA1 = <html>Coeficiente de arrastre C<sub>D</sub>:\r
+ParachuteCfg.lbl.longB1 = <html>Coeficiente de rozamiento relativo al área total del paracaídas.<br>\r
+ParachuteCfg.lbl.longB2 = Un mayor coeficiente de rozamiento genera un valor de descenso más lento.  \r
+ParachuteCfg.lbl.longB3 = Un valor típico para los paracaídas es 0,8.\r
+ParachuteCfg.but.Reset = Reiniciar\r
+ParachuteCfg.lbl.Shroudlines = Cuerdas:\r
+ParachuteCfg.lbl.Numberoflines = Número de cuerdas:\r
+ParachuteCfg.lbl.Linelength = Longitud de cuerda:\r
+ParachuteCfg.lbl.Material = Material:\r
+ParachuteCfg.lbl.Posrelativeto = Posición relativa a:\r
+ParachuteCfg.lbl.plus = Localización:\r
+ParachuteCfg.lbl.Packedlength = Longitud empaquetado:\r
+ParachuteCfg.lbl.Packeddiam = Diámetro del empaquetado:\r
+ParachuteCfg.lbl.Deploysat = Despliegue en:\r
+ParachuteCfg.lbl.seconds = segundos.\r
+ParachuteCfg.lbl.Altitude = Altitud:\r
+ParachuteCfg.tab.General = General\r
+ParachuteCfg.tab.ttip.General = Propiedades generales\r
+ParachuteCfg.tab.Radialpos = Posición radial\r
+ParachuteCfg.tab.ttip.Radialpos = Configuración de la posición radial\r
+ParachuteCfg.lbl.Radialdistance = Distancia radial:\r
+ParachuteCfg.lbl.Radialdirection = Dirección radial:\r
+ParachuteCfg.but.Reset = Reiniciar\r
+ParachuteCfg.lbl.plusdelay = Retardo:\r
+\r
+! ShockCordConfig \r
+ShockCordCfg.lbl.Shockcordlength = Longitud del tirante de suspensión\r
+ShockCordCfg.lbl.Shockcordmaterial = Material del tirante de suspensión:\r
+ShockCordCfg.lbl.Posrelativeto = Posición relativa a:\r
+ShockCordCfg.lbl.plus = Localización:\r
+ShockCordCfg.lbl.Packedlength = Longitud del empaquetado:\r
+ShockCordCfg.lbl.Packeddiam = Diámetro del empaquetado:\r
+ShockCordCfg.tab.General = General\r
+ShockCordCfg.tab.ttip.General = Propiedades generales\r
+\r
+!SleeveConfig\r
+SleeveCfg.tab.Outerdiam = Diámetro exterior:\r
+SleeveCfg.tab.Innerdiam = Diámetro interior:\r
+SleeveCfg.tab.Wallthickness = Espesor de la pared:\r
+SleeveCfg.tab.Length = Longitud:\r
+SleeveCfg.tab.General = General\r
+SleeveCfg.tab.Generalproperties = Propiedades generales\r
+\r
+! StreamerConfig\r
+StreamerCfg.lbl.Striplength = Longitud de la cinta:\r
+StreamerCfg.lbl.Stripwidth = Ancho de la cinta:\r
+StreamerCfg.lbl.Striparea = Área de la cinta:\r
+StreamerCfg.lbl.Aspectratio = Relación de aspecto:\r
+StreamerCfg.lbl.Material = Material:\r
+StreamerCfg.combo.ttip.MaterialModel = El material del componente afecta a su peso.\r
+StreamerCfg.lbl.longA1 = <html>Coeficiente de rozamiento C<sub>D</sub>:\r
+StreamerCfg.lbl.longB1 = <html>Coeficiente de rozamiento relativo al área total de la banderola.<br>\r
+StreamerCfg.lbl.longB2 = Un mayor coeficiente de rozamiento genera un valor de descenso más lento.\r
+StreamerCfg.lbl.Automatic = Automático\r
+StreamerCfg.lbl.longC1 = El coeficiente de rozamiento depende del área de la banderola.\r
+StreamerCfg.lbl.Posrelativeto = Posición relativa a:\r
+StreamerCfg.lbl.plus = Localización:\r
+StreamerCfg.lbl.Packedlength = Longitud de empaquetado:\r
+StreamerCfg.lbl.Packeddiam = Diámetro de empaquetado:\r
+StreamerCfg.lbl.Deploysat = Despliegue en:\r
+StreamerCfg.lbl.seconds = segundos.\r
+StreamerCfg.lbl.Altitude = Altitud:\r
+StreamerCfg.tab.General = General\r
+StreamerCfg.tab.ttip.General = Propiedades generales\r
+StreamerCfg.tab.Radialpos = Posición radial\r
+StreamerCfg.tab.ttip.Radialpos = Configuración de posición radial\r
+StreamerCfg.lbl.Radialdistance = Distancia radial:\r
+StreamerCfg.lbl.Radialdirection = Dirección radial:\r
+StreamerCfg.but.Reset = Reiniciar\r
+StreamerCfg.lbl.plusdelay = Retardo:\r
+\r
+! ThicknessRingComponentConfig\r
+ThicknessRingCompCfg.tab.Outerdiam = Diámetro exterior:\r
+ThicknessRingCompCfg.tab.Innerdiam = Diámetro Interior:\r
+ThicknessRingCompCfg.tab.Wallthickness = Espesor de la pared:\r
+ThicknessRingCompCfg.tab.Length = Longitud:\r
+ThicknessRingCompCfg.tab.General = General\r
+ThicknessRingCompCfg.tab.Generalprop = Propiedades generales\r
+\r
+! TransitionConfig\r
+TransitionCfg.lbl.Transitionshape = Forma de la transición:\r
+TransitionCfg.checkbox.Clipped = Acortado\r
+TransitionCfg.lbl.Shapeparam = Valor de forma:\r
+TransitionCfg.lbl.Transitionlength = Longitud de la transición:\r
+TransitionCfg.lbl.Forediam = Diámetro delantero:\r
+TransitionCfg.checkbox.Automatic = Automático\r
+TransitionCfg.lbl.Aftdiam = Diámetro trasero:\r
+TransitionCfg.lbl.Wallthickness = Espesor de la pared:\r
+TransitionCfg.checkbox.Filled = Sólido\r
+TransitionCfg.tab.General = General\r
+TransitionCfg.tab.Generalproperties = Propiedades generales\r
+TransitionCfg.tab.Shoulder = Acoplamiento\r
+TransitionCfg.tab.Shoulderproperties = Propiedades del acople\r
+\r
+! TrapezoidFinSetConfig\r
+TrapezoidFinSetCfg.lbl.Nbroffins = Número de aletas:\r
+TrapezoidFinSetCfg.lbl.ttip.Nbroffins = Número de aletas en la base de aletas.\r
+TrapezoidFinSetCfg.lbl.Finrotation = Rotación de las aletas:\r
+TrapezoidFinSetCfg.lbl.ttip.Finrotation = Posición de las aletas alrededor del fuselaje.\r
+TrapezoidFinSetCfg.lbl.Fincant = Inclinación de las aletas:\r
+TrapezoidFinSetCfg.lbl.ttip.Fincant = El ángulo de inclinación de las aletas respecto al eje central del fuselaje.\r
+TrapezoidFinSetCfg.lbl.Rootchord = Longitud de la línea base:\r
+TrapezoidFinSetCfg.lbl.Tipchord = Longitud del borde superior:\r
+TrapezoidFinSetCfg.lbl.Height = Altura:\r
+TrapezoidFinSetCfg.lbl.Sweeplength = Desplazamiento borde superior:\r
+TrapezoidFinSetCfg.lbl.Sweepangle = Ángulo del borde de ataque:\r
+TrapezoidFinSetCfg.lbl.FincrossSection = Borde de la aleta:\r
+TrapezoidFinSetCfg.lbl.Thickness = Espesor:\r
+TrapezoidFinSetCfg.lbl.Posrelativeto = Posición relativa a:\r
+TrapezoidFinSetCfg.lbl.plus = Localización:\r
+TrapezoidFinSetCfg.tab.General = General\r
+TrapezoidFinSetCfg.tab.Generalproperties = Propiedades generales\r
+\r
+!MotorConfigurationModel\r
+MotorCfgModel.Editcfg = Editar configuraciones\r
+\r
+! StorageOptionChooser\r
+StorageOptChooser.lbl.Simdatatostore = Almacenar datos simulados\r
+StorageOptChooser.rdbut.Allsimdata = Todos los datos simulados\r
+StorageOptChooser.lbl.longA1 = <html>Almacenar todos los datos simulados.<br>\r
+StorageOptChooser.lbl.longA2 = puede generar archivos muy grandes\r
+StorageOptChooser.rdbut.Every = Cada\r
+StorageOptChooser.lbl.longB1 = <html>Almacenar los valores de impresión de este apartado.<br>\r
+StorageOptChooser.lbl.longB2 = Genera valores grandes en archivos más pequeños.\r
+StorageOptChooser.lbl.seconds = Segundos\r
+StorageOptChooser.rdbut.Onlyprimfig = Sólo figuras principales\r
+StorageOptChooser.lbl.longC1 = <html>Almacenar sólo los valores en la tabla resumen.<br>\r
+StorageOptChooser.lbl.longC2 = Estos resultados se guardan en archivos mas pequeños.\r
+StorageOptChooser.checkbox.Compfile = Archivo comprimido\r
+StorageOptChooser.lbl.UsingComp = Usando la compresión reducimos el tamaño de los archivos. \r
+StorageOptChooser.lbl.longD1 = Con las opciones actuales puede realizarse una estamción del tamaño final del archivo.\r
+StorageOptChooser.ttip.Saveopt = Guardar opciones\r
+StorageOptChooser.lbl.Estfilesize = Estimación del tamaño del archivo:\r
+StorageOptChooser.lbl.Saveopt = Guardar opciones\r
+\r
+! ThrustCurveMotorSelectionPanel\r
+TCMotorSelPan.lbl.Selrocketmotor = Seleccione el motor del cohete:\r
+TCMotorSelPan.checkbox.hideSimilar = Borrar las curvas muy similares\r
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = Mostrar todos los motores\r
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc2 = Mostrar motores con diámetro inferior al del tubo portamotor\r
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc3 = Mostrar motores con diámetro igual al del tubo portamotor\r
+TCMotorSelPan.lbl.Motormountdia = Diámetro del portamotor:\r
+TCMotorSelPan.lbl.Search = Buscar:\r
+TCMotorSelPan.lbl.Selectthrustcurve = Seleccione curva de empuje:\r
+TCMotorSelPan.lbl.Ejectionchargedelay = Retardo de la carga de eyección:\r
+TCMotorSelPan.equalsIgnoreCase.None = Ninguno\r
+TCMotorSelPan.lbl.NumberofsecondsorNone = (Número de segundos o \"Ninguno\")\r
+TCMotorSelPan.lbl.Totalimpulse = Impulso total:\r
+TCMotorSelPan.lbl.Avgthrust = Empuje medio:\r
+TCMotorSelPan.lbl.Maxthrust = Empuje máximo:\r
+TCMotorSelPan.lbl.Burntime = Tiempo de quemado:\r
+TCMotorSelPan.lbl.Launchmass = Masa total:\r
+TCMotorSelPan.lbl.Emptymass = Masa carcasa:\r
+TCMotorSelPan.lbl.Datapoints = Datos de los puntos:\r
+TCMotorSelPan.lbl.Digest = Resumen:\r
+TCMotorSelPan.title.Thrustcurve = Curva de empuje:\r
+TCMotorSelPan.title.Thrust = Empuje\r
+TCMotorSelPan.delayBox.None = Ninguno\r
+\r
+\r
+! PlotDialog\r
+PlotDialog.title.Flightdataplot = Representar los datos de vuelo\r
+PlotDialog.Chart.Simulatedflight = Vuelo simulado\r
+PlotDialog.CheckBox.Showdatapoints = Mostrar los datos de los puntos\r
+PlotDialog.lbl.Chart = Click+bajar el rozamiento+derecha ampliar, arriba+izquierda disminuir\r
+\r
+\r
+! "main" prefix is used for the main application dialog\r
+\r
+# FIXME: Rename the description keys \r
+\r
+main.menu.file = Archivo\r
+main.menu.file.desc = Tareas relacionadas con el manejo de archivos\r
+main.menu.file.new = Nuevo\r
+main.menu.file.new.desc = Crear un nuevo diseño de cohete\r
+main.menu.file.open = Abrir ...\r
+BasicFrame.item.Openrocketdesign = Abrir un diseño de cohete\r
+main.menu.file.openRecent = Open Recent...\r
+BasicFrame.item.Openrecentrocketdesign = Open a recent rocket design\r
+main.menu.file.openExample = Abrir ejemplo ...\r
+BasicFrame.item.Openexamplerocketdesign = Abrir un ejemplo de diseño de cohete\r
+main.menu.file.save = Guardar\r
+BasicFrame.item.SavecurRocketdesign = Guardar el diseño actual\r
+main.menu.file.saveAs = Guardar como ...\r
+BasicFrame.item.SavecurRocketdesnewfile = Guardar el diseño actual como un nuevo documento\r
+main.menu.file.print = Imprimir ...\r
+BasicFrame.item.Printpart = Imprimir un listado de componentes y un esquema de aleta\r
+main.menu.file.close = Cerrar\r
+BasicFrame.item.Closedesign = Cerrar el diseño actual\r
+main.menu.file.quit = Salir\r
+BasicFrame.item.Quitprogram = Salir del programa\r
+\r
+main.menu.edit = Edición \r
+BasicFrame.menu.Rocketedt = Mostrar el cohete\r
+main.menu.edit.undo = Deshacer\r
+main.menu.edit.undo.desc = Deshacer la operación anterior\r
+main.menu.edit.redo = Rehacer\r
+main.menu.edit.redo.desc = Rehacer la operación anterior\r
+main.menu.edit.cut = Cortar\r
+main.menu.edit.copy = Copiar\r
+main.menu.edit.paste = Pegar\r
+main.menu.edit.delete = Borrar\r
+main.menu.edit.resize = Dimensionar...\r
+main.menu.edit.resize.desc = Dimensionar las partes del diseño del cohete\r
+main.menu.edit.preferences = Preferencias\r
+main.menu.edit.preferences.desc = Configurar las preferencias de la aplicación\r
+\r
+main.menu.analyze = Analizar\r
+main.menu.analyze.desc = Análisis del cohete\r
+main.menu.analyze.componentAnalysis = Análisis de los componentes\r
+main.menu.analyze.componentAnalysis.desc = Analiza los componentes del cohete por separado\r
+main.menu.analyze.optimization = Optimización del diseño\r
+main.menu.analyze.optimization.desc = Optimización global del diseño del cohete\r
+\r
+main.menu.help = Ayuda\r
+main.menu.help.desc = Información acerca del cohete\r
+main.menu.help.tours = Visita guiada\r
+main.menu.help.tours.desc = Realzar visitas guiadas en OpenRocket\r
+main.menu.help.license = Licencia\r
+main.menu.help.license.desc = Información de la licencia de OpenRocket\r
+main.menu.help.bugReport = Informe de errores\r
+main.menu.help.bugReport.desc = Informar sobre errores encontrados en OpenRocket\r
+main.menu.help.debugLog = Registro de sucesos\r
+main.menu.help.debugLog.desc = Visualizar el registro de depuración de OpenRocket\r
+main.menu.help.about = Acerca de\r
+main.menu.help.about.desc = Detalles del Copyright de OpenRocket\r
+\r
+main.menu.debug = Recuperación\r
+main.menu.debug.whatisthismenu = ¿Que es este menú?\r
+main.menu.debug.createtestrocket = Crear una prueba de modelo\r
+\r
+! database\r
+! Translate here all material database\r
+!\r
+\r
+! Material database\r
+! BULK_MATERIAL\r
+material.acrylic = Acrílico\r
+material.aluminum = Aluminio\r
+material.balsa = Balsa\r
+material.basswood = Tilo\r
+material.birch = Abedul\r
+material.brass = Latón\r
+material.cardboard = Cartón\r
+material.carbon_fiber = Fibra de Carbono\r
+material.cork = Corcho\r
+material.depron_xps = Depron (XPS)\r
+material.fiberglass = Fibra de vidrio\r
+material.kraft_phenolic = Cartón fenólico\r
+material.maple = Arce\r
+material.paper_office = Papel (oficina)\r
+material.pine = Pino\r
+material.plywood_birch = Contrachapado\r
+material.polycarbonate_lexan = Policarbonato (Lexan)\r
+material.polystyrene = Poliestireno\r
+material.pvc = PVC\r
+material.spruce = Pícea (Abeto común)\r
+material.steel = Acero\r
+material.styrofoam_generic_eps = Porex (generico EPS)\r
+material.styrofoam_blue_foam_xps = Porex \"Foam azul\" (XPS)\r
+material.titanium = Titanio\r
+material.quantum_tubing = Quantum tubing\r
+material.blue_tube = Tubo azul (PML)\r
+!SURFACE_MATERIAL\r
+material.ripstop_nylon = Ripstop nylon\r
+material.mylar = Mylar\r
+material.polyethylene_thin = Polietileno (delgado)\r
+material.polyethylene_heavy = Polietileno (grueso)\r
+material.silk = Seda\r
+material.paper_office = Papel (oficina)\r
+material.cellophane = Celofán\r
+material.crepe_paper = Crespón de papel\r
+! LINE_MATERIAL\r
+material.thread_heavy_duty = Trenzado (Alta resistencia)\r
+material.elastic_cord_round_2_mm_1_16_in = Cordón elástico (aprox. 2mm, 1/16 in)\r
+material.elastic_cord_flat_6_mm_1_4_in = Cordón elástico plano (6mm, 1/4 in)\r
+material.elastic_cord_flat_12_mm_1_2_in = Cordón elástico plano (12mm, 1/2 in)\r
+material.elastic_cord_flat_19_mm_3_4_in = Cordón elástico plano (19mm, 3/4 in)\r
+material.elastic_cord_flat_25_mm_1_in = Cordón elástico plano (25mm, 1 in)\r
+material.braided_nylon_2_mm_1_16_in = Nylon trenzado (2 mm, 1/16 in)\r
+material.braided_nylon_3_mm_1_8_in = Nylon trenzado (3 mm, 1/8 in)\r
+material.tubular_nylon_11_mm_7_16_in = Nylon tubular (11 mm, 7/16 in)\r
+material.tubular_nylon_14_mm_9_16_in = Nylon tubular (14 mm, 9/16 in)\r
+material.tubular_nylon_25_mm_1_in = Nylon tubular (25 mm, 1 in)\r
+\r
+! ExternalComponent\r
+ExternalComponent.Rough = Rugoso\r
+ExternalComponent.Unfinished = Inacabado\r
+ExternalComponent.Regularpaint = Pintura normal\r
+ExternalComponent.Smoothpaint = Pintura fina\r
+ExternalComponent.Polished = Pulido\r
+\r
+! LineStyle\r
+LineStyle.Solid = Sólido\r
+LineStyle.Dashed = Discontinuo\r
+LineStyle.Dotted = Punteado\r
+LineStyle.Dash-dotted = Discontinuo con puntos\r
+LineStyle.Defaultstyle = Estilo por defecto\r
+\r
+! Shape\r
+Shape.Conical = Cónico\r
+Shape.Conical.desc1 = Una ojiva cónica de perfil triangular\r
+Shape.Conical.desc2 = Transición cónica de lados rectos\r
+Shape.Ogive = Ojival\r
+Shape.Ogive.desc1 = Ojiva con perfil de arco de circunferencia. Un valor de forma igual a 1 produce una <b>Ojiva tangente</b>, mientras que un valor inferior a 1 produce una <b>Ojiva secante</b> con un perfil más afilado.\r
+Shape.Ogive.desc2 = Transición con perfil de arco de circunferencia. Un valor de forma igual a 1 produce una <b>Transición tangente</b>, mientras que un valor inferior a 1 produce una <b>Transición secante</b> con un perfil más afilado.\r
+Shape.Ellipsoid = Elíptica\r
+Shape.Ellipsoid.desc1 = Ojiva con perfil de media elipse. Por defecto, una elipse de <i>longitud</i> igual al triple de su <i>diámetro</i>.\r
+Shape.Ellipsoid.desc2 = Transición con perfil de media elipse. Por defecto, una elipse de <i>longitud</i> igual al triple de su <i>diámetro</i>.\r
+Shape.Powerseries = Serie potencial \r
+Shape.Powerseries.desc1 = Ojiva cuyo perfil es una curva obtenida a partir de una función potencial f(<i>x</i>)<sup><i>k</i></sup>. Un valor de forma k=0.5 produce una ojiva con perfil de parábola, para k=0.75 se produce una ojiva con <b>perfil potencial</b>, y para k=1 se produce una ojiva con perfil recto u <b>Ojiva cónica</b>.\r
+Shape.Powerseries.desc2 = Transición cuyo perfil es una curva obtenida a partir de una función potencial de <i>Radio</i>&nbsp; =;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>L</i>)<sup><i>k</i></sup> donde <i>k</i> es el parámetro de forma.  Para <i>k</i>=0.5 la transición es <b>\u00BD-potencial</b> o <b>parabólica</b>, para <i>k</i>=0.75 a <b>\u00BE-potencia</b>, y para <i>k</i>=1 <b>cónica</b>.\r
+Shape.Parabolicseries = Serie parabólica\r
+Shape.Parabolicseries.desc1 = Ojiva con perfil de arco de parábola. Un valor de forma igual a 1 produce una <b>Ojiva tangente</b>, un valor igual a 0.75 produce una <b>parábola de 3/4</b>, un valor igual a 0.5 produce una <b>parábola de 1/2</b>, y un valor igual a 0 produce un perfil recto u <b>Ojiva cónica</b>.\r
+Shape.Parabolicseries.desc2 = Una transición de serie parabólica tiene un perfil de parábola. El valor de forma defien el tipo de parábola a utilizar. Un valor de forma de 1.0 produce una parábola completa que es tangente al cuerpo tubular en el extremo trasero, un valor de 0.75 produce una <b>parábola de 3/4</b>, un valor de 0.5 produce una <b>parábola de 1/2</b>, y un valor de 0 produce una transición cónica.\r
+Shape.Haackseries = Haack series\r
+Shape.Haackseries.desc1 = Ojiva con perfil de mínimo arrastre aerodinámico recomendado para vuelos supersónicos. Un valor de forma igual a 0 produce una <b>Ojiva LD Haack</b> u <b>Ojiva Von Karman</b> que minimiza el arrastre aerodinámico para una determinada longitud y diámetro de la base, mientras que un valor igual a 0.333 produce una <b>Ojiva LV-Haack</b> que minimiza el arrastre aerodinámico para una determinada longitud y volumen de la ojiva.\r
+Shape.Haackseries.desc2 = Las transiciones Haack series están diseñadas para minimizar el arrastre aerodinámico. Estas transiciones poseen sus equivalentes, pero no necesariamente producen un arrastre óptimo.  Un valor de forma 0 produce una transición <b>LD-Haack</b> o <b>Von Karman</b>, mientras que un valor de 0.333 produce una forma <b>LV-Haack</b>.            \r
+\r
+\r
+! RocketComponent\r
+RocketComponent.Position.TOP = Parte superior del componente\r
+RocketComponent.Position.MIDDLE = Parte media del componente\r
+RocketComponent.Position.BOTTOM = Extremo inferior del componente\r
+RocketComponent.Position.AFTER = Después del componente\r
+RocketComponent.Position.ABSOLUTE = Extremo de la ojiva\r
+\r
+! LaunchLug\r
+LaunchLug.Launchlug = Soporte para Guía\r
+! NoseCone\r
+NoseCone.NoseCone = Ojiva\r
+! Transition\r
+Transition.Transition = Transición\r
+!Stage\r
+Stage.Stage = Etapa\r
+\r
+Stage.SeparationEvent.UPPER_IGNITION = Ignición del motor de la etapa superior\r
+Stage.SeparationEvent.IGNITION = Ignición del motor de la etapa actual\r
+Stage.SeparationEvent.BURNOUT = Apagado del motor de la etapa actual\r
+Stage.SeparationEvent.EJECTION = Carga de eyección de la etapa actual\r
+Stage.SeparationEvent.LAUNCH = Lanzamiento\r
+Stage.SeparationEvent.NEVER = Nunca\r
+\r
+! BodyTube\r
+BodyTube.BodyTube = Cuerpo tubular\r
+! TubeCoupler\r
+TubeCoupler.TubeCoupler = Acoplador\r
+!InnerTube\r
+InnerTube.InnerTube = Tubo interior\r
+! TrapezoidFinSet\r
+TrapezoidFinSet.TrapezoidFinSet = Aleta trapezoidal\r
+! FreeformFinSet\r
+FreeformFinSet.FreeformFinSet = Aleta de forma libre\r
+!MassComponent\r
+MassComponent.MassComponent = Masa\r
+! Parachute\r
+Parachute.Parachute = Paracaídas\r
+! ShockCord\r
+ShockCord.ShockCord = Tirante de suspensión\r
+! Bulkhead\r
+Bulkhead.Bulkhead = Disco de enganche\r
+\r
+!Rocket\r
+Rocket.motorCount.Nomotor = [Sin motores]\r
+Rocket.compname.Rocket = Cohete\r
+\r
+!MotorMount\r
+MotorMount.IgnitionEvent.AUTOMATIC = Automático (Lanzamiento o carga de eyección)\r
+MotorMount.IgnitionEvent.LAUNCH = Lanzamiento\r
+MotorMount.IgnitionEvent.EJECTION_CHARGE = Primera carga de eyección de la etapa previa\r
+MotorMount.IgnitionEvent.BURNOUT = Primer encendido de la etapa previa\r
+MotorMount.IgnitionEvent.NEVER = Nunca\r
+\r
+!ComponentIcons \r
+ComponentIcons.Nosecone = Ojiva\r
+ComponentIcons.Bodytube = Cuerpo tubular\r
+ComponentIcons.Transition = Transición\r
+ComponentIcons.Trapezoidalfinset = Aleta trapezoidal\r
+ComponentIcons.Ellipticalfinset = Aleta elíptica\r
+ComponentIcons.Freeformfinset = Aleta de forma libre\r
+ComponentIcons.Launchlug = Tubo para Guía\r
+ComponentIcons.Innertube = Tubo interior\r
+ComponentIcons.Tubecoupler = Tubo de acoplamiento\r
+ComponentIcons.Centeringring = Anillo de centrado\r
+ComponentIcons.Bulkhead = Disco de enganche\r
+ComponentIcons.Engineblock = Retén de motor\r
+ComponentIcons.Parachute = Paracaídas\r
+ComponentIcons.Streamer = Banderola\r
+ComponentIcons.Shockcord = Tirante de suspensión\r
+ComponentIcons.Masscomponent = Componente masa\r
+ComponentIcons.disabled = (Deshabilitado)\r
+\r
+! StageAction\r
+StageAction.Stage = Etapa\r
+\r
+! RecoveryDevice\r
+RecoveryDevice.DeployEvent.LAUNCH = Lanzamiento (NN segundos)\r
+RecoveryDevice.DeployEvent.EJECTION = Primera carga de eyección de esta etapa\r
+RecoveryDevice.DeployEvent.APOGEE = Apogeo\r
+RecoveryDevice.DeployEvent.ALTITUDE = Altura específica durante el descenso\r
+RecoveryDevice.DeployEvent.CURRENT_STAGE_SEPARATION = Separación de etapa actual\r
+RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION = Separación de etapa inferior\r
+RecoveryDevice.DeployEvent.NEVER = Nunca\r
+\r
+! FlightEvent\r
+FlightEvent.Type.LAUNCH = Lanzamiento\r
+FlightEvent.Type.IGNITION = Encendido del motor\r
+FlightEvent.Type.LIFTOFF = Despegue\r
+FlightEvent.Type.LAUNCHROD = Abandono de la Guía de lanzamiento\r
+FlightEvent.Type.BURNOUT = Apagado del motor\r
+FlightEvent.Type.EJECTION_CHARGE = Carga de eyección\r
+FlightEvent.Type.STAGE_SEPARATION = Separación de etapa\r
+FlightEvent.Type.APOGEE = Apogeo\r
+FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT = Despliegue del sistema de recuperación\r
+FlightEvent.Type.GROUND_HIT = Contacto con el suelo\r
+FlightEvent.Type.SIMULATION_END = Fin de la simulación\r
+FlightEvent.Type.ALTITUDE = Altitud\r
+\r
+! ThrustCurveMotorColumns\r
+TCurveMotorCol.MANUFACTURER = Fabricante\r
+TCurveMotorCol.DESIGNATION = Designación\r
+TCurveMotorCol.TYPE = Tipo\r
+TCurveMotorCol.DIAMETER = Diámetro\r
+TCurveMotorCol.LENGTH = Longitud\r
+\r
+! RocketInfo\r
+RocketInfo.lengthLine.Length = Longitud: \r
+RocketInfo.lengthLine.maxdiameter = , Diámetro máximo: \r
+RocketInfo.massText1 = Masa con motores: \r
+RocketInfo.massText2 = Masa sin motores: \r
+RocketInfo.at = a M=\r
+RocketInfo.cgText = CG:\r
+RocketInfo.cpText = CP:\r
+RocketInfo.stabText = Estabilidad: \r
+RocketInfo.Warning = Peligro, cohete inestable.\r
+RocketInfo.Calculating = Calculando...\r
+RocketInfo.Apogee = Apogeo:\r
+RocketInfo.Maxvelocity = Velocidad Máx.: \r
+RocketInfo.Maxacceleration = Aceleración Máx.: \r
+RocketInfo.apogeeValue = N/A\r
+RocketInfo.Mach = , (Número Mach: \r
+RocketInfo.velocityValue = N/A\r
+RocketInfo.accelerationValue = N/A\r
+\r
+! FinSet\r
+FinSet.CrossSection.SQUARE = Cuadrado\r
+FinSet.CrossSection.ROUNDED = Redondeado\r
+FinSet.CrossSection.AIRFOIL = Aerodinámico\r
+FinSet.TabRelativePosition.FRONT = Borde principal del extremo de anclaje\r
+FinSet.TabRelativePosition.CENTER = Borde principal del anclaje\r
+FinSet.TabRelativePosition.END = Borde principal de tracción\r
+\r
+! FlightDataType\r
+FlightDataType.TYPE_TIME = Tiempo\r
+FlightDataType.TYPE_ALTITUDE = Altitud\r
+FlightDataType.TYPE_VELOCITY_Z = Velocidad vertical\r
+FlightDataType.TYPE_ACCELERATION_Z = Aceleración vertical\r
+FlightDataType.TYPE_VELOCITY_TOTAL = Velocidad total\r
+FlightDataType.TYPE_ACCELERATION_TOTAL = Aceleración total\r
+FlightDataType.TYPE_POSITION_X = Posición contra el viento\r
+FlightDataType.TYPE_POSITION_Y = Posición a favor del viento\r
+FlightDataType.TYPE_POSITION_XY = Distancia lateral\r
+FlightDataType.TYPE_POSITION_DIRECTION = Dirección lateral\r
+FlightDataType.TYPE_VELOCITY_XY = Velocidad lateral\r
+FlightDataType.TYPE_ACCELERATION_XY = Aceleración lateral\r
+FlightDataType.TYPE_AOA = Ángulo de ataque\r
+FlightDataType.TYPE_ROLL_RATE = Relación de rotación\r
+FlightDataType.TYPE_PITCH_RATE = Relación de pico\r
+FlightDataType.TYPE_YAW_RATE = Relación de desvío\r
+FlightDataType.TYPE_MASS = Masa\r
+FlightDataType.TYPE_LONGITUDINAL_INERTIA = Momento de inercia longitudinal\r
+FlightDataType.TYPE_ROTATIONAL_INERTIA = Momento de inercia rotacional\r
+FlightDataType.TYPE_CP_LOCATION = Situación del CP\r
+FlightDataType.TYPE_CG_LOCATION = Situación del CG\r
+FlightDataType.TYPE_STABILITY = Calibración del margen de estabilidad\r
+FlightDataType.TYPE_MACH_NUMBER = Número Mach\r
+FlightDataType.TYPE_REYNOLDS_NUMBER = Número de Reynolds\r
+FlightDataType.TYPE_THRUST_FORCE = Empuje\r
+FlightDataType.TYPE_DRAG_FORCE = Fuerza de rozamiento\r
+FlightDataType.TYPE_DRAG_COEFF = Coeficiente de rozamiento\r
+FlightDataType.TYPE_AXIAL_DRAG_COEFF = Coeficiente de rozamiento axial\r
+FlightDataType.TYPE_FRICTION_DRAG_COEFF = Coeficiente de rozamiento por fricción\r
+FlightDataType.TYPE_PRESSURE_DRAG_COEFF = Presión del coeficiente de rozamiento\r
+FlightDataType.TYPE_BASE_DRAG_COEFF = Coeficiente de rozamiento base\r
+FlightDataType.TYPE_NORMAL_FORCE_COEFF = Coeficiente de rozamiento normal\r
+FlightDataType.TYPE_PITCH_MOMENT_COEFF = Pico del coeficiente de rozamiento\r
+FlightDataType.TYPE_YAW_MOMENT_COEFF = Coeficiente de rozamiento de desviación\r
+FlightDataType.TYPE_SIDE_FORCE_COEFF = Coeficiente de fuerza lateral\r
+FlightDataType.TYPE_ROLL_MOMENT_COEFF = Coeficiente del momento de rotación\r
+FlightDataType.TYPE_ROLL_FORCING_COEFF = Fuerza del coeficiente de rotación\r
+FlightDataType.TYPE_ROLL_DAMPING_COEFF = Disminución del coeficiente de rotación\r
+FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF = Disminución del coeficiente de pico\r
+FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF = Disminución del coeficiente de desviación\r
+FlightDataType.TYPE_REFERENCE_LENGTH = Longitud de referencia \r
+FlightDataType.TYPE_REFERENCE_AREA = Área de referencia\r
+FlightDataType.TYPE_ORIENTATION_THETA = Orientación vertical (zenit)\r
+FlightDataType.TYPE_ORIENTATION_PHI = Orientación lateral (azimut)\r
+FlightDataType.TYPE_WIND_VELOCITY = Velocidad del viento\r
+FlightDataType.TYPE_AIR_TEMPERATURE = Temperatura del aire\r
+FlightDataType.TYPE_AIR_PRESSURE = Presión del aire\r
+FlightDataType.TYPE_SPEED_OF_SOUND = Velocidad del sonido\r
+FlightDataType.TYPE_TIME_STEP = Simulación del tiempo de etapa\r
+FlightDataType.TYPE_COMPUTATION_TIME = Cálculo del tiempo\r
+FlightDataType.TYPE_LATITUDE = Latitud\r
+FlightDataType.TYPE_LONGITUDE = Longitud\r
+FlightDataType.TYPE_CORIOLIS_ACCELERATION = Aceleración Coriolis\r
+\r
+! PlotConfiguration\r
+PlotConfiguration.Verticalmotion = Movimiento vertical vs. Tiempo\r
+PlotConfiguration.Totalmotion = Movimiento total vs. Tiempo\r
+PlotConfiguration.Flightside = Perfil lateral de vuelo\r
+PlotConfiguration.Stability = Estabilidad vs. Tiempo\r
+PlotConfiguration.Dragcoef = Coeficiente de rozamiento vs. Número Mach\r
+PlotConfiguration.Rollcharacteristics = Características de rotación\r
+PlotConfiguration.Angleofattack = Ángulo de orientación y ataque vs. Tiempo\r
+PlotConfiguration.Simulationtime = Simulación del tiempo de etapa y cálculo del tiempo\r
+\r
+! Warning\r
+Warning.LargeAOA.str1 = Evaluación de la amplitud del ángulo de ataque.\r
+Warning.LargeAOA.str2 = La amplitud del ángulo de ataque es excesiva (\r
+Warning.DISCONTINUITY = Discontinuidad en el diámetro del fuselaje.\r
+Warning.THICK_FIN = Las aletas gruesas no están correctamente modeladas.\r
+Warning.JAGGED_EDGED_FIN = El perfil afilado de las aletas puede ser inexacto.\r
+Warning.LISTENERS_AFFECTED = Las Extensiones se ejecutaron con la simulación del vuelo\r
+Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING = Sistema de recuperación abierto en fase de impulso, mientras el motor aún empujaba\r
+Warning.FILE_INVALID_PARAMETER = Parámetro encontrado no válido. Ignorado.\r
+\r
+\r
+! Scale dialog\r
+ScaleDialog.lbl.scaleRocket = El Cohete entero\r
+ScaleDialog.lbl.scaleSubselection = Todos los componentes seleccionados\r
+ScaleDialog.lbl.scaleSelection = Sólo el componente seleccionado\r
+ScaleDialog.title = Dimensión del diseño\r
+ScaleDialog.lbl.scale = Dimensión:\r
+ScaleDialog.lbl.scale.ttip = Indique si desea dimensionar el diseño completo o sólo los componentes seleccionados\r
+ScaleDialog.lbl.scaling = Dimensión a aplicar:\r
+ScaleDialog.lbl.scaling.ttip = Tamaño resultante, valores por encima del 100% aumentan el tamaño, y valores por debajo de 100% reduce el diseño.\r
+! The scaleFrom/scaleTo pair creates a phrase "Scale from [...] to [...]"\r
+ScaleDialog.lbl.scaleFrom = Dimensionar desde\r
+ScaleDialog.lbl.scaleTo = hasta\r
+ScaleDialog.lbl.scaleFromTo.ttip = Definir la dimensión en base a una longitud conocida u original.\r
+ScaleDialog.checkbox.scaleMass = Actualizar valores de Masa especificada\r
+ScaleDialog.checkbox.scaleMass.ttip = Dimensionar la Masa del componente y recalcular los valores de Masa por el cubo del factor de la escala\r
+ScaleDialog.button.scale = Dimensionar\r
+ScaleDialog.undo.scaleRocket = Dimensionar el cohete\r
+ScaleDialog.undo.scaleComponent = Dimensionar el componente\r
+ScaleDialog.undo.scaleComponents = Dimensionar los componentes\r
+\r
+!icons\r
+Icons.Undo = Deshacer\r
+Icons.Redo = Rehacer\r
+\r
+OpenRocketPrintable.Partsdetail = Detalle de las partes\r
+OpenRocketPrintable.Fintemplates = Plantilla de las aletas\r
+OpenRocketPrintable.Transitiontemplates = Plantillas de las transiciones\r
+OpenRocketPrintable.Noseconetemplates = Plantilla de la ojiva\r
+OpenRocketPrintable.Finmarkingguide = Guía marcas de aleta\r
+OpenRocketPrintable.DesignReport = Informe del Diseño\r
+\r
+OpenRocketDocument.Redo = Rehacer\r
+OpenRocketDocument.Undo = Deshacer\r
+\r
+!EllipticalFinSet\r
+EllipticalFinSet.Ellipticalfinset = Grupo de aletas elípticas\r
+\r
+! Optimization\r
+\r
+! Modifiers\r
+\r
+optimization.modifier.nosecone.length = Longitud de la ojiva\r
+optimization.modifier.nosecone.length.desc = Optimizar la longitud de la ojiva.\r
+optimization.modifier.nosecone.diameter = Diámetro de la ojiva optimization.modifier.nosecone.diameter.desc = Optimizar el diámetro de la base de la ojiva.\r
+optimization.modifier.nosecone.diameter.desc = Optimizar el diámetro de la base de la ojiva.\r
+optimization.modifier.nosecone.thickness = Grosor de la ojiva\r
+optimization.modifier.nosecone.thickness.desc = Optimizar el grosor de la pared de la ojiva.\r
+optimization.modifier.nosecone.shapeparameter = Parámetro de forma\r
+optimization.modifier.nosecone.shapeparameter.desc = Optimiza el parámetro de forma de la ojiva.\r
+               \r
+optimization.modifier.transition.length = Longitud\r
+optimization.modifier.transition.length.desc = Optimiza la longitud de la transición.\r
+optimization.modifier.transition.forediameter = Diámetro delantero\r
+optimization.modifier.transition.forediameter.desc = Optimiza el diámetro delantero de la transición.\r
+optimization.modifier.transition.aftdiameter = Diámetro trasero\r
+optimization.modifier.transition.aftdiameter.desc = Optimiza el diámetro trasero de la transición.\r
+optimization.modifier.transition.thickness = Grosor\r
+optimization.modifier.transition.thickness.desc = Optimiza el grosor de la pared de la transición.\r
+optimization.modifier.transition.shapeparameter = Parámetro de forma\r
+optimization.modifier.transition.shapeparameter.desc = Optimizar el parámetro de forma de la transición.\r
+\r
+optimization.modifier.bodytube.length = Longitud\r
+optimization.modifier.bodytube.length.desc = Optimizar la longitud del cuerpo.\r
+optimization.modifier.bodytube.outerDiameter = Diámetro exterior\r
+optimization.modifier.bodytube.outerDiameter.desc = Optimizar el diámetro exterior del cuerpo manteniendo el grosor de la pared.\r
+optimization.modifier.bodytube.thickness = Grosor\r
+optimization.modifier.bodytube.thickness.desc = Optimizar el grosor de la pared del cuerpo.\r
+\r
+optimization.modifier.trapezoidfinset.rootChord = Longitud línea base\r
+optimization.modifier.trapezoidfinset.rootChord.desc = Optiminizar la longitud de la línea base de las aletas (longitud de la aleta sobre la superficie del cuerpo).\r
+optimization.modifier.trapezoidfinset.tipChord = Longitud borde superior\r
+optimization.modifier.trapezoidfinset.tipChord.desc = Optimizar la longitud del borde superior de las aletas (longitd del borde exterior de la aleta).\r
+optimization.modifier.trapezoidfinset.sweep = Desplazamiento borde superior\r
+optimization.modifier.trapezoidfinset.sweep.desc = Optimiza el desplazamiento del borde superior de las aletas (desplazamiento del borde superior de la aleta respecto del extremo delantero de la línea base).\r
+optimization.modifier.trapezoidfinset.height = Altura\r
+optimization.modifier.trapezoidfinset.height.desc = Optimizar la altura de las aletas (semi-spam).\r
+\r
+optimization.modifier.ellipticalfinset.length = Longitud línea base\r
+optimization.modifier.ellipticalfinset.length.desc = Optiminizar la longitud de la línea base de las aletas\r
+optimization.modifier.ellipticalfinset.height = Altura\r
+optimization.modifier.ellipticalfinset.height.desc = Optimizar la altura de las aletas (semi-spam).\r
+\r
+optimization.modifier.finset.cant = Angulo de ataque\r
+optimization.modifier.finset.cant.desc = Optimiza el ángulo de ataque de las aletas.\r
+optimization.modifier.finset.position = Posición\r
+optimization.modifier.finset.position.desc = Optimiza la posición de las aletas a lo largo del cuerpo del cohete.\r
+\r
+optimization.modifier.launchlug.length = Longitud\r
+optimization.modifier.launchlug.length.desc = Optimiza la longitud del tubo para la Guía.\r
+optimization.modifier.launchlug.outerDiameter = Diámetro exterior\r
+optimization.modifier.launchlug.outerDiameter.desc = Optimiza el diámetro exterior del tubo para la Guía.\r
+optimization.modifier.launchlug.thickness = Grosor\r
+optimization.modifier.launchlug.thickness.desc = Optimiza el grosor del tubo para la Guía manteniendo el diámetro exterior.\r
+optimization.modifier.launchlug.position = Posición\r
+optimization.modifier.launchlug.position.desc = Optimiza la posición del soporte para la guía a lo largo del cuerpo del cohete.\r
+\r
+\r
+optimization.modifier.internalcomponent.position = Posición\r
+optimization.modifier.internalcomponent.position.desc = Optimiza la posición del componente interno respecto del componente que lo contiene.\r
+\r
+optimization.modifier.masscomponent.mass = Masa\r
+optimization.modifier.masscomponent.mass.desc = Optimiza la masa del componente Masa.\r
+\r
+optimization.modifier.parachute.diameter = Diámetro\r
+optimization.modifier.parachute.diameter.desc = Optimiza el diámetro del pabellón del paracaídas.\r
+optimization.modifier.parachute.coefficient = Coeficiente de rozamiento\r
+optimization.modifier.parachute.coefficient.desc = Optimiza el coeficiente de rozamiento del paracaídas. Un paracaídas típico posee un coeficiente de 0.8.\r
+\r
+optimization.modifier.streamer.length = Longitud\r
+optimization.modifier.streamer.length.desc = Optimiza la longitud de la banderola.\r
+optimization.modifier.streamer.width = Anchura\r
+optimization.modifier.streamer.width.desc = Optimiza la anchura de la banderola.\r
+optimization.modifier.streamer.aspectRatio = Relación de aspecto\r
+optimization.modifier.streamer.aspectRatio.desc = Optimiza la relación de aspecto de la banderola (longitud/anchura). Usted NO debe seleccionar una longitud o anchura de la banderola al mismo tiempo que una relación de aspecto.\r
+optimization.modifier.streamer.coefficient = Coeficiente de rozamiento\r
+optimization.modifier.streamer.coefficient.desc = Optimiza el coeficiente de rozamiento de la banderola.\r
+\r
+optimization.modifier.recoverydevice.deployDelay = Retardo de eyección\r
+optimization.modifier.recoverydevice.deployDelay.desc = Optimiza el tiempo de retardo de eyección del sistema de recuperación.\r
+optimization.modifier.recoverydevice.deployAltitude = Altitud de eyección\r
+optimization.modifier.recoverydevice.deployAltitude.desc = Optimiza la altitud de la eyección del sistema de recuperación.\r
+\r
+optimization.modifier.rocketcomponent.overrideMass = Masa especificada\r
+optimization.modifier.rocketcomponent.overrideMass.desc = Optimiza la Masa especificada del componente.\r
+optimization.modifier.rocketcomponent.overrideCG = CG especificado\r
+optimization.modifier.rocketcomponent.overrideCG.desc = Optimiza la localización del Centro de Gravedad especificado en el componente.\r
+\r
+optimization.modifier.motormount.overhang = Sobresalida del motor\r
+optimization.modifier.motormount.overhang.desc = Optimiza la sobresalida del motor hacia el exterior.\r
+optimization.modifier.motormount.delay = Retardo de ignición\r
+optimization.modifier.motormount.delay.desc = Optimiza el retardo de la ingnición del motor.\r
+\r
+\r
+\r
+\r
+! General rocket design optimization dialog\r
+\r
+GeneralOptimizationDialog.title = Optimización del cohete\r
+GeneralOptimizationDialog.goal.maximize = Maximizar el valor\r
+GeneralOptimizationDialog.goal.minimize = Minimizar el valor\r
+GeneralOptimizationDialog.goal.seek = Buscar el valor de\r
+GeneralOptimizationDialog.btn.start = Iniciar optimización\r
+GeneralOptimizationDialog.btn.stop = Detener optimización\r
+GeneralOptimizationDialog.lbl.paramsToOptimize = Parámetros de optimización:\r
+GeneralOptimizationDialog.btn.add = Agregar\r
+GeneralOptimizationDialog.btn.add.ttip = Agregar el parámetro de optimizacaión\r
+GeneralOptimizationDialog.btn.remove = Eliminar\r
+GeneralOptimizationDialog.btn.remove.ttip = Eliminar el parámetro seleccionado de la optimización. \r
+GeneralOptimizationDialog.btn.removeAll = Eliminar todo\r
+GeneralOptimizationDialog.btn.removeAll.ttip = Eliminar todos los parámetros de optimización.\r
+GeneralOptimizationDialog.lbl.availableParams = Parámetros disponibles:\r
+GeneralOptimizationDialog.lbl.optimizationOpts = Opciones de optimización\r
+GeneralOptimizationDialog.lbl.optimizeSim = Optimizar simulación:\r
+GeneralOptimizationDialog.lbl.optimizeSim.ttip = Seleccionar la simulación a optimizar.\r
+GeneralOptimizationDialog.lbl.optimizeValue = Valor optimizado:\r
+GeneralOptimizationDialog.lbl.optimizeValue.ttip = Seleccionar el valor a optimizar.\r
+GeneralOptimizationDialog.lbl.optimizeGoal = Objetivo de optimización:\r
+GeneralOptimizationDialog.lbl.optimizeGoal.ttip = Seleccionar el objetivo de la optimización.\r
+GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip = Buscar valor personalizado\r
+GeneralOptimizationDialog.lbl.requireStability = Estabilidad requerida\r
+GeneralOptimizationDialog.lbl.requireMinStability = Mínima estabilidad:\r
+GeneralOptimizationDialog.lbl.requireMinStability.ttip = Requerir un margen mínimo de estabilidad para el diseño.\r
+GeneralOptimizationDialog.lbl.requireMaxStability = Máxima estabilidad:\r
+GeneralOptimizationDialog.lbl.requireMaxStability.ttip = Requerir un margen máximo de estabilidad para el diseño.\r
+GeneralOptimizationDialog.status.bestValue = El mejor valor:\r
+GeneralOptimizationDialog.status.bestValue.ttip = El mejor valor de optimización encontrado.\r
+GeneralOptimizationDialog.status.stepCount = Número de pasos:\r
+GeneralOptimizationDialog.status.stepCount.ttip = Número de pasos que deben realizarse para la optimización.\r
+GeneralOptimizationDialog.status.evalCount = Evaluaciones:\r
+GeneralOptimizationDialog.status.evalCount.ttip = Número total de evaluaciones (simulaciones) que deben realizarse.\r
+GeneralOptimizationDialog.status.stepSize = Tamaño del paso:\r
+GeneralOptimizationDialog.status.stepSize.ttip = Tamaño actual del paso de optimización (respecto al rango de parámetros de optimización).\r
+GeneralOptimizationDialog.btn.plotPath = Gráfica del proceso\r
+GeneralOptimizationDialog.btn.plotPath.ttip = Gráfica del proceso de optimización (sólo para 1 o 2 dimensiones).\r
+GeneralOptimizationDialog.btn.save = Guardar resultados\r
+GeneralOptimizationDialog.btn.save.ttip = Guardar los resultados de las evaluaciones (simulaciones) en un archivo CSV.\r
+GeneralOptimizationDialog.btn.apply = Aplicar optimización\r
+GeneralOptimizationDialog.btn.apply.ttip = Aplicar los resultados de la optimización al diseño del cohete.\r
+GeneralOptimizationDialog.btn.reset = Reiniciar\r
+GeneralOptimizationDialog.btn.reset.ttip = Reiniciar el diseño actual del cohete con el diseño optimizado.\r
+GeneralOptimizationDialog.btn.close = Cerrar\r
+GeneralOptimizationDialog.btn.close.ttip = Cerrar el cuadro de diálogo sin modificar el diseño actual del cohete.\r
+GeneralOptimizationDialog.error.selectParams.text = Primero seleccione algunos parámetros a optimizar de entre todos los parámetros disponibles.\r
+GeneralOptimizationDialog.error.selectParams.title = Seleccionar los parámetros de optimización\r
+GeneralOptimizationDialog.error.optimizationFailure.text = Falló la ejecución de la optimización:\r
+GeneralOptimizationDialog.error.optimizationFailure.title = Fallo de la optimización\r
+GeneralOptimizationDialog.undoText = Aplicar la optimización\r
+GeneralOptimizationDialog.basicSimulationName = Simulación básica\r
+GeneralOptimizationDialog.noSimulationName = Sin simulación\r
+GeneralOptimizationDialog.table.col.parameter = Parámetro\r
+GeneralOptimizationDialog.table.col.current = Actual\r
+GeneralOptimizationDialog.table.col.min = Mínimo\r
+GeneralOptimizationDialog.table.col.max = Máximo\r
+GeneralOptimizationDialog.export.header = Incluir línea de cabecera\r
+GeneralOptimizationDialog.export.header.ttip = Incluir una línea de cabecera en la que se indican las descripciones.\r
+GeneralOptimizationDialog.export.stability = Estabilidad\r
+\r
+\r
+! Dialog for plotting optimization results\r
+OptimizationPlotDialog.title = Resultados de la optimización\r
+OptimizationPlotDialog.lbl.zoomInstructions = Click y arrastrar abajo+derecha para acercar Zoom, arriba+izquierda para alejar Zoom\r
+OptimizationPlotDialog.plot1d.title = Resultado de la optimización\r
+OptimizationPlotDialog.plot1d.series = Resultado de la optimización\r
+OptimizationPlotDialog.plot2d.title = Trazabilidad de la optimización\r
+OptimizationPlotDialog.plot2d.path = Trazabilidad de la optimización\r
+OptimizationPlotDialog.plot2d.evals = Evaluaciones\r
+OptimizationPlotDialog.plot.ttip.stability = Estabilidad:\r
+OptimizationPlotDialog.plot.label.optimum = Óptimo\r
+\r
+! Optimization parameters\r
+MaximumAltitudeParameter.name = Altitud en apogeo\r
+MaximumVelocityParameter.name = Velocidad máxima\r
+MaximumAccelerationParameter.name = Aceleración máxima\r
+StabilityParameter.name = Estabilidad\r
+GroundHitVelocityParameter.name = Velocidad de aterrizaje\r
+LandingDistanceParameter.name = Distancia de aterrizaje\r
+TotalFlightTimeParameter.name = Tiempo total de vuelo\r
+DeploymentVelocityParameter.name = Velocidad durante la eyección\r
+\r
+\r
+! Compass directions drawn on a compass rose.\r
+CompassRose.lbl.north = N\r
+CompassRose.lbl.east  = E\r
+CompassRose.lbl.south = S\r
+CompassRose.lbl.west  = O\r
+\r
+! Compass directions with subdirections.  These might not be localized even if the directions on the compass rose are.\r
+CompassSelectionButton.lbl.N = N\r
+CompassSelectionButton.lbl.NE = NE\r
+CompassSelectionButton.lbl.E = E\r
+CompassSelectionButton.lbl.SE = SE\r
+CompassSelectionButton.lbl.S = S\r
+CompassSelectionButton.lbl.SW = SO\r
+CompassSelectionButton.lbl.W = O\r
+CompassSelectionButton.lbl.NW = NO\r
+\r
+\r
+SlideShowDialog.btn.next = Siguiente\r
+SlideShowDialog.btn.prev = Anterior\r
+\r
+SlideShowLinkListener.error.title = Visita guiada no encontrada\r
+SlideShowLinkListener.error.msg = Lo sentimos, la Visita seleccionada aún no se ha redactado.\r
+\r
+GuidedTourSelectionDialog.title = Visita guiada\r
+GuidedTourSelectionDialog.lbl.selectTour = Seleccione un tema:\r
+GuidedTourSelectionDialog.lbl.description = Descripción del tema:\r
+GuidedTourSelectionDialog.lbl.length = Número de diapositivas:\r
+GuidedTourSelectionDialog.btn.start = ¡Empezar el Tour!\r
+\r
+\r
+! Custom Fin BMP Importer\r
+CustomFinImport.button.label = Importar un BMP\r
+CustomFinImport.filter = Archivos Mapa de Bits (*.bmp)\r
+CustomFinImport.badFinImage = Imagen de aleta no válida. Debe ser una imagen en blanco y negro (negro para la aleta), sin que los bordes toquen los lados excepto la parte inferior de la imagen que debe ser la línea base de la aleta.\r
+CustomFinImport.errorLoadingFile = Error al cargar el archivo: \r
+CustomFinImport.errorParsingFile = Error al analizar la imagen de la aleta: \r
+CustomFinImport.undo = Importar juego de aletas de Forma libre\r
+CustomFinImport.error.title = Error al cargar el perfil de la aleta\r
+CustomFinImport.error.badimage = No se pudo deducir la forma de la aleta de la imagen.\r
+CustomFinImport.description = La imagen será convertida internamente en una imagen en blanco y negro (negro para la aleta), por tanto asegurese de que utiliza un color oscuro sólidopara la aleta, y un color blanco y claro para el fondo. La base de la aleta debe estar tocando el borde inferior de la imagen.\r
+\r
+\r
+\r
+PresetModel.lbl.select = Prefabricado:\r
+PresetModel.lbl.database = Desde la Base de Datos...\r
+\r
+\r
+! Component Preset Chooser Dialog\r
+ComponentPresetChooserDialog.title = Seleccionar un prefabricado\r
+ComponentPresetChooserDialog.filter.label = Filtro:\r
+ComponentPresetChooserDialog.checkbox.filterAftDiameter = Ajustado al diámetro trasero\r
+ComponentPresetChooserDialog.checkbox.filterForeDiameter = Ajustado al diámetro delantero\r
+ComponentPresetChooserDialog.menu.sortAsc = Orden ascendente\r
+ComponentPresetChooserDialog.menu.sortDesc = Orden descendente\r
+ComponentPresetChooserDialog.menu.units = Unidades\r
+ComponentPresetChooserDialog.checkbox.showAllCompatible = Mostrar todos los compatibles\r
+table.column.Manufacturer = Fabricante\r
+table.column.PartNo = Cód. Referencia\r
+table.column.OuterDiameter = Diámetro externo\r
+table.column.InnerDiameter = Diámetro interno\r
+table.column.Length = Longitud\r
+table.column.Favorite = Favorito\r
+table.column.ShoulderLength = Longitud del acople\r
+table.column.ShoulderDiameter = Diámetro del acople\r
+table.column.ForeShoulderLength = Longitud del acople delantero\r
+table.column.ForeShoulderDiameter = Diámetro del acople delantero\r
+table.column.ForeOuterDiameter = Diámetro exterior del acople delantero\r
+table.column.Shape = Forma\r
+table.column.Material = Material\r
+table.column.Finish = Acabado\r
+table.column.Thickness = Grosor\r
+table.column.Filled = Relleno\r
+table.column.Mass = Masa\r
+table.column.Diameter = Diámetro\r
+table.column.Sides = Caras\r
+table.column.LineCount = Orden de línea\r
+table.column.LineLength = Longitud de línea\r
+table.column.LineMaterial = Material de línea\r
+\r
index 480f021433150a07d12fe4fc80b91ca93e5dcf5a..ead57a82e56c4d9cf10dc476edf4a099569fce1d 100644 (file)
@@ -1,4 +1,3 @@
-\r
 #\r
 # French base translation file\r
 # Translated by Tripoli France\r
 # They are pieces that are inserted dynamically.\r
 #\r
 \r
+\r
 ! Set to the name of the current translation file (used for debugging purposes)\r
 debug.currentFile = messages_fr.properties\r
 \r
 ! RocketActions\r
 RocketActions.checkbox.Donotaskmeagain = Ne plus me demander\r
-RocketActions.lbl.Youcanchangedefop = Vous pouvez changer le mode opératoire par defaut dans les préferences.\r
+RocketActions.lbl.Youcanchangedefop = Vous pouvez changer le mode opératoire par défaut dans les préferences.\r
 RocketActions.showConfirmDialog.lbl1 = Supprimer les simulations sélectionnées?\r
 RocketActions.showConfirmDialog.lbl2 = <html><i>Cette opération n'est pas réversible.</i>\r
 RocketActions.showConfirmDialog.title = Effacer les simulations\r
@@ -57,9 +57,6 @@ RocketPanel.lbl.infoMessage = <html>Cliquer pour s
 \r
 \r
 ! BasicFrame\r
-BasicFrame.SimpleFileFilter1 = Tous les fichiers fusée (*.ork; *.rkt)\r
-BasicFrame.SimpleFileFilter2 = Fichiers OpenRocket (*.ork)\r
-BasicFrame.SimpleFileFilter3 = Fichiers RockSim (*.rkt)\r
 BasicFrame.tab.Rocketdesign = Projet fusée\r
 BasicFrame.tab.Flightsim = Simulations de vol\r
 BasicFrame.title.Addnewcomp = Ajouter une nouvelle pièce\r
@@ -72,13 +69,15 @@ BasicFrame.WarningDialog.txt1 = Les probl
 BasicFrame.WarningDialog.txt2 = Certains éléments du projet n'ont peut être pas été chargé correctement.\r
 BasicFrame.WarningDialog.title = Avertissement lors de l'ouverture du fichier\r
 \r
+\r
 ! General error messages used in multiple contexts\r
 error.fileExists.title = Le fichier existe déjà\r
-error.fileExists.desc = Le fichier '{filename}' existe déjà.  Voulez vous l'ecraser?\r
+error.fileExists.desc = Le fichier '{filename}' existe déjà.  Voulez vous l'écraser?\r
 \r
 error.writing.title = Erreur d'écriture du fichier\r
 error.writing.desc = Une erreur est survenue lors de l'écriture dans le fichier:\r
 \r
+\r
 ! Labels used in buttons of dialog windows\r
 # TODO: Rename these to "btn.xxx"\r
 button.ok = OK\r
@@ -90,9 +89,13 @@ dlg.but.ok = Accepter
 dlg.but.cancel = Annuler\r
 dlg.but.close = Fermer\r
 \r
-\r
 ! General file type names\r
 filetypes.pdf = fichier PDF\r
+BasicFrame.SimpleFileFilter1 = Tous les fichiers fusée (*.ork; *.rkt)\r
+BasicFrame.SimpleFileFilter2 = Fichiers OpenRocket (*.ork)\r
+BasicFrame.SimpleFileFilter3 = Fichiers RockSim (*.rkt)\r
+BasicFrame.SimpleFileFilter4 = Pièces OpenRocket pre-configurées (*.orc)\r
+filetypes.images = Fichiers Image\r
 \r
 \r
 ! About Dialog\r
@@ -107,6 +110,7 @@ AboutDialog.lbl.translator = Tripoli France
 AboutDialog.lbl.translatorWebsite = http://tripoli.france.free.fr/\r
 AboutDialog.lbl.translatorIcon = logoTripoliFrance.png\r
 \r
+\r
 ! Print dialog\r
 PrintDialog.title = Imprimer ou exporter\r
 PrintDialog.but.previewAndPrint = Pré-visualiser et imprimer\r
@@ -119,7 +123,6 @@ PrintDialog.error.preview.title = Impossible d'ouvrir la pr
 PrintDialog.error.preview.desc1 = Impossible d'ouvrir la prévisualisation PDF.\r
 PrintDialog.error.preview.desc2 = S'il vous plait utilisez l'option "Sauvegarder en PDF" à la place.\r
 \r
-\r
 !PrintSettingsDialog\r
 PrintSettingsDialog.title = Configuration impression\r
 PrintSettingsDialog.lbl.Templatefillcolor = Couleur de remplissage du modèle:\r
@@ -166,6 +169,9 @@ debuglogdlg.lbl.Logmessage = Texte du message:
 debuglogdlg.lbl.Stacktrace = Stack trace:\r
 \r
 \r
+! MotorChooserDialog\r
+MotorChooserDialog.title = Selectionnez un moteur fusée\r
+\r
 ! Edit Motor configuration dialog\r
 edtmotorconfdlg.but.removemotor = Enlever le moteur\r
 edtmotorconfdlg.but.Selectmotor = Choisir le moteur\r
@@ -201,7 +207,7 @@ matedtpan.title.Editmaterial = Modifier un mat
 matedtpan.title2.Editmaterial = Les matériaux prédéfinis ne peuvent pas être modifiés.\r
 matedtpan.but.ttip.delete = Supprimer un matériau personnalisé\r
 matedtpan.but.ttip.revertall = Supprimer tous les matériaux personnalisés\r
-matedtpan.title.Deletealluser-defined = Effacer tous les matériaux personalisés?\r
+matedtpan.title.Deletealluser-defined = Effacer tous les matériaux personnalisés?\r
 matedtpan.title.Revertall = Revenir aux valeurs précédentes?\r
 matedtpan.lbl.edtmaterials = Modifier les matériaux n'affectera pas les projets fusée existants.\r
 \r
@@ -226,6 +232,7 @@ pref.dlg.tab.Miscellaneousoptions = Autres options
 pref.dlg.lbl.Positiontoinsert = Position pour insérer des composants internes:\r
 pref.dlg.lbl.Confirmdeletion = Confirmer l'effacement des simulations:\r
 pref.dlg.lbl.User-definedthrust = Courbes de poussée personnalisées:\r
+pref.dlg.lbl.Windspeed = Vitesse du vent\r
 pref.dlg.Allthrustcurvefiles = Tous les fichiers de courbes de poussée (*.eng; *.rse; *.zip; répertoires)\r
 pref.dlg.RASPfiles = Fichiers moteur RASP (*.eng)\r
 pref.dlg.RockSimfiles = Fichiers moteur RockSim (*.rse)\r
@@ -281,6 +288,7 @@ simedtdlg.lbl.Simname = Nom de la simulation:
 simedtdlg.tab.Launchcond = Conditions de lancement\r
 simedtdlg.tab.Simopt = Options de simulation\r
 simedtdlg.tab.Plotdata = Tracer les données\r
+simedtdlg.tab.CustomExpressions = Expressions personnalisées\r
 simedtdlg.tab.Exportdata = Exporter les données\r
 simedtdlg.lbl.Motorcfg = Configuration moteur:\r
 simedtdlg.lbl.ttip.Motorcfg = Choisir la configuration moteur à utiliser.\r
@@ -318,7 +326,7 @@ simedtdlg.lbl.ttip.Length = Longueur de la rampe.
 simedtdlg.lbl.Angle = Angle:\r
 simedtdlg.lbl.ttip.Angle = Angle de la rampe de lancement par rapport à la verticale.\r
 simedtdlg.lbl.Direction = Direction:\r
-simedtdlg.lbl.ttip.Direction1 = <html>Direction de la rampe de lance par rapport au vent.<br>\r
+simedtdlg.lbl.ttip.Direction1 = <html>Direction de la rampe de lancement par rapport au vent.<br>\r
 simedtdlg.lbl.ttip.Direction2 =  = Face au vent,\r
 simedtdlg.lbl.ttip.Direction3 = = vent arrière.\r
 simedtdlg.border.Simopt = Options de simulation\r
@@ -327,16 +335,16 @@ simedtdlg.lbl.ttip.Calcmethod = <html>La m
 simedtdlg.lbl.ExtBarrowman = Barrowman étendu\r
 simedtdlg.lbl.Simmethod = Méthode de Simulation:\r
 simedtdlg.lbl.ttip.Simmethod1 = <html>Le simulateur de six degrés de liberté permet la liberté totale de fusée en vol.<br>\r
-simedtdlg.lbl.ttip.Simmethod2 = Integration is performed using a 4<sup>th</sup> order Runge-Kutta 4 numerical integration.\r
+simedtdlg.lbl.ttip.Simmethod2 = l'Integration faite en utilisant a 4<sup>th</sup> order Runge-Kutta 4 numerical integration.\r
 simedtdlg.lbl.GeodeticMethod = Calculs Geodetic:\r
-simedtdlg.lbl.ttip.GeodeticMethodTip = Relate to the calculation of coordinates on the earth.  This also enables coriolis effect computations.\r
+simedtdlg.lbl.ttip.GeodeticMethodTip = A un rapport avec les calculs des coordonnées sur la terre.  Ceci permet egalement de calculer l'effet de coriolis.\r
 simedtdlg.lbl.Timestep = Réglage du pas de temps:\r
 simedtdlg.lbl.ttip.Timestep1 = <html>Le temps entre les étapes de la simulation.<br>Avec un pas de temps plus petit la simulation est plus lente mais également plus précise.<br>\r
-simedtdlg.lbl.ttip.Timestep2 = The 4<sup>th</sup> order simulation method is quite accurate with a time step of\r
+simedtdlg.lbl.ttip.Timestep2 = La méthode de calcul du 4<sup>ème</sup> ordre est suffisamment précise avec un pas de temps de\r
 simedtdlg.but.ttip.resettodefault = Réinitialiser le pas de temps à sa valeur par défaut (\r
 simedtdlg.border.Simlist = Auditeurs de simulation\r
-simedtdlg.txt.longA1 = <html><i>Les auditeurs de simulation</i> sont une fonction avancé qui permet à l'utilisateur d'écrire du code pour suivre et interagir avec la simulation.  \r
-simedtdlg.txt.longA2 = Pour plus de détails sur les auditeurs de simulation, reférez vous à la documentation technique d'OpenRocket.\r
+simedtdlg.txt.longA1 = <html><i>Les auditeurs de simulation</i> sont une fonction avancée qui permet à l'utilisateur d'écrire du code pour suivre et interagir avec la simulation.  \r
+simedtdlg.txt.longA2 = Pour plus de détails sur les auditeurs de simulation, référez vous à la documentation technique d'OpenRocket.\r
 simedtdlg.lbl.Curlist = Auditeurs de simulation actuel:\r
 simedtdlg.lbl.Addsimlist = Ajouter un "auditeur de simulation"\r
 simedtdlg.lbl.Noflightdata = Aucune donnée de vol disponible.\r
@@ -354,9 +362,10 @@ simedtdlg.IntensityDesc.Extreme = Extr
 GeodeticComputationStrategy.none.name = Aucune\r
 GeodeticComputationStrategy.none.desc = Ne pas faire de calculs geodetic.\r
 GeodeticComputationStrategy.spherical.name = Approximation sphérique\r
-GeodeticComputationStrategy.spherical.desc = <html>Perform geodetic computations assuming a spherical Earth.<br>This is sufficiently accurate for almost all purposes.\r
+GeodeticComputationStrategy.spherical.desc = <html>Performe des calculs geodetic en assumant une terre sphérique.<br>Ceci est suffisamment précis dans la plupart des cas.\r
 GeodeticComputationStrategy.wgs84.name = ellipsoïde WGS84\r
-GeodeticComputationStrategy.wgs84.desc = <html>Perform geodetic computations on the WGS84 reference ellipsoid using Vincenty's method.<br>Slower and unnecessary in most cases.\r
+GeodeticComputationStrategy.wgs84.desc = <html>Performe des calculs geodetic sur la référence elliptique WGS84 en utilisant la méthode de Vincenty.<br>Plus long et non nécessaire dans la plupart des cas.\r
+\r
 \r
 \r
 \r
@@ -377,12 +386,22 @@ simpanel.dlg.lbl.DeleteSim2 = <html><i>Cette op
 simpanel.dlg.lbl.DeleteSim3 = Effacer les simulations\r
 simpanel.col.Name = Nom\r
 simpanel.col.Motors = Moteurs\r
+simpanel.col.Velocityoffrod = Vitesse en sortie de rampe\r
+simpanel.col.Velocityatdeploy = Vitesse au déploiement\r
 simpanel.col.Apogee = Apogée\r
 simpanel.col.Maxvelocity = Vitesse Max.\r
 simpanel.col.Maxacceleration = Accélération Max.\r
 simpanel.col.Timetoapogee = Temps pour atteindre l'apogée\r
 simpanel.col.Flighttime = Temps de vol\r
 simpanel.col.Groundhitvelocity = Vitesse à l'atterrissage\r
+simpanel.ttip.uptodate = <i>A jour</i>\r
+simpanel.ttip.loaded = <i>Données chargées depuis un fichier</i>\r
+simpanel.ttip.outdated = <i><font color=\"red\">Les données sont obsoletes</font></i><br>Cliquez <i><b>Run simulations</b></i> pour simuler.\r
+simpanel.ttip.external = <i>Imported data</i>\r
+simpanel.ttip.notSimulated = <i>Pas encore simulé</i><br>Cliquez <i><b>Run simulations</b></i> pour simuler.\r
+simpanel.ttip.noData = Pas de données de simulations disponible.\r
+simpanel.ttip.noWarnings = <font color=\"gray\">Pas d'avertissements.</font>\r
+simpanel.ttip.warnings = <font color=\"red\">Averstissements:</font>\r
 \r
 ! SimulationRunDialog\r
 SimuRunDlg.title.RunSim = Simulations en cour...\r
@@ -400,6 +419,9 @@ SimuRunDlg.msg.unknownerror1 = Une erreur inconnue s'est produite lors de la sim
 SimuRunDlg.msg.unknownerror2 = Le programme peut être instable, vous devez enregistrer toutes vos créations et redémarrez OpenRocket maintenant!\r
 \r
 \r
+RK4SimulationStepper.error.valuesTooLarge = Les valeurs de la simulations dépassent les limittes.  Essayez de choisir un pas de temps plus court.\r
+\r
+SimulationModifierTree.OptimizationParameters = Parametres d'optimisation\r
 \r
 ! SimulationExportPanel\r
 SimExpPan.desc = Fichiers dont les données sont séparées par une virgule (*.csv)\r
@@ -430,10 +452,86 @@ SimExpPan.Col.Variable = Variable
 SimExpPan.Col.Unit = Unité\r
 \r
 \r
-CsvOptionPanel.separator.space = SPACE\r
+CsvOptionPanel.separator.space = ESPACE\r
 CsvOptionPanel.separator.tab = TAB\r
 \r
 \r
+! Custom expression general stuff\r
+customExpression.Name = Nom\r
+customExpression.Symbol = Symbole\r
+customExpression.Expression = Expression\r
+customExpression.Units = Unités\r
+customExpression.Operator = Operateur\r
+customExpression.Description = Description\r
+\r
+! Custom expression panel\r
+customExpressionPanel.but.NewExpression = Nouvelle expression\r
+customExpressionPanel.but.ttip.NewExpression = Ajouter une nouvelle expression personalisée\r
+customExpressionPanel.but.Import = Importer\r
+customExpressionPanel.but.ttip.Import = Importer des expressions personalisés depuis un autre fichier .ork\r
+customExpressionPanel.lbl.UpdateNote = Vous devez faire tourner la simulation avant de pouvoir disposer de données à tracer.\r
+customExpressionPanel.lbl.CalcNote = Les "Expressions" seront calculées dans l'ordre montré.\r
+customExpressionPanel.lbl.CustomExpressions = Expressions personalisées :\r
+customExpression.Units.but.ttip.Remove = Supprimer cette expression\r
+customExpression.Units.but.ttip.Edit = Modifier cette expression\r
+customExpression.Units.but.ttip.MoveUp = Déplacer en haut l'expression dans l'ordre de calcul\r
+customExpression.Units.but.ttip.MoveDown = Déplacer en bas l'expression dans l'ordre de calcul\r
+\r
+\r
+! Custom expression builder window\r
+ExpressionBuilderDialog.title = Constructeur d'Expression\r
+ExpressionBuilderDialog.InsertVariable = Ajouter une Variable\r
+ExpressionBuilderDialog.InsertOperator = Ajouter un Operateur\r
+ExpressionBuilderDialog.led.ttip.Name = Un nom ne peut pas avoir été déjà utilisé\r
+ExpressionBuilderDialog.led.ttip.Symbol = Un symbole ne peut pas avoir été déjà utilisé\r
+ExpressionBuilderDialog.led.ttip.Expression = L'expression doit utiliser seulement des symboles et opérateurs connu\r
+ExpressionBuilderDialog.CopyToOtherSimulations = Copier dans les autres simulations\r
+ExpressionBuilderDialog.CopyToOtherSimulations.ttip = <html>Make a copy of this expression in other simulations in this document.<br>Will not overwrite or modify any existing expressions in other simulations. \r
+\r
+! Custom expression variable selector\r
+CustomVariableSelector.title = Selecteur de variable\r
+\r
+! Custom operator selector\r
+CustomOperatorSelector.title = Operator Selector\r
+\r
+! Operators\r
+Operator.plus = Addition\r
+Operator.minus = Soustraction\r
+Operator.star = Multiplication\r
+Operator.div = Divison\r
+Operator.mod = Modulo\r
+Operator.pow = Exponentiel\r
+Operator.abs = Valeur absolue\r
+Operator.ceil = Plafond (valeure de l'entier suivant\r
+Operator.floor = Sol (valeure de l'entier précedente\r
+Operator.sqrt = Racine carrée\r
+Operator.cbrt = Racine Cubic \r
+Operator.exp = Euler\'s number raised to the value (e^x)\r
+Operator.ln = Logarithme népérien\r
+Operator.sin = Sinus\r
+Operator.cos = Cosinus\r
+Operator.tan = Tangente\r
+Operator.asin = Arc sinus\r
+Operator.acos = Arc cosinus\r
+Operator.atan = Arc tangente\r
+Operator.hsin = Sinus Hyerbolic\r
+Operator.hcos = Cosinus Hyperbolic\r
+Operator.htan = Tangente Hyperbolic\r
+Operator.log10 = Base 10 logarithm\r
+Operator.round = Arondir à l'entier le plus proche\r
+Operator.random = Nombre aléatoire entre zero et une valeur donnée\r
+Operator.expm1 = The same as exp(x)-1, but more accurate for small x \r
+Operator.mean = The arithmetic mean of a given range\r
+Operator.min = La valeur minimum dans une echelle donnée\r
+Operator.max = La valeur maximum dans une echelle donnée\r
+Operator.var = The variance of a given range\r
+Operator.stdev = The standard deviation of a given range\r
+Operator.rms = The root-mean-squared value of a given range\r
+Operator.lclip = Clips a value (1st parameter) to be no less than a given value (2eme parametre)\r
+Operator.uclip = Clips a value (1st parameter) to be no greater than a given value (2eme parametre)\r
+Operator.binf = Gives the fraction of values in a given range (1er parametre) inside a bin with given lower (2nd parameter) and upper (3rd parameter) bounds\r
+Operator.trapz = Integrates the given range using trapezoidal integration\r
+Operator.tnear = Find the time corresponding to the point in a range (1er parametre) nearest to a given value (2nd parameter)\r
 \r
 ! MotorPlot\r
 MotorPlot.title.Motorplot = Courbe du moteur\r
@@ -442,13 +540,11 @@ MotorPlot.Chart.Motorthrustcurve = Courbe de pouss
 MotorPlot.Chart.Time = Temps / s\r
 MotorPlot.Chart.Thrust = Poussée / N\r
 MotorPlot.txt.Designation = Désignation:\r
-MotorPlot.txt.Manufacturer = Manufacturer:\r
+MotorPlot.txt.Manufacturer = Fabriquant:\r
 MotorPlot.txt.Type = Type:\r
 MotorPlot.txt.Delays = Retards:\r
 MotorPlot.txt.Comment = Commentaires:\n\r
 \r
-\r
-\r
 ! Simulation plot panel\r
 simplotpanel.lbl.Presetplotconf = Prédéfinir les paramètres du tracé:\r
 simplotpanel.lbl.Xaxistype = Axe des X:\r
@@ -468,6 +564,8 @@ simplotpanel.AUTO_NAME = Auto
 simplotpanel.LEFT_NAME = Gauche\r
 simplotpanel.RIGHT_NAME = Droite\r
 simplotpanel.CUSTOM = Personnalisé\r
+SimulationPlotPanel.error.noPlotSelected = S'il vous plait ajoutez une ou plusieurs variables à tracer sur l'axe des Y.\r
+SimulationPlotPanel.error.noPlotSelected.title = Rien à tracer\r
 \r
 ! Component add buttons\r
 compaddbuttons.Bodycompandfinsets = Pièces du corps et ailerons\r
@@ -507,7 +605,11 @@ componentanalysisdlg.lbl.machnumber = Mach number:
 componentanalysisdlg.lbl.rollrate = Taux de roulis:\r
 componentanalysisdlg.lbl.activestages = Etages actifs:\r
 componentanalysisdlg.lbl.motorconf = Configuration moteur:\r
-componentanalysisdlg.TabStability.Col.Component = Pièce\r
+!componentanalysisdlg.TabStability.Col.Component = Pièce\r
+componentanalysisdlg.TabStability.Col = Pièce\r
+componentanalysisdlg.TabStability.Col.CG = CG\r
+componentanalysisdlg.TabStability.Col.Mass = Mass\r
+componentanalysisdlg.TabStability.Col.CP = CP\r
 componentanalysisdlg.TabStability = Stabilité\r
 componentanalysisdlg.TabStability.ttip = Information de stabilité\r
 componentanalysisdlg.dragTableModel.Col.Component = Pièce\r
@@ -574,10 +676,10 @@ FinSetConfig.tab.Fintabs = Embases des ailerons
 FinSetConfig.tab.Through-the-wall = Ailerons traversant le fuselage\r
 FinSetConfig.but.Converttofreeform = Convertir en forme libre\r
 FinSetConfig.but.Converttofreeform.ttip = Convertir ce jeu d'ailerons en forme libre\r
-FinSetConfig.but.AutoCalc = Calculer automatiquement\r
 FinSetConfig.Convertfinset = Convertir le jeu d'ailerons\r
 FinSetConfig.but.Splitfins = Séparer les ailerons\r
 FinSetConfig.but.Splitfins.ttip = Diviser le jeu d'ailerons en aileron indépendant\r
+FinSetConfig.but.AutoCalc = Calculer automatiquement\r
 FinSetConfig.lbl.Through-the-wall  = Ailerons traversant le fuselage:\r
 FinSetConfig.lbl.Tablength = Longueur de l'embase:\r
 FinSetConfig.ttip.Tablength = La longueur de l'embase de l'aileron.\r
@@ -587,6 +689,9 @@ FinSetConfig.lbl.Tabposition = Position de l'embase:
 FinSetConfig.ttip.Tabposition = La position de l'embase de l'aileron.\r
 FinSetConfig.lbl.relativeto = relative à\r
 \r
+!FinMarkingGuide\r
+FinMarkingGuide.lbl.Front = Front\r
+\r
 ! MotorDatabaseLoadingDialog\r
 MotorDbLoadDlg.title = Chargement des moteurs\r
 MotorDbLoadDlg.Loadingmotors = Chargement des moteurs...\r
@@ -663,6 +768,13 @@ ComponentCfgDlg.configuration =
 ComponentCfgDlg.configuration1 = configuration\r
 ComponentCfgDlg.Modify = Modifier\r
 \r
+!StageConfig\r
+StageConfig.tab.Separation = Séparation\r
+StageConfig.tab.Separation.ttip = Options de séparation de l'étage\r
+StageConfig.separation.lbl.title = Choisir lorsque cet étage se sépare:\r
+StageConfig.separation.lbl.plus = plus\r
+StageConfig.separation.lbl.seconds = secondes\r
+\r
 !EllipticalFinSetConfig\r
 EllipticalFinSetCfg.Nbroffins = Nombre d'ailerons:\r
 EllipticalFinSetCfg.Rotation = Rotation:\r
@@ -692,7 +804,7 @@ FreeformFinSetCfg.lbl.FincrossSection = Coupe de l'aileron:
 FreeformFinSetCfg.lbl.Thickness = Epaisseur:\r
 ! doubleClick1 + 2 form the message "Double-click to edit", split approximately at the middle\r
 FreeformFinSetConfig.lbl.doubleClick1 = Double-cliquer\r
-FreeformFinSetConfig.lbl.doubleClick2 = pour éditer\r
+FreeformFinSetConfig.lbl.doubleClick2 = pour modifier\r
 FreeformFinSetConfig.lbl.clickDrag = Cliquer+déplacer: Ajouter et déplacer des points\r
 FreeformFinSetConfig.lbl.ctrlClick = Ctrl+cliquer: Enlever un point\r
 FreeformFinSetConfig.lbl.scaleFin = Redimensionner les ailerons\r
@@ -730,8 +842,9 @@ LaunchLugCfg.tab.Generalprop = Propri
 \r
 ! MassComponentConfig\r
 MassComponentCfg.lbl.Mass = Masse\r
-MassComponentCfg.lbl.Length = Longueur\r
-MassComponentCfg.lbl.Diameter = Diamètre\r
+MassComponentCfg.lbl.Density = Densité Approximative:\r
+MassComponentCfg.lbl.Length = Longueur:\r
+MassComponentCfg.lbl.Diameter = Diamètre:\r
 MassComponentCfg.lbl.PosRelativeto = Position relative à:\r
 MassComponentCfg.lbl.plus = plus\r
 MassComponentCfg.tab.General = Général\r
@@ -954,6 +1067,8 @@ main.menu.file.new = Nouveau
 main.menu.file.new.desc = Crée un nouveau projet fusée\r
 main.menu.file.open = Ouvrir...\r
 BasicFrame.item.Openrocketdesign = Ouvre un projet fusée\r
+main.menu.file.openRecent = Ouvrir les fichiers recent...\r
+BasicFrame.item.Openrecentrocketdesign = Ouvrir un projet fusée recent\r
 main.menu.file.openExample = Ouvrir un exemple...\r
 BasicFrame.item.Openexamplerocketdesign = Ouvre un exemple de projet fusée\r
 main.menu.file.save = Sauvegarder\r
@@ -985,16 +1100,20 @@ main.menu.edit.preferences.desc = Configure les pr
 main.menu.analyze = Analyse\r
 main.menu.analyze.desc = Analyses de la fusée\r
 main.menu.analyze.componentAnalysis = Analyse des Pièces\r
-main.menu.analyze.componentAnalysis.desc = Analyse séparé des pices de la fusée\r
+main.menu.analyze.componentAnalysis.desc = Analyse séparée des pièces de la fusée\r
 main.menu.analyze.optimization = Optimisation de la fusée\r
 main.menu.analyze.optimization.desc = Optimisation generale de la fusée\r
+main.menu.analyze.customExpressions = Expressions personalisées\r
+main.menu.analyze.customExpressions.desc = Defini de nouveaux type de données de vol en ecrivant des expressions mathematique personalisées \r
 \r
 main.menu.help = Aide\r
 main.menu.help.desc = Information à propos d'OpenRocket\r
+main.menu.help.tours = Tours d'horizon\r
+main.menu.help.tours.desc = Suivez un tour d'horizon d'OpenRocket\r
 main.menu.help.license = Licence\r
 main.menu.help.license.desc = Information sur la license d'OpenRocket\r
 main.menu.help.bugReport = Rapport d'erreurs\r
-main.menu.help.bugReport.desc = Information pour pouvoir sgnaler les bugs dans OpenRocket\r
+main.menu.help.bugReport.desc = Information pour pouvoir signaler les bugs dans OpenRocket\r
 main.menu.help.debugLog = Debug log\r
 main.menu.help.debugLog.desc = Visualiser le fichier log d'OpenRocket\r
 main.menu.help.about = A propos\r
@@ -1008,50 +1127,61 @@ main.menu.debug.createtestrocket = Cr
 ! Translate here all material database\r
 !\r
 \r
+Material.CUSTOM = Pérsonalisé\r
+\r
 ! Material database\r
+Databases.materials.types.Bulk = Bulk\r
+Databases.materials.types.Line = Ligne\r
+Databases.materials.types.Surface = Surface\r
+\r
 ! BULK_MATERIAL\r
-Databases.materials.Acrylic = Acrylique\r
-Databases.materials.Balsa = Balsa\r
-Databases.materials.Birch = Bouleau\r
-Databases.materials.Cardboard = Carton\r
-Databases.materials.Carbonfiber = Fibre de carbone\r
-Databases.materials.Cork = Liège\r
-Databases.materials.DepronXPS = Depron (XPS)\r
-Databases.materials.Fiberglass = Fibre de verre\r
-Databases.materials.Kraftphenolic = Kraft phénolique\r
-Databases.materials.Maple = Érable\r
-Databases.materials.Paperoffice = Papier (bureau)\r
-Databases.materials.Pine = Pin\r
-Databases.materials.Plywoodbirch = Contre-plaqué (bouleau)\r
-Databases.materials.PolycarbonateLexan = Polycarbonate (Lexan)\r
-Databases.materials.Polystyrene = Polystyrène\r
-Databases.materials.PVC = PVC\r
-Databases.materials.Spruce = Sapin\r
-Databases.materials.StyrofoamgenericEPS = Polystyrène (générique EPS)\r
-Databases.materials.StyrofoamBluefoamXPS = \"Mousse Bleue\" de polystyrène (XPS)\r
-Databases.materials.Quantumtubing = Tube Quantum\r
-Databases.materials.BlueTube = Blue tube\r
+material.acrylic = Acrylique\r
+material.aluminum = Aluminum\r
+material.balsa = Balsa\r
+material.basswood = Tilleul\r
+material.birch = Bouleau\r
+material.brass = Laiton\r
+material.cardboard = Carton\r
+material.carbon_fiber = Fibre de carbone\r
+material.cork = Liège\r
+material.depron_xps = Depron (XPS)\r
+material.fiberglass = Fibre de verre\r
+material.kraft_phenolic = Kraft phénolique\r
+material.maple = Érable\r
+material.paper_office = Papier (bureau)\r
+material.pine = Pin\r
+material.plywood_birch = Contre-plaqué (bouleau)\r
+material.polycarbonate_lexan = Polycarbonate (Lexan)\r
+material.polystyrene = Polystyrène\r
+material.pvc = PVC\r
+material.spruce = Sapin\r
+material.steel = Acier\r
+material.styrofoam_generic_eps = Polystyrène (générique EPS)\r
+material.styrofoam_blue_foam_xps = \"Mousse Bleue\" de polystyrène (XPS)\r
+material.titanium = Titane\r
+material.quantum_tubing = Tube Quantum\r
+material.blue_tube = Blue tube\r
 !SURFACE_MATERIAL\r
-Databases.materials.Ripstopnylon = Ripstop nylon\r
-Databases.materials.Mylar = Mylar\r
-Databases.materials.Polyethylenethin = Polyéthylène (fin)\r
-Databases.materials.Polyethyleneheavy = Polyéthylène (lourd)\r
-Databases.materials.Silk = Soie\r
-Databases.materials.Paperoffice = Papier (bureau)\r
-Databases.materials.Cellophane = Cellophane\r
-Databases.materials.Crepepaper = Papier crépon\r
+material.ripstop_nylon = Ripstop nylon\r
+material.mylar = Mylar\r
+material.polyethylene_thin = Polyéthylène (fin)\r
+material.polyethylene_heavy = Polyéthylène (lourd)\r
+material.silk = Soie\r
+material.paper_office = Papier (bureau)\r
+material.cellophane = Cellophane\r
+material.crepe_paper = Papier crépon\r
 ! LINE_MATERIAL\r
-Databases.materials.Threadheavy-duty = Fil(résistant)\r
-Databases.materials.Elasticcordround2mm = Corde Elastique (ronde 2mm, 1/16 in)\r
-Databases.materials.Elasticcordflat6mm = Corde Elastique (plate 6mm, 1/4 in)\r
-Databases.materials.Elasticcordflat12mm = Corde Elastique (plate 12mm, 1/2 in)\r
-Databases.materials.Elasticcordflat19mm = Corde Elastique (plate 19mm, 3/4 in)\r
-Databases.materials.Elasticcordflat25mm = Corde Elastique (plate 25mm, 1 in)\r
-Databases.materials.Braidednylon2mm = Nylon tressé (2 mm, 1/16 in)\r
-Databases.materials.Braidednylon3mm = Nylon tressé (3 mm, 1/8 in)\r
-Databases.materials.Tubularnylon11mm = Nylon tubulaire (11 mm, 7/16 in)\r
-Databases.materials.Tubularnylon14mm = Nylon tubulaire (14 mm, 9/16 in)\r
-Databases.materials.Tubularnylon25mm = Nylon tubulaire (25 mm, 1 in)\r
+material.thread_heavy_duty = Fil(haute résistance)\r
+material.elastic_cord_round_2_mm_1_16_in = Corde Elastique (ronde 2mm, 1/16 in)\r
+material.elastic_cord_flat_6_mm_1_4_in = Corde Elastique (plate 6mm, 1/4 in)\r
+material.elastic_cord_flat_12_mm_1_2_in = Corde Elastique (plate 12mm, 1/2 in)\r
+material.elastic_cord_flat_19_mm_3_4_in = Corde Elastique (plate 19mm, 3/4 in)\r
+material.elastic_cord_flat_25_mm_1_in = Corde Elastique (plate 25mm, 1 in)\r
+material.braided_nylon_2_mm_1_16_in = Nylon tressé (2 mm, 1/16 in)\r
+material.braided_nylon_3_mm_1_8_in = Nylon tressé (3 mm, 1/8 in)\r
+material.tubular_nylon_11_mm_7_16_in = Nylon tubulaire (11 mm, 7/16 in)\r
+material.tubular_nylon_14_mm_9_16_in = Nylon tubulaire (14 mm, 9/16 in)\r
+material.tubular_nylon_25_mm_1_in = Nylon tubulaire (25 mm, 1 in)\r
 \r
 ! ExternalComponent\r
 ExternalComponent.Rough = Rugueuse\r
@@ -1103,6 +1233,14 @@ NoseCone.NoseCone = Ogive
 Transition.Transition = Transition\r
 !Stage\r
 Stage.Stage = Etage\r
+\r
+Stage.SeparationEvent.UPPER_IGNITION = Allumage du moteur au dessus\r
+Stage.SeparationEvent.IGNITION = Allumage du moteur de l'étage courant\r
+Stage.SeparationEvent.BURNOUT = Fin de combustion du moteur de l'étage courant\r
+Stage.SeparationEvent.EJECTION = Charge d'éjection de l'étage courant\r
+Stage.SeparationEvent.LAUNCH = Lancement\r
+Stage.SeparationEvent.NEVER = Jamais\r
+\r
 ! BodyTube\r
 BodyTube.BodyTube = Tube du corps\r
 ! TubeCoupler\r
@@ -1121,6 +1259,14 @@ Parachute.Parachute = Parachute
 ShockCord.ShockCord = Cordon amortisseur\r
 ! Bulkhead\r
 Bulkhead.Bulkhead = Cloison\r
+! CenteringRing\r
+CenteringRing.CenteringRing = Anneau de centrage\r
+! EngineBlock\r
+EngineBlock.EngineBlock = Engine block\r
+! Streamer\r
+Streamer.Streamer = Streamer\r
+! Sleeve\r
+Sleeve.Sleeve = Sleeve\r
 \r
 !Rocket\r
 Rocket.motorCount.Nomotor = [aucun moteurs]\r
@@ -1137,19 +1283,19 @@ MotorMount.IgnitionEvent.NEVER = Jamais
 ComponentIcons.Nosecone = Ogive\r
 ComponentIcons.Bodytube = Tube\r
 ComponentIcons.Transition = Transition\r
-ComponentIcons.Trapezoidalfinset = Jeu d'ailerons de forme trapézoïdale\r
-ComponentIcons.Ellipticalfinset = Jeu d'ailerons de forme elliptique \r
-ComponentIcons.Freeformfinset = Jeu d'ailerons de forme personnalisé\r
+ComponentIcons.Trapezoidalfinset = Jeux d'ailerons de forme trapézoïdale\r
+ComponentIcons.Ellipticalfinset = Jeux d'ailerons de forme elliptique \r
+ComponentIcons.Freeformfinset = Jeux d'ailerons de forme personnalisé\r
 ComponentIcons.Launchlug = Tube de guidage\r
 ComponentIcons.Innertube = Tube interne\r
 ComponentIcons.Tubecoupler = Coupleur de tube\r
 ComponentIcons.Centeringring = Anneau de centrage\r
 ComponentIcons.Bulkhead = Cloison\r
-ComponentIcons.Engineblock = Bague de retension moteur\r
+ComponentIcons.Engineblock = Bague de rétention moteur\r
 ComponentIcons.Parachute = Parachute\r
-ComponentIcons.Streamer = Banderolle\r
+ComponentIcons.Streamer = Banderole\r
 ComponentIcons.Shockcord = Cordon amortisseur\r
-ComponentIcons.Masscomponent = Piéce Masse\r
+ComponentIcons.Masscomponent = Pièce Masse\r
 ComponentIcons.disabled = (désactivé)\r
 \r
 ! StageAction\r
@@ -1160,6 +1306,8 @@ RecoveryDevice.DeployEvent.LAUNCH = Lancement(plus NN secondes)
 RecoveryDevice.DeployEvent.EJECTION = Première charge d'éjection de cet étage\r
 RecoveryDevice.DeployEvent.APOGEE = Apogée\r
 RecoveryDevice.DeployEvent.ALTITUDE = Altitude spécifiée durant la descente\r
+RecoveryDevice.DeployEvent.CURRENT_STAGE_SEPARATION = Séparation de l'etage en cour\r
+RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION = Séparation de l'etage de dessous\r
 RecoveryDevice.DeployEvent.NEVER = Jamais\r
 \r
 ! FlightEvent\r
@@ -1228,6 +1376,7 @@ FlightDataType.TYPE_ROLL_RATE = Taux de roulis
 FlightDataType.TYPE_PITCH_RATE = Taux de tangage\r
 FlightDataType.TYPE_YAW_RATE = Taux d'embardée\r
 FlightDataType.TYPE_MASS = Masse\r
+FlightDataType.TYPE_PROPELLANT_MASS = Masse du propergol\r
 FlightDataType.TYPE_LONGITUDINAL_INERTIA = Moment d'inertie longitudinale\r
 FlightDataType.TYPE_ROTATIONAL_INERTIA = Moment d'inertie rotatif\r
 FlightDataType.TYPE_CP_LOCATION = Emplacement du CP\r
@@ -1264,6 +1413,7 @@ FlightDataType.TYPE_COMPUTATION_TIME = Temps de calcul
 FlightDataType.TYPE_LATITUDE = Latitude\r
 FlightDataType.TYPE_LONGITUDE = Longitude\r
 FlightDataType.TYPE_CORIOLIS_ACCELERATION = Accélération de Coriolis\r
+FlightDataType.TYPE_GRAVITY = Gravitational acceleration\r
 \r
 ! PlotConfiguration\r
 PlotConfiguration.Verticalmotion = Mouvement vertical par rapport au temps\r
@@ -1281,9 +1431,13 @@ Warning.LargeAOA.str2 = Grand angle d'attaque rencontr
 Warning.DISCONTINUITY = Discontinuité dans le diamètre du corps de la fusée.\r
 Warning.THICK_FIN = Les ailerons fin ne seront peut être pas modélisés correctement.\r
 Warning.JAGGED_EDGED_FIN = Des ailerons aux bords irréguliers ne seront pas modélisés correctement.\r
-Warning.LISTENERS_AFFECTED = Listeners modified the flight simulation\r
+Warning.LISTENERS_AFFECTED = Les ecouteurs ont modifié la simulation de vol\r
 Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING = Le dispositif de récupération s'est ouvert alors que la combustion du moteur n'était pas finie.\r
 Warning.FILE_INVALID_PARAMETER = Paramètre invalide rencontré, ignorer.\r
+Warning.PARALLEL_FINS = Beaucoup trop d'ailerons en paralléle\r
+Warning.SUPERSONIC = Les calculs du corps ne seront peut etre pas très précis aux vitesses supersonic.\r
+Warning.RECOVERY_LAUNCH_ROD = Le dispositif de recuperation deployé pendant que l'on etait sur la rampe.\r
+Warning.RECOVERY_HIGH_SPEED = Deploiement du systeme de recuperation à grande vitesse\r
 \r
 \r
 ! Scale dialog\r
@@ -1298,9 +1452,9 @@ ScaleDialog.lbl.scaling.ttip = Taille r
 ! The scaleFrom/scaleTo pair creates a phrase "Scale from [...] to [...]"\r
 ScaleDialog.lbl.scaleFrom = Mise à l'échelle de \r
 ScaleDialog.lbl.scaleTo = à\r
-ScaleDialog.lbl.scaleFromTo.ttip = Define the scaling based on an original and resulting length.\r
+ScaleDialog.lbl.scaleFromTo.ttip = Définir la mise à l'échelle en fonction de la longueur d'origine et la longueur finale.\r
 ScaleDialog.checkbox.scaleMass = Mettez à jour explicitement les masses\r
-ScaleDialog.checkbox.scaleMass.ttip = Scale mass component and override mass values by the cube of the scaling factor\r
+ScaleDialog.checkbox.scaleMass.ttip = Mettre à l'échelle les pièces poids et remplacer leurs masses par le cube du facteur de mise à l'échelle\r
 ScaleDialog.button.scale = Redimensionner\r
 ScaleDialog.undo.scaleRocket = Redimensionner la fusée\r
 ScaleDialog.undo.scaleComponent = Redimensionner une pièce\r
@@ -1312,7 +1466,11 @@ Icons.Redo = Redo
 \r
 OpenRocketPrintable.Partsdetail = Détail des pièces\r
 OpenRocketPrintable.Fintemplates = Gabaries des ailerons\r
+OpenRocketPrintable.Transitiontemplates = Gabaries de transition\r
+OpenRocketPrintable.Noseconetemplates = Gabaries d'ogive\r
+OpenRocketPrintable.Finmarkingguide = Guide de marquage pour les ailerons\r
 OpenRocketPrintable.DesignReport = Rapport de conception\r
+OpenRocketPrintable.Centeringringtemplates = Gabaries pour les anneaux de centrage\r
 \r
 OpenRocketDocument.Redo = Refaire\r
 OpenRocketDocument.Undo = Défaire\r
@@ -1367,7 +1525,7 @@ optimization.modifier.ellipticalfinset.height = Hauteur
 optimization.modifier.ellipticalfinset.height.desc = Optimizer la hauteur (semi-span) du jeux d'ailerons.\r
 \r
 optimization.modifier.finset.cant = Cant angle\r
-optimization.modifier.finset.cant.desc = Optimize the cant angle of the fin set.\r
+optimization.modifier.finset.cant.desc = Optimize le "cant angle" du jeux d'ailerons.\r
 optimization.modifier.finset.position = Position\r
 optimization.modifier.finset.position.desc = Optimisation de la position du jeux d'ailerons sur le corps de la fusée.\r
 \r
@@ -1397,7 +1555,7 @@ optimization.modifier.streamer.length.desc = Optimisation de la longueur de la b
 optimization.modifier.streamer.width = Largeur\r
 optimization.modifier.streamer.width.desc = Optimisation de la largeur de la banderole (streamer).\r
 optimization.modifier.streamer.aspectRatio = Aspect ratio\r
-optimization.modifier.streamer.aspectRatio.desc = Optimize the aspect ratio of the streamer (length/width).  You should NOT select streamer length or width at the same time with the aspect ratio.\r
+optimization.modifier.streamer.aspectRatio.desc = Optimise le ratio d'aspect de la banderole (streamer) (longeur/largeur).  Vous ne devriez PAS choisir la longueur ou la largeur du streamer au meme moment avec le ratio d'aspect.\r
 optimization.modifier.streamer.coefficient = Coefficient de trainée\r
 optimization.modifier.streamer.coefficient.desc = Optimisation du coéfficient de trainée de la banderole (streamer).\r
 \r
@@ -1445,25 +1603,25 @@ GeneralOptimizationDialog.lbl.optimizeGoal.ttip = Choisir le but de l'optimisati
 GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip = Valeur personnalisée à rechercher\r
 GeneralOptimizationDialog.lbl.requireStability = Stabilité désirée\r
 GeneralOptimizationDialog.lbl.requireMinStability = Stabilité minimum:\r
-GeneralOptimizationDialog.lbl.requireMinStability.ttip = Exiger une marge de stabilité statique minimale pour le design\r
+GeneralOptimizationDialog.lbl.requireMinStability.ttip = Exiger une marge de stabilité statique minimale pour le "design"\r
 GeneralOptimizationDialog.lbl.requireMaxStability = Stabilité maximum:\r
-GeneralOptimizationDialog.lbl.requireMaxStability.ttip = Exiger une marge de stabilité statique maximale pour le design\r
+GeneralOptimizationDialog.lbl.requireMaxStability.ttip = Exiger une marge de stabilité statique maximale pour le "design"\r
 GeneralOptimizationDialog.status.bestValue = Meilleure valeur:\r
-GeneralOptimizationDialog.status.bestValue.ttip = Meilleure valeur optimum trouvé jusqu'à présent.\r
-GeneralOptimizationDialog.status.stepCount = Step count:\r
-GeneralOptimizationDialog.status.stepCount.ttip = Number of optimization steps that have been performed.\r
+GeneralOptimizationDialog.status.bestValue.ttip = Meilleure valeur optimum trouvée jusqu'à présent.\r
+GeneralOptimizationDialog.status.stepCount = Nombre de pas:\r
+GeneralOptimizationDialog.status.stepCount.ttip = Nombre de pas d'optimisation qui ont été accompli.\r
 GeneralOptimizationDialog.status.evalCount = Evaluations:\r
-GeneralOptimizationDialog.status.evalCount.ttip = Total number of function evaluations (simulations) that have been performed.\r
-GeneralOptimizationDialog.status.stepSize = Step size:\r
-GeneralOptimizationDialog.status.stepSize.ttip = Current optimization step size (relative to the optimization parameter ranges)\r
+GeneralOptimizationDialog.status.evalCount.ttip = Nombre total d'évaluations de fonctions (simulations) qui ont été accompli.\r
+GeneralOptimizationDialog.status.stepSize = Taille du pas:\r
+GeneralOptimizationDialog.status.stepSize.ttip = Taille du pas de l'optimisation en cours (relative à la plage des paramètres d'optimisation)\r
 GeneralOptimizationDialog.btn.plotPath = Tracer le chemin\r
-GeneralOptimizationDialog.btn.plotPath.ttip = Plot the optimization path (one and two dimensional optimization only)\r
-GeneralOptimizationDialog.btn.save = Savegarder le chemin\r
-GeneralOptimizationDialog.btn.save.ttip = Sauvegarder les resultats après évaluation des fonctions (simulations) dans un fichier CSV.\r
+GeneralOptimizationDialog.btn.plotPath.ttip = Tracer le chemin de l'optimisation (optimisation à une ou deux dimensions seulement)\r
+GeneralOptimizationDialog.btn.save = Chemin pour la sauvegarder\r
+GeneralOptimizationDialog.btn.save.ttip = Sauvegarder les résultats après évaluation des fonctions (simulations) dans un fichier CSV.\r
 GeneralOptimizationDialog.btn.apply = Appliquer l'optimisation\r
-GeneralOptimizationDialog.btn.apply.ttip = Appliquer les résultats de l'optimisation au design de la fusée\r
-GeneralOptimizationDialog.btn.reset = Re-Réinitialiser\r
-GeneralOptimizationDialog.btn.reset.ttip = Réinitialiser le design de la fusée au design actuel de la fusée\r
+GeneralOptimizationDialog.btn.apply.ttip = Appliquer les résultats de l'optimisation au "design" de la fusée\r
+GeneralOptimizationDialog.btn.reset = Réinitialiser\r
+GeneralOptimizationDialog.btn.reset.ttip = Réinitialiser le "design" de la fusée au "design" actuel de la fusée\r
 GeneralOptimizationDialog.btn.close = Fermer\r
 GeneralOptimizationDialog.btn.close.ttip = Fermer la fenêtre de dialogue sans modifier la fusée\r
 GeneralOptimizationDialog.error.selectParams.text = Tout d'abord choisissez des paramètres à partir desquels optimiser.\r
@@ -1536,9 +1694,51 @@ GuidedTourSelectionDialog.btn.start = Commencer le tour d'horizon!
 ! Custom Fin BMP Importer\r
 CustomFinImport.button.label = Importer depuis un fichier BMP\r
 CustomFinImport.filter = Fichiers Bitmap (*.bmp)\r
-CustomFinImport.badFinImage = Image ailerons Invalide. Doit etre une image en noir et blanc (noir pour l'aileron), ne touchant aucun bord, excepté le bas de l'image, qui est la base de l'aileron.\r
+CustomFinImport.badFinImage = Image ailerons Invalide. Doit être une image en noir et blanc (noir pour l'aileron), ne touchant aucun bord, excepté le bas de l'image, qui est la base de l'aileron.\r
 CustomFinImport.errorLoadingFile = Erreur de chargement du fichier: \r
 CustomFinImport.errorParsingFile = Erreur dans l'analyse de l'image de l'aileron: \r
-CustomFinImport.undo = Importer un jeux d'ailerons de forme libre\r
+CustomFinImport.undo = Importer un jeu d'ailerons de forme libre\r
 CustomFinImport.error.title = Erreur de chargement du profile de l'aileron\r
-CustomFinImport.error.badimage = Impossible de deduire la forme de l'aileron à partir de l'image.\r
+CustomFinImport.error.badimage = Impossible de déduire la forme de l'aileron à partir de l'image.\r
+CustomFinImport.description = L'image sera convertie en noir et blanc en interne (noir pour l'aileron), faites attention à utiliser une couleur foncée pour l'aileron, et blanc ou une couleur clair pour le fond. L'aileron doit toucher en bas de l'image, qui est le bas de l'aileron.\r
+\r
+\r
+PresetModel.lbl.select = Choisir une pièce prédefinie:\r
+PresetModel.lbl.database = A partir d'une base de données...\r
+\r
+\r
+! Component Preset Chooser Dialog\r
+ComponentPresetChooserDialog.title = Choisir une pièce prédéfinie\r
+ComponentPresetChooserDialog.filter.label = Filtrer:\r
+ComponentPresetChooserDialog.checkbox.filterAftDiameter = Match aft diameter\r
+ComponentPresetChooserDialog.checkbox.filterForeDiameter = Match fore diameter\r
+ComponentPresetChooserDialog.menu.sortAsc = Trier par ordre croissant\r
+ComponentPresetChooserDialog.menu.sortDesc = Trier par ordre dé-croissant\r
+ComponentPresetChooserDialog.menu.units = Unités\r
+ComponentPresetChooserDialog.checkbox.showAllCompatible = Montrer tous ceux qui sont compatibles\r
+table.column.Favorite = Préférée\r
+table.column.Manufacturer = Frabriquant\r
+table.column.PartNo = Réference de la pièce\r
+table.column.Description = Description\r
+table.column.Type = Type\r
+table.column.Length = Longueur\r
+table.column.Width = Largeur\r
+table.column.InnerDiameter = Diamètre interne\r
+table.column.OuterDiameter = Diamètre externe\r
+table.column.AftOuterDiameter = Diamètre externe arrière\r
+table.column.AftShoulderLength = Longueur de l'épaulement arrière\r
+table.column.AftShoulderDiameter = Diamètre de l'épaulement arrière\r
+table.column.ForeShoulderLength = Longueur de l'épaulement avant\r
+table.column.ForeShoulderDiameter = Diamètre de l'épaulement avant\r
+table.column.ForeOuterDiameter = Diamètre externe avant\r
+table.column.Shape = Forme\r
+table.column.Material = Matériel\r
+table.column.Finish = Finition\r
+table.column.Thickness = Epaisseur\r
+table.column.Filled = Pleine\r
+table.column.Mass = Masse\r
+table.column.Diameter = Diamètre\r
+table.column.Sides = Cotés\r
+table.column.LineCount = Nombre de ligne\r
+table.column.LineLength = Longueur de la ligne\r
+table.column.LineMaterial = Materiau de la ligne\r
index 38084ea4542cde5312d2caeedd43471ec7e4a7fc..1d2c03661672a30112c3eaf0836d1bbed8b2cbf3 100644 (file)
@@ -1,4 +1,3 @@
-
 #
 # Italian base translation file
 # provided by Mauro Biasutti
@@ -49,14 +48,15 @@ RocketPanel.FigTypeAct.Sideview = Vista laterale
 RocketPanel.FigTypeAct.ttip.Sideview = Vista laterale
 RocketPanel.FigTypeAct.Backview = Vista da sotto
 RocketPanel.FigTypeAct.ttip.Backview = Vista da dietro 
+RocketPanel.FigViewAct.2D = 2D View
+RocketPanel.FigViewAct.ttip.2D = 2D View
+RocketPanel.FigViewAct.3D = 3D View
+RocketPanel.FigViewAct.ttip.3D = 3D View
 RocketPanel.lbl.Motorcfg = Configurazione del motore:
 RocketPanel.lbl.infoMessage = <html>Clicca per selezionare &nbsp;&nbsp; Shift+click per altra selezione &nbsp;&nbsp; Doppio-click per modificare &nbsp;&nbsp; Click+trascina per muovere
 
 
 ! BasicFrame
-BasicFrame.SimpleFileFilter1 = Tutti i disegni di razzi (*.ork; *.rkt)
-BasicFrame.SimpleFileFilter2 = Disegni di OpenRocket (*.ork)
-BasicFrame.SimpleFileFilter3 = Disegni di RockSim (*.rkt)
 BasicFrame.tab.Rocketdesign = Disegno di razzi
 BasicFrame.tab.Flightsim = Simulazioni di volo
 BasicFrame.title.Addnewcomp = Aggiungi nuovo componente
@@ -93,6 +93,11 @@ dlg.but.close = Chiudi
 
 ! General file type names
 filetypes.pdf = PDF files
+BasicFrame.SimpleFileFilter1 = Tutti i disegni di razzi (*.ork; *.rkt)
+BasicFrame.SimpleFileFilter2 = Disegni di OpenRocket (*.ork)
+BasicFrame.SimpleFileFilter3 = Disegni di RockSim (*.rkt)
+BasicFrame.SimpleFileFilter4 = OpenRocket presets (*.orc)
+filetypes.images = Image files
 
 
 ! About Dialog
@@ -227,6 +232,7 @@ pref.dlg.tab.Miscellaneousoptions = Altre opzioni
 pref.dlg.lbl.Positiontoinsert = Posizione nella quale inserire nuovi componenti del corpo:
 pref.dlg.lbl.Confirmdeletion = Conferma la cancellazione delle simulazioni:
 pref.dlg.lbl.User-definedthrust = Curva di spinta fornita dall'utente:
+pref.dlg.lbl.Windspeed = Wind speed
 pref.dlg.Allthrustcurvefiles = Tutti i files di curva di spinta (*.eng; *.rse; *.zip; cartelle)
 pref.dlg.RASPfiles = RASP motor files (*.eng)
 pref.dlg.RockSimfiles = RockSim engine files (*.rse)
@@ -282,6 +288,7 @@ simedtdlg.lbl.Simname = Nome della simulazione:
 simedtdlg.tab.Launchcond = Condizioni di lancio
 simedtdlg.tab.Simopt = Opzioni di simulazione
 simedtdlg.tab.Plotdata = Grafico
+simedtdlg.tab.CustomExpressions = Custom expressions
 simedtdlg.tab.Exportdata = Esporta i dati
 simedtdlg.lbl.Motorcfg = Configurazione del motore:
 simedtdlg.lbl.ttip.Motorcfg = Seleziona la configurazione del motore da usare.
@@ -379,6 +386,8 @@ simpanel.dlg.lbl.DeleteSim2 = <html><i>Questa operazione non puo' essere annulla
 simpanel.dlg.lbl.DeleteSim3 = Cancella simulazioni
 simpanel.col.Name = Nome
 simpanel.col.Motors = Motori
+simpanel.col.Velocityoffrod = Velocity off rod
+simpanel.col.Velocityatdeploy = Velocity at deployment
 simpanel.col.Apogee = Apogeo
 simpanel.col.Maxvelocity = Velocita' massima
 simpanel.col.Maxacceleration = Accelerazione massima
@@ -437,7 +446,63 @@ SimExpPan.Col.Unit = Unita'
 CsvOptionPanel.separator.space = SPAZIO
 CsvOptionPanel.separator.tab = TAB
 
-
+! Custom expression general stuff
+customExpression.Name = Name
+customExpression.Symbol = Symbol
+customExpression.Expression = Expression
+customExpression.Units = Units
+customExpression.Operator = Operator
+customExpression.Description = Description
+
+! Custom expression panel
+customExpressionPanel.but.NewExpression = New expression
+customExpressionPanel.lbl.UpdateNote = You must run the simulation before data will be available for plotting.
+customExpressionPanel.lbl.CalcNote = Expressions will be calculated in the order shown.
+customExpressionPanel.lbl.CustomExpressions = Custom Expressions :
+customExpression.Units.but.ttip.Remove = Remove this expression
+customExpression.Units.but.ttip.Edit = Edit this expression
+customExpression.Units.but.ttip.MoveUp = Move expression up in calculation order
+customExpression.Units.but.ttip.MoveDown = Move expression down in calculation order
+
+! Custom expression builder window
+ExpressionBuilderDialog.title = Expression Builder
+ExpressionBuilderDialog.InsertVariable = Insert Variable
+ExpressionBuilderDialog.InsertOperator = Insert Operator
+ExpressionBuilderDialog.led.ttip.Name = Name must not have already been used
+ExpressionBuilderDialog.led.ttip.Symbol = Symbol must not have already been used
+ExpressionBuilderDialog.led.ttip.Expression = Expression must use only known symbols and operators
+ExpressionBuilderDialog.CopyToOtherSimulations = Copy to other simulations
+ExpressionBuilderDialog.CopyToOtherSimulations.ttip = <html>Make a copy of this expression in other simulations in this document.<br>Will not overwrite or modify any existing expressions in other simulations. 
+
+! Custom expression variable selector
+CustomVariableSelector.title = Variable Selector
+
+! Custom operator selector
+CustomOperatorSelector.title = Operator Selector
+
+! Operators
+Operator.plus = Addition
+Operator.minus = Subtraction
+Operator.star = Multiplication
+Operator.div = Divison
+Operator.mod = Modulo
+Operator.pow = Exponentiation
+Operator.abs = Absolute value
+Operator.ceil = Ceiling (next integer value
+Operator.floor = Floor (previous integer value
+Operator.sqrt = Square root
+Operator.cbrt = Cubic root
+Operator.exp = Euler\'s number raised to the value (e^x)
+Operator.ln = Natural logarithm
+Operator.sin = Sine
+Operator.cos = Cosine
+Operator.tan = Tangent
+Operator.asin = Arc sine
+Operator.acos = Arc cosine
+Operator.atan = Arc tangent
+Operator.hsin = Hyerbolic sine
+Operator.hcos = Hyperbolic cosine
+Operator.htan = Hyperbolic tangent
 
 ! MotorPlot
 MotorPlot.title.Motorplot = Motor plot
@@ -451,8 +516,6 @@ MotorPlot.txt.Type = Tipo:
 MotorPlot.txt.Delays = Ritardi:
 MotorPlot.txt.Comment = Commenti:\n
 
-
-
 ! Simulation plot panel
 simplotpanel.lbl.Presetplotconf = Valori predefiniti per le configurazioni di disegno:
 simplotpanel.lbl.Xaxistype = asse X :
@@ -475,7 +538,6 @@ simplotpanel.CUSTOM = Personalizzato
 SimulationPlotPanel.error.noPlotSelected = Per favore aggiungi una o piu' variabili per disegnare sull'asse Y.
 SimulationPlotPanel.error.noPlotSelected.title = Niente da disegnare
 
-
 ! Component add buttons
 compaddbuttons.Bodycompandfinsets = Componenti del corpo e pinne
 compaddbuttons.Nosecone = Naso
@@ -673,6 +735,13 @@ ComponentCfgDlg.configuration = (configurazione)
 ComponentCfgDlg.configuration1 =
 ComponentCfgDlg.Modify = Modifica
 
+!StageConfig
+StageConfig.tab.Separation = Separation
+StageConfig.tab.Separation.ttip = Stage separation options
+StageConfig.separation.lbl.title = Select when this stage separates:
+StageConfig.separation.lbl.plus = plus
+StageConfig.separation.lbl.seconds = seconds
+
 !EllipticalFinSetConfig
 EllipticalFinSetCfg.Nbroffins = Numero di pinne:
 EllipticalFinSetCfg.Rotation = Rotazione:
@@ -705,6 +774,7 @@ FreeformFinSetConfig.lbl.doubleClick1 = Doppio-click
 FreeformFinSetConfig.lbl.doubleClick2 = per modificare
 FreeformFinSetConfig.lbl.clickDrag = Click+muovi: aggiunge e muove punti
 FreeformFinSetConfig.lbl.ctrlClick = Ctrl+click: rimuove punti
+FreeformFinSetConfig.lbl.scaleFin = Scale Fin
 
 
 !InnerTubeConfig
@@ -739,6 +809,7 @@ LaunchLugCfg.tab.Generalprop = Proprieta' generali
 
 ! MassComponentConfig
 MassComponentCfg.lbl.Mass = Mass:
+MassComponentCfg.lbl.Density = Approximate density:
 MassComponentCfg.lbl.Length = Lunghezza:
 MassComponentCfg.lbl.Diameter = Diameter:
 MassComponentCfg.lbl.PosRelativeto = Posizione relativa a :
@@ -922,7 +993,6 @@ StorageOptChooser.lbl.Estfilesize = Stima della dimensione del file:
 StorageOptChooser.lbl.Saveopt = Salva le opzioni
 
 ! ThrustCurveMotorSelectionPanel
-
 TCMotorSelPan.lbl.Selrocketmotor = Seleziona il motore del razzo:
 TCMotorSelPan.checkbox.hideSimilar = Nascondi le curve di spinta molto simili
 TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = Mostra tutti i motori
@@ -964,6 +1034,8 @@ main.menu.file.new = Nuovo
 main.menu.file.new.desc = Crea il disegno di un nuovo Razzo
 main.menu.file.open = Apri..
 BasicFrame.item.Openrocketdesign = Apri il disegno di un razzo
+main.menu.file.openRecent = Open Recent...
+BasicFrame.item.Openrecentrocketdesign = Open a recent rocket design
 main.menu.file.openExample = Apri esempio
 BasicFrame.item.Openexamplerocketdesign = Apri l'esempio di un disegno di razzo
 main.menu.file.save = Salva
@@ -1001,6 +1073,8 @@ main.menu.analyze.optimization.desc = Ottimizzazioni generali sul disegno del ra
 
 main.menu.help = Aiuto
 main.menu.help.desc = Informazioni su OpenRocket
+main.menu.help.tours = Guided tours
+main.menu.help.tours.desc = Take guided tours on OpenRocket
 main.menu.help.license = Licenza
 main.menu.help.license.desc = Informazioni sulla licenza di OpenRocket 
 main.menu.help.bugReport = Bug Report
@@ -1020,48 +1094,53 @@ main.menu.debug.createtestrocket = Crea un test del razzo
 
 ! Material database
 ! BULK_MATERIAL
-Databases.materials.Acrylic = Acrilico
-Databases.materials.Balsa = Balsa
-Databases.materials.Birch = Betulla
-Databases.materials.Cardboard = Cartoncino
-Databases.materials.Carbonfiber = Fibra di carbonio
-Databases.materials.Cork = Sughero
-Databases.materials.DepronXPS = Depron (XPS)
-Databases.materials.Fiberglass = Fibra di vetro
-Databases.materials.Kraftphenolic = Kraft phenolic
-Databases.materials.Maple = Acero
-Databases.materials.Paperoffice = Carta (ufficio)
-Databases.materials.Pine = Pino
-Databases.materials.Plywoodbirch = Compensato (betulla)
-Databases.materials.PolycarbonateLexan = Policarbonato (Lexan)
-Databases.materials.Polystyrene = Polistirene
-Databases.materials.PVC = PVC
-Databases.materials.Spruce = Abete rosso
-Databases.materials.StyrofoamgenericEPS = polistirolo (generic EPS)
-Databases.materials.StyrofoamBluefoamXPS = polistirolo \"Blue foam\" (XPS)
-Databases.materials.Quantumtubing = Quantum tubing
-Databases.materials.BlueTube = Blue tube
+material.acrylic = Acrilico
+material.aluminum = Aluminum
+material.balsa = Balsa
+material.basswood = Basswood
+material.birch = Betulla
+material.brass = Brass
+material.cardboard = Cartoncino
+material.carbon_fiber = Fibra di carbonio
+material.cork = Sughero
+material.depron_xps = Depron (XPS)
+material.fiberglass = Fibra di vetro
+material.kraft_phenolic = Kraft phenolic
+material.maple = Acero
+material.paper_office = Carta (ufficio)
+material.pine = Pino
+material.plywood_birch = Compensato (betulla)
+material.polycarbonate_lexan = Policarbonato (Lexan)
+material.polystyrene = Polistirene
+material.pvc = PVC
+material.spruce = Abete rosso
+material.steel = Steel
+material.styrofoam_generic_eps = polistirolo (generic EPS)
+material.styrofoam_blue_foam_xps = polistirolo \"Blue foam\" (XPS)
+material.titanium = Titanium
+material.quantum_tubing = Quantum tubing
+material.blue_tube = Blue tube
 !SURFACE_MATERIAL
-Databases.materials.Ripstopnylon = Ripstop nylon
-Databases.materials.Mylar = Mylar
-Databases.materials.Polyethylenethin = Polyethylene (thin)
-Databases.materials.Polyethyleneheavy = Polyethylene (heavy)
-Databases.materials.Silk = Seta
-Databases.materials.Paperoffice = Carta (ufficio)
-Databases.materials.Cellophane = Cellophane
-Databases.materials.Crepepaper = Cr\u00eape carta
+material.ripstop_nylon = Ripstop nylon
+material.mylar = Mylar
+material.polyethylene_thin = Polyethylene (thin)
+material.polyethylene_heavy = Polyethylene (heavy)
+material.silk = Seta
+material.paper_office = Carta (ufficio)
+material.cellophane = Cellophane
+material.crepe_paper = Cr\u00eape carta
 ! LINE_MATERIAL
-Databases.materials.Threadheavy-duty = Thread (heavy-duty)
-Databases.materials.Elasticcordround2mm = Elastic cord (round 2mm, 1/16 in)
-Databases.materials.Elasticcordflat6mm = Elastic cord (flat  6mm, 1/4 in)
-Databases.materials.Elasticcordflat12mm = Elastic cord (flat 12mm, 1/2 in)
-Databases.materials.Elasticcordflat19mm = Elastic cord (flat 19mm, 3/4 in)
-Databases.materials.Elasticcordflat25mm = Elastic cord (flat 25mm, 1 in)
-Databases.materials.Braidednylon2mm = Braided nylon (2 mm, 1/16 in)
-Databases.materials.Braidednylon3mm = Braided nylon (3 mm, 1/8 in)
-Databases.materials.Tubularnylon11mm = Tubular nylon (11 mm, 7/16 in)
-Databases.materials.Tubularnylon14mm = Tubular nylon (14 mm, 9/16 in)
-Databases.materials.Tubularnylon25mm = Tubular nylon (25 mm, 1 in)
+material.thread_heavy_duty = Thread (heavy-duty)
+material.elastic_cord_round_2_mm_1_16_in = Elastic cord (round 2mm, 1/16 in)
+material.elastic_cord_flat_6_mm_1_4_in = Elastic cord (flat  6mm, 1/4 in)
+material.elastic_cord_flat_12_mm_1_2_in = Elastic cord (flat 12mm, 1/2 in)
+material.elastic_cord_flat_19_mm_3_4_in = Elastic cord (flat 19mm, 3/4 in)
+material.elastic_cord_flat_25_mm_1_in = Elastic cord (flat 25mm, 1 in)
+material.braided_nylon_2_mm_1_16_in = Braided nylon (2 mm, 1/16 in)
+material.braided_nylon_3_mm_1_8_in = Braided nylon (3 mm, 1/8 in)
+material.tubular_nylon_11_mm_7_16_in = Tubular nylon (11 mm, 7/16 in)
+material.tubular_nylon_14_mm_9_16_in = Tubular nylon (14 mm, 9/16 in)
+material.tubular_nylon_25_mm_1_in = Tubular nylon (25 mm, 1 in)
 
 ! ExternalComponent
 ExternalComponent.Rough = Ruvido
@@ -1113,6 +1192,14 @@ NoseCone.NoseCone = Naso
 Transition.Transition = Transizione
 !Stage
 Stage.Stage = Stadio
+
+Stage.SeparationEvent.UPPER_IGNITION = Upper stage motor ignition
+Stage.SeparationEvent.IGNITION = Current stage motor ignition
+Stage.SeparationEvent.BURNOUT = Current stage motor burnout
+Stage.SeparationEvent.EJECTION = Current stage ejection charge
+Stage.SeparationEvent.LAUNCH = Launch
+Stage.SeparationEvent.NEVER = Never
+
 ! BodyTube
 BodyTube.BodyTube = Corpo
 ! TubeCoupler
@@ -1170,6 +1257,8 @@ RecoveryDevice.DeployEvent.LAUNCH = Lancio (piu' NN secondi)
 RecoveryDevice.DeployEvent.EJECTION = Prima carica di espulsione di questo stadio
 RecoveryDevice.DeployEvent.APOGEE = Apogeo
 RecoveryDevice.DeployEvent.ALTITUDE = Una altezza specifica durante la discesa
+RecoveryDevice.DeployEvent.CURRENT_STAGE_SEPARATION = Current stage separation
+RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION = Lower stage separation
 RecoveryDevice.DeployEvent.NEVER = Mai
 
 ! FlightEvent
@@ -1305,7 +1394,6 @@ ScaleDialog.lbl.scale = Scala:
 ScaleDialog.lbl.scale.ttip = Seleziona se vuoi scalare l'intero disegno o solo il componente selezionato
 ScaleDialog.lbl.scaling = La scala da applicare:
 ScaleDialog.lbl.scaling.ttip = Dimensione risultante,valori al di sopra del 100% aumentano e valori al di sotto del 100% diminuiscono il disegno.
-
 ! The scaleFrom/scaleTo pair creates a phrase "Scale from [...] to [...]"
 ScaleDialog.lbl.scaleFrom = Scala da
 ScaleDialog.lbl.scaleTo = a
@@ -1327,6 +1415,7 @@ OpenRocketPrintable.Transitiontemplates = Modelli della transizione
 OpenRocketPrintable.Noseconetemplates = Modelli del naso
 OpenRocketPrintable.Finmarkingguide = Linea di guida della pinna
 OpenRocketPrintable.DesignReport = Relazione del disegno
+OpenRocketPrintable.Centeringringtemplates = Centering Ring templates
 
 OpenRocketDocument.Redo = Rifai
 OpenRocketDocument.Undo = Annulla
@@ -1469,6 +1558,7 @@ GeneralOptimizationDialog.status.evalCount = Valutazioni:
 GeneralOptimizationDialog.status.evalCount.ttip = Numero totale di valutazioni di funzioni(simulazioni) che sono state eseguite.
 GeneralOptimizationDialog.status.stepSize = Dim passo:
 GeneralOptimizationDialog.status.stepSize.ttip = Dimensione del passo di ottimizzazione corrente(relativa al range di valori dei parametri)GeneralOptimizationDialog.btn.plotPath = Disegna percorso
+GeneralOptimizationDialog.btn.plotPath = Plot path
 GeneralOptimizationDialog.btn.plotPath.ttip = Disegna il percorso di ottimizzazione (solamente ottimizzazione mono- e bi-dimensionale)
 GeneralOptimizationDialog.btn.save = Salva percorso
 GeneralOptimizationDialog.btn.save.ttip = Salva i risultati delle valutazioni delle funzioni (simulazioni) come fila CSV.
@@ -1532,3 +1622,69 @@ CompassSelectionButton.lbl.SW = SW
 CompassSelectionButton.lbl.W = W
 CompassSelectionButton.lbl.NW = NW
 
+
+SlideShowDialog.btn.next = Next
+SlideShowDialog.btn.prev = Previous
+
+SlideShowLinkListener.error.title = Guided tour not found
+SlideShowLinkListener.error.msg = Sorry, the selected tour has not yet been written.
+
+GuidedTourSelectionDialog.title = Guided tours
+GuidedTourSelectionDialog.lbl.selectTour = Select guided tour:
+GuidedTourSelectionDialog.lbl.description = Tour description:
+GuidedTourSelectionDialog.lbl.length = Number of slides:
+GuidedTourSelectionDialog.btn.start = Start tour!
+
+
+! Custom Fin BMP Importer
+CustomFinImport.button.label = Import from image
+CustomFinImport.badFinImage = Invalid fin image. Make sure the fin is a solid black or dark color and touching the bottom of the image.
+CustomFinImport.errorLoadingFile = Error loading file: 
+CustomFinImport.errorParsingFile = Error parsing fin image: 
+CustomFinImport.undo = Import freeform fin set
+CustomFinImport.error.title = Error loading fin profile
+CustomFinImport.error.badimage = Could not deduce fin shape from image.
+CustomFinImport.description = The image will be converted internally to black and white image (black for the fin), so make sure you use a solid dark color for the fin, and white or a light color for the background. The fin must be touching the bottom of the image, which is the base of the fin.
+
+
+PresetModel.lbl.select = Select preset:
+PresetModel.lbl.database = From database...
+
+
+! Component Preset Chooser Dialog
+ComponentPresetChooserDialog.title = Choose component preset
+ComponentPresetChooserDialog.filter.label = Filter by text:
+ComponentPresetChooserDialog.checkbox.filterAftDiameter = Match aft diameter
+ComponentPresetChooserDialog.checkbox.filterForeDiameter = Match fore diameter
+ComponentPresetChooserDialog.menu.sortAsc = Sort Ascending
+ComponentPresetChooserDialog.menu.sortDesc = Sort Descending
+ComponentPresetChooserDialog.menu.units = Units
+ComponentPresetChooserDialog.checkbox.showAllCompatible = Show all compatible
+table.column.Favorite = Favorite
+table.column.Manufacturer = Manufacturer
+table.column.PartNo = Part Number
+table.column.Description = Description
+table.column.Type = Type
+table.column.Length = Length
+table.column.Width = Width
+table.column.InnerDiameter = Inner Diameter
+table.column.OuterDiameter = Outer Diameter
+table.column.AftOuterDiameter = Aft Outer Diameter
+table.column.AftShoulderLength = Aft Shoulder Length
+table.column.AftShoulderDiameter = Aft Shoulder Diameter
+table.column.ForeShoulderLength = Fore Shoulder Length
+table.column.ForeShoulderDiameter = Fore Shoulder Diameter
+table.column.ForeOuterDiameter = Fore Outer Diameter
+table.column.Shape = Shape
+table.column.Material = Material
+table.column.Finish = Finish
+table.column.Thickness = Thickness
+table.column.Filled = Filled
+table.column.Mass = Mass
+table.column.Diameter = Diameter
+table.column.Sides = Sides
+table.column.LineCount = Line Count
+table.column.LineLength = Line Length
+table.column.LineMaterial = Line Material
+
+
diff --git a/core/resources/l10n/messages_pl.properties b/core/resources/l10n/messages_pl.properties
new file mode 100644 (file)
index 0000000..a25fecd
--- /dev/null
@@ -0,0 +1,1631 @@
+#
+ # Polish base translation file
+ #
+ # Should you need to add new logical keys here is the proposed method
+ #
+ # className.ComponentType.componentName
+ #
+ #
+ # Text tokens within braces should not be translated, e.g.
+ #    "The file '{filename}' exists."
+ # They are pieces that are inserted dynamically.
+ #
+ ! Set to the name of the current translation file (used for debugging purposes)
+ debug.currentFile  =  messages_pl.properties
+ ! RocketActions
+ RocketActions.checkbox.Donotaskmeagain  =  Nie pytaj ponownie
+ RocketActions.lbl.Youcanchangedefop  =  Domy\u015Bln\u0105 operacj\u0119 mo\u017Cna zmieni\u0107 w ustawieniach.
+ RocketActions.showConfirmDialog.lbl1  =  Usun\u0105\u0107 zaznaczone symulacje?
+ RocketActions.showConfirmDialog.lbl2  =  <html><i>Tej operacji nie mo\u017Cna cofn\u0105\u0107.</i>
+ RocketActions.showConfirmDialog.title  =  Usu\u0144 symulacje
+ RocketActions.DelCompAct.Delete  =  Usu\u0144
+ RocketActions.DelCompAct.ttip.Delete  =  Usu\u0144 wybran\u0105 cz\u0119\u015B\u0107
+ RocketActions.DelSimuAct.Delete  =  Usu\u0144
+ RocketActions.DelSimuAct.ttip.Delete  =  Usu\u0144 zaznaczon\u0105 symulacj\u0119.
+ RocketActions.DelAct.Delete  =  Usu\u0144
+ RocketActions.DelAct.ttip.Delete  =  Usu\u0144 wybran\u0105 cz\u0119\u015B\u0107 lub symulacj\u0119
+ RocketActions.CutAction.Cut  =  Wytnij
+ RocketActions.CutAction.ttip.Cut  =  Wytnij do schowka wybran\u0105 cz\u0119\u015B\u0107 lub symulacj\u0119 i usu\u0144 z projektu
+ RocketActions.CopyAct.Copy  =  Kopiuj
+ RocketActions.CopyAct.ttip.Copy  =  Kopiuj do schowka wybran\u0105 cz\u0119\u015B\u0107 (oraz jej cz\u0119\u015Bci sk\u0142adowe)
+ RocketActions.PasteAct.Paste  =  Wklej
+ RocketActions.PasteAct.ttip.Paste  =  Wklej wybran\u0105 cz\u0119\u015B\u0107 lub symulacj\u0119 ze schowka do projektu.
+ RocketActions.EditAct.Edit  =  Edycja
+ RocketActions.EditAct.ttip.Edit  =  Edytuj zaznaczon\u0105 cz\u0119\u015B\u0107.
+ RocketActions.NewStageAct.Newstage  =  Nowy stopie\u0144
+ RocketActions.NewStageAct.ttip.Newstage  =  Dodaj stopie\u0144 do projektu rakiety.
+ RocketActions.ActBoosterstage  =  Stopie\u0144 startowy rakiety
+ RocketActions.MoveUpAct.Moveup  =  W gór\u0119
+ RocketActions.MoveUpAct.ttip.Moveup  =  Przesu\u0144 wybran\u0105 cz\u0119\u015B\u0107 w gór\u0119.
+ RocketActions.MoveDownAct.Movedown  =  W dó\u0142
+ RocketActions.MoveDownAct.ttip.Movedown  =  Przesu\u0144 wybran\u0105 cz\u0119\u015B\u0107 w dó\u0142.
+ ! RocketPanel
+ RocketPanel.FigTypeAct.Sideview  =  Widok z boku
+ RocketPanel.FigTypeAct.ttip.Sideview  =  Widok z boku
+ RocketPanel.FigTypeAct.Backview  =  Widok z ty\u0142u
+ RocketPanel.FigTypeAct.ttip.Backview  =  Widok tylny
+ RocketPanel.FigViewAct.2D  =  Widok 2D
+ RocketPanel.FigViewAct.ttip.2D  =  Widok 2D
+ RocketPanel.FigViewAct.3D  =  Widok 3D
+ RocketPanel.FigViewAct.ttip.3D  =  Widok 3D
+ RocketPanel.lbl.Motorcfg  =  Konfiguracja silnika:
+ RocketPanel.lbl.infoMessage  =  <html>Kliknij aby wybra\u0107 &nbsp;&nbsp; Shift+kliknij aby wybra\u0107 kolejny &nbsp;&nbsp; kliknij podwójnie aby edytowa\u0107 &nbsp;&nbsp; Kliknij+przeci\u0105gnij aby przesun\u0105\u0107
+ ! BasicFrame
+ BasicFrame.tab.Rocketdesign  =  Projekt rakiety
+ BasicFrame.tab.Flightsim  =  Symulacje lotu
+ BasicFrame.title.Addnewcomp  =  Dodaj now\u0105 cz\u0119\u015B\u0107
+ BasicFrame.dlg.lbl1  =  Projekt '
+ BasicFrame.dlg.lbl2  =  ' nie zosta\u0142 zapisany.
+ BasicFrame.dlg.lbl3  =  Czy chcesz zapisa\u0107?
+ BasicFrame.dlg.title  =  Projekt nie zosta\u0142 zapisany
+ BasicFrame.StageName.Sustainer  =  Cz\u0142on g\u0142ówny
+ BasicFrame.WarningDialog.txt1  =  Podczas próby otwarcia wyst\u0105pi\u0142y nast\u0119puj\u0105ce problemy:
+ BasicFrame.WarningDialog.txt2  =  Niektóre z elementów projektu mog\u0142y zosta\u0107 b\u0142\u0119dnie za\u0142adowane.
+ BasicFrame.WarningDialog.title  =  Ostrze\u017Cenia podczas otwierania pliku
+ ! General error messages used in multiple contexts
+ error.fileExists.title  =  Plik ju\u017C istnieje
+ error.fileExists.desc  =  Plik '{filename}' ju\u017C istnieje  Czy chcesz nadpisa\u0107?
+ error.writing.title  =  B\u0142\u0105d przy zapisie pliku
+ error.writing.desc  =  Wyst\u0105pi\u0142 b\u0142\u0105d podczas zapisu pliku:
+ ! Labels used in buttons of dialog windows
+ # TODO: Rename these to "btn.xxx"
+ button.ok  =  OK
+ button.cancel  =  Anuluj
+ button.close  =  Zamknij
+ ! Common labels used in buttons of dialog windows
+ dlg.but.ok  =  OK
+ dlg.but.cancel  =  Anuluj
+ dlg.but.close  =  Zamknij
+ ! General file type names
+ filetypes.pdf  =  Pliki PDF (*.pdf)
+ BasicFrame.SimpleFileFilter1  =  Wszystkie projekty rakiet (*.ork; *.rkt)
+ BasicFrame.SimpleFileFilter2  =  Projekty OpenRocket (*.ork; *.rkt)
+ BasicFrame.SimpleFileFilter3  =  Projekty RockSim (*.rkt)
+ BasicFrame.SimpleFileFilter4  =  Ustawienia OpenRocket (*.orc)
+ filetypes.images  =  Pliki obrazów
+ ! About Dialog
+ AboutDialog.lbl.version  =  Wersja
+ ! The texts below provide additional credits for the translation maintainer
+ ! - In AboutDialog.lbl.translation replace "English" with the current language.
+ ! - AboutDialog.lbl.translator is the translator / group name (may be empty)
+ ! - AboutDialog.lbl.translatorWebsite is a URL to the translator / group (may be empty)
+ ! - AboutDialog.lbl.translatorIcon is the file name of an icon under pix/translators/ (may be empty)
+ AboutDialog.lbl.translation  =  Polskie t\u0142umaczenie w wykonaniu:
+ AboutDialog.lbl.translator  =  PTR (\u0141ukasz & Alex)
+ AboutDialog.lbl.translatorWebsite  = 
+ AboutDialog.lbl.translatorIcon  = 
+ ! Print dialog
+ PrintDialog.title  =  Drukuj lub eksportuj
+ PrintDialog.but.previewAndPrint  =  Podgl\u0105d & wydruk
+ PrintDialog.checkbox.showByStage  =  Poka\u017C wg stopni
+ PrintDialog.lbl.selectElements  =  Wybierz elementy do za\u0142\u0105czenia:
+ printdlg.but.saveaspdf  =  Zapisz jako PDF
+ printdlg.but.preview  =  Podgl\u0105d
+ printdlg.but.settings  =  Ustawienia
+ PrintDialog.error.preview.title  =  Nie mo\u017Cna wy\u015Bwietli\u0107 podgl\u0105du
+ PrintDialog.error.preview.desc1  =  Nie mo\u017Cna wy\u015Bwietli\u0107 podgl\u0105du PDF.
+ PrintDialog.error.preview.desc2  =  Zamiast tego wybierz opcj\u0119 "zapisz jako PDF".
+ !PrintSettingsDialog
+ PrintSettingsDialog.title  =  Ustawienia drukowania
+ PrintSettingsDialog.lbl.Templatefillcolor  =  Kolor wype\u0142nienia szablonu:
+ PrintSettingsDialog.lbl.Templatebordercolor  =  Kolor ramki szablonu:
+ PrintSettingsDialog.lbl.Papersize  =  Wielko\u015B\u0107 arkusza:
+ PrintSettingsDialog.lbl.Paperorientation  =  Orientacja arkusza:
+ PrintSettingsDialog.but.Reset  =  Reset
+ PrintSettingsDialog.but.Close  =  Zamknij
+ ! Bug Report dialog
+ bugreport.dlg.title  =  Raport o b\u0142\u0119dach
+ bugreport.dlg.but.Sendbugreport  =  Wy\u015Blij raport o b\u0142\u0119dach
+ bugreport.dlg.but.Sendbugreport.Ttip  =  Wy\u015Blij raport z b\u0142\u0119dami automatycznie do deweloperów OpenRocket.
+ bugreport.dlg.successmsg1  =  Raport z b\u0142\u0119dami zosta\u0142 wys\u0142any.
+ bugreport.dlg.successmsg2  =  Dzi\u0119kujemy za Twój wk\u0142ad w rozwój OpenRocket!
+ bugreport.dlg.successmsg3  =  Raport z b\u0142\u0119dami zosta\u0142 wys\u0142any.
+ bugreport.dlg.connectedInternet  =  <html>Je\u017Celi Internet jest pod\u0142\u0105czony, mo\u017Cesz klikn\u0105\u0107 <em>Wy\u015Blij raport z b\u0142\u0119dami</em>.
+ bugreport.dlg.otherwise  =  W przeciwnym wypadku wy\u015Blij poni\u017Cszy tekst na adres:
+ bugreport.lbl.Theinformation  =  Powy\u017Csze informacje mog\u0105 by\u0107 dodane do publicznego raportu b\u0142\u0119dów.  Upewnij si\u0119, \u017Ce tekst nie zawiera \u017Cadnych informacji, których nie chcia\u0142(a)by\u015B upublicznia\u0107.
+ bugreport.dlg.failedmsg1  =  OpenRocket nie by\u0142 w stanie wys\u0142a\u0107 raportu z b\u0142\u0119dami:
+ bugreport.dlg.failedmsg2  =  Prosz\u0119 wys\u0142a\u0107 raport r\u0119cznie do
+ bugreport.dlg.failedmsg3  =  B\u0142\u0105d podczas wysy\u0142ania raportu
+ bugreport.reportDialog.txt  =  <html><b>Mo\u017Cesz zg\u0142osi\u0107 b\u0142\u0105d w OpenRocket poprzez wype\u0142nienie oraz wys\u0142anie poni\u017Cszego formularza.</b><br>Mo\u017Cesz tak\u017Ce zg\u0142asza\u0107 b\u0142\u0119dy oraz dodawa\u0107 za\u0142\u0105czniki na stronie OpenRocket.
+ bugreport.reportDialog.txt2  =  <html><b>Prosz\u0119 do\u0142\u0105czy\u0107 krótki opis czynno\u015Bci wykonywanych w momencie wyst\u0105pienia b\u0142\u0119du.</b>
+ bugreport.dlg.provideDescription  =  Prosz\u0119 najpierw wprowadzi\u0107 opis b\u0142\u0119du.
+ bugreport.dlg.provideDescription.title  =  Brak opisu b\u0142\u0119du
+ ! Debug log dialog
+ debuglogdlg.but.clear  =  Wyczy\u015B\u0107
+ debuglogdlg.OpenRocketdebuglog  =  Rejestr debuggera programu OpenRocket
+ debuglogdlg.Displayloglines  =  Wy\u015Bwietl wiersze rejestru:
+ debuglogdlg.Follow  =  \u015Aledzenie
+ debuglogdlg.col.Time  =  Czas
+ debuglogdlg.col.Level  =  Poziom
+ debuglogdlg.col.Location  =  Lokalizacja
+ debuglogdlg.col.Message  =  Komunikat
+ debuglogdlg.lbl.Loglinenbr  =  Numer wiersza rejestru:
+ debuglogdlg.lbl.Time  =  Czas:
+ debuglogdlg.lbl.Level  =  Poziom:
+ debuglogdlg.lbl.Location  =  Lokalizacja:
+ debuglogdlg.lbl.Logmessage  =  Komunikat:
+ debuglogdlg.lbl.Stacktrace  =  Zapis stosu wywo\u0142a\u0144:
+ ! Edit Motor configuration dialog
+ edtmotorconfdlg.but.removemotor  =  Usu\u0144 silnik
+ edtmotorconfdlg.but.Selectmotor  =  Wybierz silnik
+ edtmotorconfdlg.but.Removeconfiguration  =  Usu\u0144 konfiguracj\u0119
+ edtmotorconfdlg.but.Newconfiguration  =  Nowa konfiguracja
+ edtmotorconfdlg.lbl.Motormounts  =  <html><b>Gniazda silnikowe:</b>
+ edtmotorconfdlg.title.Editmotorconf  =  Edytuj konfiguracje silnika
+ edtmotorconfdlg.selectcomp  =  <html>Wybierz cz\u0119\u015Bci, które pe\u0142ni\u0105 funkcj\u0119 gniazd silnikowych:
+ edtmotorconfdlg.lbl.Motorconfig  =  <html><b>Konfiguracje silników:</b>
+ edtmotorconfdlg.lbl.Configname  =  Nazwa konfiguracji:
+ edtmotorconfdlg.lbl.Leavenamedefault  =  Pozostaw bez nazwy w celu u\u017Cycia nazwy domy\u015Blnej.
+ ! Example design dialog
+ exdesigndlg.but.open  =  Otwórz
+ exdesigndlg.lbl.Selectexample  =  Wybierz przyk\u0142adowe projekty do otwarcia:
+ exdesigndlg.lbl.Openexampledesign  =  Otwórz projekt przyk\u0142adowy
+ exdesigndlg.lbl.Exampledesignsnotfound  =  Projekt przyk\u0142adowy nie zosta\u0142 znaleziony.
+ exdesigndlg.lbl.Examplesnotfound  =  Nie znaleziono przyk\u0142adów
+ ! Material edit panel
+ matedtpan.but.new  =  Nowy
+ matedtpan.but.edit  =  Edytuj
+ matedtpan.but.delete  =  Usu\u0144
+ matedtpan.but.revertall  =  Cofnij wszystko
+ matedtpan.col.Material  =  Materia\u0142
+ matedtpan.col.Type  =  Typ
+ matedtpan.col.Density  =  G\u0119sto\u015B\u0107
+ matedtpan.col.but.ttip.New  =  Dodaj nowy materia\u0142
+ matedtpan.title.Addcustmaterial  =  Dodaj w\u0142asny materia\u0142
+ matedtpan.but.ttip.edit  =  Edytuj dodany materia\u0142
+ matedtpan.title.Editmaterial  =  Edytuj materia\u0142
+ matedtpan.title2.Editmaterial  =  Materia\u0142y wbudowane nie mog\u0105 by\u0107 modyfikowane.
+ matedtpan.but.ttip.delete  =  U\u017Cyj materia\u0142u
+ matedtpan.but.ttip.revertall  =  Usu\u0144 wszystkie materia\u0142y okre\u015Blone przez u\u017Cytkownika
+ matedtpan.title.Deletealluser-defined  =  Usun\u0105\u0107 wszystkie materia\u0142y okre\u015Blone przez u\u017Cytkownika?
+ matedtpan.title.Revertall  =  Cofn\u0105\u0107 wszystko?
+ matedtpan.lbl.edtmaterials  =  Edytowanie materia\u0142ów nie wp\u0142ynie na istniej\u0105ce projekty rakiet.
+ !MaterialModel
+ MaterialModel.title.Material  =  Materia\u0142
+ MaterialModel.title.Defcustmat  =  Zdefiniuj w\u0142asny materia\u0142
+ ! Preference dialog
+ pref.dlg.but.add  =  Dodaj
+ pref.dlg.but.reset  =  Reset
+ pref.dlg.but.checknow  =  Sprawd\u017A teraz
+ pref.dlg.but.defaultmetric  =  Domy\u015Blny system metryczny
+ pref.dlg.but.defaultimperial  =  Domy\u015Blny system Brytyjski
+ pref.dlg.title.Preferences  =  Ustawienia
+ pref.dlg.tab.Units  =  Jednostki
+ pref.dlg.tab.Defaultunits  =  Jednostki domy\u015Blne
+ pref.dlg.tab.Materials  =  Materia\u0142y
+ pref.dlg.tab.Custommaterials  =  Materia\u0142y niestandardowe
+ pref.dlg.tab.Options  =  Opcje
+ pref.dlg.tab.Miscellaneousoptions  =  Ró\u017Cne opcje
+ pref.dlg.lbl.Positiontoinsert  =  Miejsce wstawienia nowych cz\u0119\u015Bci sk\u0142adowych korpusu:
+ pref.dlg.lbl.Confirmdeletion  =  Potwierd\u017A usuni\u0119cie symulacji:
+ pref.dlg.lbl.User-definedthrust  =  Krzywe si\u0142y ci\u0105gu okre\u015Blone przez u\u017Cytkownika
+ pref.dlg.lbl.Windspeed  =  Pr\u0119dko\u015B\u0107 wiatru
+ pref.dlg.Allthrustcurvefiles  =  Wszystkie pliki krzywych si\u0142y ci\u0105gu (*.eng; *.rse; *.zip; foldery)
+ pref.dlg.RASPfiles  =  Pliki silnikowe RASP (*.eng)
+ pref.dlg.RockSimfiles  =  Pliki silnikowe RockSim (*.rse)
+ pref.dlg.ZIParchives  =  Archiwa ZIP (*.zip)
+ pref.dlg.checkbox.Checkupdates  =  Wyszukaj dost\u0119pne aktualizacje przy uruchomieniu programu
+ pref.dlg.ttip.Checkupdatesnow  =  Wyszukaj dost\u0119pne aktualizacje teraz
+ pref.dlg.lbl.Selectprefunits  =  Wybierz preferowane jednostki:
+ pref.dlg.lbl.Rocketdimensions  =  Wymiary rakiety:
+ pref.dlg.lbl.Linedensity  =  G\u0119sto\u015B\u0107 linii:
+ pref.dlg.lbl.Motordimensions  =  Wymiary silnika:
+ pref.dlg.lbl.Surfacedensity  =  G\u0119sto\u015B\u0107 powierzchniowa:
+ pref.dlg.lbl.Distance  =  Odleg\u0142o\u015B\u0107:
+ pref.dlg.lbl.Bulkdensity  =  Ca\u0142kowita g\u0119sto\u015B\u0107:
+ pref.dlg.lbl.Velocity  =  Pr\u0119dko\u015B\u0107:
+ pref.dlg.lbl.Surfaceroughness  =  Nierówno\u015B\u0107 powierzchni:
+ pref.dlg.lbl.Acceleration  =  Przyspieszenie:
+ pref.dlg.lbl.Area  =  Powierzchnia:
+ pref.dlg.lbl.Mass  =  Masa:
+ pref.dlg.lbl.Angle  =  K\u0105t:
+ pref.dlg.lbl.Force  =  Si\u0142a:
+ pref.dlg.lbl.Rollrate  =  Tempo obrotu:
+ pref.dlg.lbl.Totalimpulse  =  Ca\u0142kowity impuls:
+ pref.dlg.lbl.Temperature  =  Temperatura:
+ pref.dlg.lbl.Momentofinertia  =  Moment bezw\u0142adno\u015Bci:
+ pref.dlg.lbl.Pressure  =  Ci\u015Bnienie:
+ pref.dlg.lbl.Stability  =  Stabilno\u015B\u0107:
+ pref.dlg.lbl.FlightTime  =  Czas lotu:
+ pref.dlg.lbl.effect1  =  Zmiany zostan\u0105 wprowadzone przy otwarciu kolejnego okna.
+ pref.dlg.lbl.Checkingupdates  =  Wyszukiwanie aktualizacji...
+ pref.dlg.lbl.msg1  =  Wyst\u0105pi\u0142 b\u0142\u0105d podczas komunikacji z serwerem.
+ pref.dlg.lbl.msg2  =  Nie mo\u017Cna uzyska\u0107 informacji o aktualizacji
+ pref.dlg.lbl.msg3  =  Korzystasz z najnowszej wersji OpenRocket.
+ pref.dlg.lbl.msg4  =  Brak dost\u0119pnych aktualizacji
+ pref.dlg.PrefChoiseSelector1  =  Zawsze pytaj
+ pref.dlg.PrefChoiseSelector2  =  Wstaw w \u015Brodku
+ pref.dlg.PrefChoiseSelector3  =  Dodaj na ko\u0144cu
+ pref.dlg.PrefBooleanSelector1  =  Usu\u0144
+ pref.dlg.PrefBooleanSelector2  =  Potwierd\u017A
+ pref.dlg.Add  =  Dodaj
+ pref.dlg.DescriptionArea.Adddirectories  =  Dodaj katalogi, pliki silnikowe RASP (*.eng), Pliki silnikowe RockSim (*.rse) albo archiwa ZIP rozdzielone \u015Brednikiem (;) by za\u0142adowa\u0107 zewn\u0119trzne krzywe si\u0142y ci\u0105gu.  Zmiany zostan\u0105 wprowadzone przy kolejnym uruchomieniu OpenRocket.
+ PreferencesDialog.lbl.language  =  J\u0119zyk programu:
+ PreferencesDialog.languages.default  =  Domy\u015Blny j\u0119zyk systemu
+ PreferencesDialog.lbl.languageEffect  =  Nowy j\u0119zyk zostanie ustawiony przy kolejnym uruchomieniu OpenRocket.
+ ! Simulation edit dialog
+ simedtdlg.but.runsimulation  =  Przeprowad\u017A symulacj\u0119
+ simedtdlg.but.resettodefault  =  Przywró\u0107 domy\u015Blny
+ simedtdlg.but.add  =  Dodaj
+ simedtdlg.but.remove  =  Usu\u0144
+ simedtdlg.title.Editsim  =  Edytuj symulacj\u0119
+ simedtdlg.lbl.Simname  =  Nazwa symulacji:
+ simedtdlg.tab.Launchcond  =  Warunki startowe
+ simedtdlg.tab.Simopt  =  Opcje symulacji
+ simedtdlg.tab.Plotdata  =  Poka\u017C wykres
+ simedtdlg.tab.Exportdata  =  Eksportuj dane
+ simedtdlg.lbl.Motorcfg  =  Konfiguracja silnika:
+ simedtdlg.lbl.ttip.Motorcfg  =  Wybierz konfiguracj\u0119 silnika.
+ simedtdlg.combo.ttip.motorconf  =  Wybierz konfiguracj\u0119 silnika.
+ simedtdlg.lbl.Wind  =  Wiatr
+ simedtdlg.lbl.Averwindspeed  =  \u015Arednia pr\u0119dko\u015B\u0107 wiatru:
+ simedtdlg.lbl.ttip.Averwindspeed  =  \u015Arednia pr\u0119dko\u015B\u0107 wiatru wzgl\u0119dem powierzchni.
+ simedtdlg.lbl.Stddeviation  =  Odchylenie standardowe:
+ simedtdlg.lbl.ttip.Stddeviation  =  <html>Odchylenie standardowe pr\u0119dko\u015Bci wiatru.<br>Pr\u0119dko\u015B\u0107 wiatru jest w zakresie dwukrotnego odchylenia standardowego od warto\u015Bci \u015Bredniej przez 95% czasu.
+ simedtdlg.lbl.Turbulenceintensity  =  Intensywno\u015B\u0107 turbulencji:
+ simedtdlg.lbl.ttip.Turbulenceintensity1  =  <html>Intensywno\u015B\u0107 turbulencji = odchylenie standardowe podzielone przez \u015Bredni\u0105 pr\u0119dko\u015B\u0107 wiatru.<br>
+ simedtdlg.lbl.ttip.Turbulenceintensity2  =  Typowe warto\u015Bci w zakresie od
+ simedtdlg.lbl.ttip.Turbulenceintensity3  =  do
+ simedtdlg.border.Atmoscond  =  Warunki atmosferyczne
+ simedtdlg.checkbox.InterStdAtmosphere  =  Stosuj mi\u0119dzynarodowy standard modelu atmosferycznego
+ simedtdlg.checkbox.ttip.InterStdAtmosphere1  =  <html>Wybierz, aby zastosowa\u0107 mi\u0119dzynarodowy standard modelu atmosferycznego.<br>Temperatura w tym modelu wynosi
+ simedtdlg.checkbox.ttip.InterStdAtmosphere2  =  ; ci\u015Bnienie
+ simedtdlg.checkbox.ttip.InterStdAtmosphere3  =  na poziomie morza.
+ simedtdlg.lbl.Temperature  =  Temperatura:
+ simedtdlg.lbl.ttip.Temperature  =  Temperatura w miejscu startu rakiety.
+ simedtdlg.lbl.Pressure  =  Ci\u015Bnienie:
+ simedtdlg.lbl.ttip.Pressure  =  Ci\u015Bnienie atmosferyczne punktu startowego.
+ simedtdlg.lbl.Launchsite  =  Punkt startowy
+ simedtdlg.lbl.Latitude  =  Szeroko\u015B\u0107 geograficzna:
+ simedtdlg.lbl.ttip.Latitude  = <html>Od szeroko\u015Bci geograficznej miejsca startu zale\u017Cy wp\u0142yw przyci\u0105gania ziemskiego na rakiet\u0119.<br>Dodatnie warto\u015Bci znajduj\u0105 si\u0119 na pó\u0142kuli pó\u0142nocnej, ujemne warto\u015Bci na pó\u0142kuli po\u0142udniowej.
+ simedtdlg.lbl.Longitude = Dugo\u015B\u0107 geograficzna:
+ simedtdlg.lbl.ttip.Longitude  =  <html>Wymagane w w przypadku modeli przewiduj\u0105cych warunki pogodowe i modeli wzniesienia.
+ simedtdlg.lbl.Altitude  =  Wysoko\u015B\u0107:
+ simedtdlg.lbl.ttip.Altitude  =  <html>Wysoko\u015B\u0107 lokalizacji startowej ponad poziomem morza.<br>Wp\u0142ywa na po\u0142o\u017Cenie rakiety w modelu atmosferycznym.
+ simedtdlg.border.Launchrod  =  Pr\u0119t startowy
+ simedtdlg.lbl.Length  =  D\u0142ugo\u015B\u0107:
+ simedtdlg.lbl.ttip.Length  =  D\u0142ugo\u015B\u0107 pr\u0119ta startowego.
+ simedtdlg.lbl.Angle  =  K\u0105t:
+ simedtdlg.lbl.ttip.Angle  =  K\u0105t nachylenia pr\u0119ta startowego do pionu.
+ simedtdlg.lbl.Direction  =  Kierunek:
+ simedtdlg.lbl.ttip.Direction1  =  <html>Orientacja pr\u0119ta startowego wzgl\u0119dem wiatru.<br>
+ simedtdlg.lbl.ttip.Direction2  =   
+ simedtdlg.lbl.ttip.Direction3  =  
+ simedtdlg.border.Simopt  =  Opcje symulatora
+ simedtdlg.lbl.Calcmethod  =  Metoda obliczeniowa:
+ simedtdlg.lbl.ttip.Calcmethod  =  <html>Rozszerzona metoda Barrowmana s\u0142u\u017Cy do obliczania si\u0142 aerodynamicznych zgodnie z <br>równaniami Barrowmana, rozszerzonymi w celu uj\u0119cia wi\u0119kszej liczby cz\u0119\u015Bci sk\u0142adowych modelu.
+ simedtdlg.lbl.ExtBarrowman  =  Rozszerzona metoda Barrowmana
+ simedtdlg.lbl.Simmethod  =  Metoda symulacji:
+ simedtdlg.lbl.ttip.Simmethod1  =  <html>Symulator uwzgl\u0119dnia sze\u015B\u0107 stopni swobody, co zapewnia ca\u0142kowit\u0105 swobod\u0119 lotu rakiety.<br>
+ simedtdlg.lbl.ttip.Simmethod2  =  Integracja jest dokonywana za pomoc\u0105 integracji numerycznej czwartego stopnia Rungego-Kutty 4.
+ simedtdlg.lbl.GeodeticMethod  =  Obliczenia geodezyjne:
+ simedtdlg.lbl.ttip.GeodeticMethodTip  =  Dotycz\u0105 obliczania wspó\u0142rz\u0119dnych na kuli ziemskiej.  Ta funkcja umo\u017Cliwia równie\u017C obliczanie efektu Coriolisa.
+ simedtdlg.lbl.Timestep  =  Krok czasowy:
+ simedtdlg.lbl.ttip.Timestep1  =  <html>Odst\u0119p czasu pomi\u0119dzy poszczególnymi krokami symulacji.<br>Mniejszy krok czasowy zwi\u0119ksza dok\u0142adno\u015B\u0107 symulacji, ale te\u017C zmniejsza jej szybko\u015B\u0107.<br>
+ simedtdlg.lbl.ttip.Timestep2  =  Metoda symulacji czwartego stopnia jest dosy\u0107 dok\u0142adna przy kroku czasowym wynosz\u0105cym
+ simedtdlg.but.ttip.resettodefault  =  Przywró\u0107 domy\u015Blny krok czasowy (
+ simedtdlg.border.Simlist  =  Detektory symulacji
+ simedtdlg.txt.longA1  =  <html><i>Detektory symulacji</i> s\u0105 zaawansowan\u0105 funkcj\u0105, umo\u017Cliwiaj\u0105c\u0105 U\u017Cytkownikowi zdefiniowanie w\u0142asnych kodów monitoruj\u0105cych proces symulacji i wchodz\u0105cych z ni\u0105 w interakcje.
+ simedtdlg.txt.longA2  =  Szczegó\u0142owa instrukcja pisania detektorów symulacji znajduje si\u0119 w dokumentacji technicznej programu OpenRocket.
+ simedtdlg.lbl.Curlist  =  Bie\u017C\u0105ce detektory symulacji:
+ simedtdlg.lbl.Addsimlist  =  Dodaj detektor symulacji
+ simedtdlg.lbl.Noflightdata  =  Brak dost\u0119pnych danych o locie rakiety.
+ simedtdlg.lbl.runsimfirst  =  Prosz\u0119 najpierw przeprowadzi\u0107 symulacj\u0119.
+ simedtdlg.chart.Simflight  =  Lot symulowany
+ simedtdlg.dlg.Simres  =  Wyniki symulacji
+ simedtdlg.IntensityDesc.None  =  Brak
+ simedtdlg.IntensityDesc.Verylow  =  Bardzo niski
+ simedtdlg.IntensityDesc.Low  =  Niski
+ simedtdlg.IntensityDesc.Medium  =  \u015Aredni
+ simedtdlg.IntensityDesc.High  =  Wysoki
+ simedtdlg.IntensityDesc.Veryhigh  =  Bardzo Wysoki
+ simedtdlg.IntensityDesc.Extreme  =  Ekstremum
+ GeodeticComputationStrategy.flat.name  =  P\u0142aska ziemia
+ GeodeticComputationStrategy.flat.desc  =  Obliczenia przy za\u0142o\u017Ceniu, \u017Ce powierzchnia kuli ziemskiej jest p\u0142aska.  Wystarczaj\u0105ce dolotów na niskie wysoko\u015Bci.
+ GeodeticComputationStrategy.spherical.name  =  Aproksymacja sferyczna
+ GeodeticComputationStrategy.spherical.desc  =  <html>Obliczenia geodezyjne przy za\u0142o\u017Ceniu, \u017Ce Ziemia ma kszta\u0142t sfery.<br>Ta metoda jest wystarczaj\u0105co dok\u0142adna niemal w ka\u017Cdym przypadku.
+ GeodeticComputationStrategy.wgs84.name  =  Elipsoida WGS-84
+ GeodeticComputationStrategy.wgs84.desc  =  <html>Obliczenia geodezyjne metod\u0105 Vincentego w uk\u0142adzie elipsoidalnym WGS-84.<br>Powolne i w wi\u0119kszo\u015Bci przypadków niepotrzebne.
+ ! Simulation Panel
+ simpanel.but.newsimulation  =  Nowa symulacja
+ simpanel.but.editsimulation  =  Edytuj symulacj\u0119
+ simpanel.but.runsimulations  =  Przeprowad\u017A symulacj\u0119
+ simpanel.but.deletesimulations  =  Usu\u0144 symulacje
+ simpanel.but.plotexport  =  Rysuj wykres / eksportuj
+ simpanel.but.ttip.newsimulation  =  Dodaj nowa symulacj\u0119
+ simpanel.but.ttip.editsim  =  Edytuj zaznaczon\u0105 symulacj\u0119
+ simpanel.but.ttip.runsimu  =  Powtórz zaznaczon\u0105 symulacj\u0119
+ simpanel.but.ttip.deletesim  =  Usu\u0144 zaznaczone symulacje
+ simpanel.checkbox.donotask  =  Nie pytaj ponownie
+ simpanel.lbl.defpref  =  Domy\u015Bln\u0105 operacj\u0119 mo\u017Cna zmieni\u0107 w ustawieniach.
+ simpanel.dlg.lbl.DeleteSim1  =  Usun\u0105\u0107 zaznaczone symulacje?
+ simpanel.dlg.lbl.DeleteSim2  =  <html><i>Tej operacji nie mo\u017Cna cofn\u0105\u0107.</i>
+ simpanel.dlg.lbl.DeleteSim3  =  Usu\u0144 symulacje
+ simpanel.col.Name  =  Nazwa
+ simpanel.col.Motors  =  Silniki
+ simpanel.col.Velocityoffrod  =  Pr\u0119dko\u015B\u0107 zej\u015Bcia z wyrzutni
+ simpanel.col.Velocityatdeploy  =  Pr\u0119dko\u015B\u0107 w chwili aktywacji UWS
+ simpanel.col.Apogee  =  Apogeum
+ simpanel.col.Maxvelocity  =  Maksymalna pr\u0119dko\u015B\u0107
+ simpanel.col.Maxacceleration  =  Maksymalne przyspieszenie
+ simpanel.col.Timetoapogee  =  Czas do apogeum
+ simpanel.col.Flighttime  =  Czas lotu
+ simpanel.col.Groundhitvelocity  =  Pr\u0119dko\u015B\u0107 przyziemienia
+ ! SimulationRunDialog
+ SimuRunDlg.title.RunSim  =  Symulacje w trakcie...
+ SimuRunDlg.lbl.Running  =  Symulacja aktywna...
+ SimuRunDlg.lbl.Simutime  =  Czas symulacji:
+ SimuRunDlg.lbl.Altitude  =  Wysoko\u015B\u0107:
+ SimuRunDlg.lbl.Velocity  =  Pr\u0119dko\u015B\u0107:
+ SimuRunDlg.msg.Unabletosim  =  Nie mo\u017Cna przeprowadzi\u0107 symulacji:
+ SimuRunDlg.msg.errorOccurred  =  Wyst\u0105pi\u0142 b\u0142\u0105d podczas symulacji.
+ SimuRunDlg.msg.AnException1  =  Wyst\u0105pi\u0142 wyj\u0105tek podczas symulacji:
+ SimuRunDlg.msg.AnException2  =  Prosz\u0119 zg\u0142osi\u0107 to jako b\u0142\u0105d oraz poda\u0107 szczegó\u0142y.
+ SimuRunDlg.msg.AssertionError1  =  Podczas symulacji wyst\u0105pi\u0142 b\u0142\u0105d obliczeniowy.
+ SimuRunDlg.msg.AssertionError2  =  Prosz\u0119 zg\u0142osi\u0107 to jako b\u0142\u0105d oraz poda\u0107 szczegó\u0142y.
+ SimuRunDlg.msg.unknownerror1  =  Podczas symulacji wyst\u0105pi\u0142 nieznany b\u0142\u0105d.
+ SimuRunDlg.msg.unknownerror2  =  Program mo\u017Ce by\u0107 niestabilny. Zapisz wszystkie projekty i uruchom ponownie OpenRocket!
+ RK4SimulationStepper.error.valuesTooLarge  =  Warto\u015Bci w symulacji wykroczy\u0142y poza dopuszczalne granice.  Spróbuj ustawi\u0107 mniejszy krok czasowy.
+ ! SimulationExportPanel
+ SimExpPan.desc  =  Pliki rozdzielone przecinkiem (*.csv)
+ SimExpPan.border.Vartoexport  =  Zmienne do wyeksportowania
+ SimExpPan.but.Selectall  =  Wybierz wszystko
+ SimExpPan.but.Selectnone  =  Odznacz wszystko
+ SimExpPan.border.Fieldsep  =  Separator pól
+ SimExpPan.lbl.Fieldsepstr  =  Ci\u0105g znaków - separator pól:
+ SimExpPan.lbl.longA1  =  <html>Ci\u0105g znaków stosowany do oddzielania pól w eksportowanym pliku.<br>
+ SimExpPan.lbl.longA2  =  W przypadku pliku CSV u\u017Cyj przecinka (",").
+ SimExpPan.checkbox.Includesimudesc  =  Dodaj opis symulacji
+ SimExpPan.checkbox.ttip.Includesimudesc  =  Dodaj komentarz opisuj\u0105cy symulacj\u0119 na pocz\u0105tku pliku.
+ SimExpPan.border.Comments  =  Komentarze
+ SimExpPan.checkbox.Includefielddesc  =  Dodaj opisy pól
+ SimExpPan.checkbox.ttip.Includefielddesc  =  Dodaj wiersz komentarza z opisem eksportowanych zmiennych.
+ SimExpPan.checkbox.Incflightevents  =  Dodaj zdarzenia lotu
+ SimExpPan.checkbox.ttip.Incflightevents  =  Dodaj wiersz komentarza do ka\u017Cdego zdarzenia lotu.
+ SimExpPan.lbl.Commentchar  =  Znak komentarza:
+ SimExpPan.lbl.ttip.Commentchar  =  Znak(i) sygnalizuj\u0105cy(e) komentarz.
+ SimExpPan.but.Exporttofile  =  Eksportuj do pliku...
+ SimExpPan.Fileexists.desc1  =  Plik \"
+ SimExpPan.Fileexists.desc2  =  \" istnieje.  Nadpisa\u0107?
+ SimExpPan.Fileexists.title  =  Plik ju\u017C istnieje
+ SimExpPan.ExportingVar.desc1  =  Eksportuj\u0119 1 zmienn\u0105 z
+ SimExpPan.ExportingVar.desc2  =  Eksportuj\u0119
+ SimExpPan.ExportingVar.desc3  =  zmienne z
+ SimExpPan.Col.Variable  =  Zmienna
+ SimExpPan.Col.Unit  =  Jednostka
+ CsvOptionPanel.separator.space  =  SPACJA
+ CsvOptionPanel.separator.tab  =  TABULATOR
+ ! MotorPlot
+ MotorPlot.title.Motorplot  =  Wykres silnika
+ MotorPlot.but.Select  =  Wybierz
+ MotorPlot.Chart.Motorthrustcurve  =  Krzywa si\u0142y ci\u0105gu silnika
+ MotorPlot.Chart.Time  =  Czas / s
+ MotorPlot.Chart.Thrust  =  Si\u0142a ci\u0105gu / N
+ MotorPlot.txt.Designation  =  Oznaczenie:
+ MotorPlot.txt.Manufacturer  =  Producent:
+ MotorPlot.txt.Type  =  Typ:
+ MotorPlot.txt.Delays  =  Opó\u017Anienia:
+ MotorPlot.txt.Comment  =  Komentarz:\n
+ ! Simulation plot panel
+ simplotpanel.lbl.Presetplotconf  =  Standardowe ustawienia wykresu:
+ simplotpanel.lbl.Xaxistype  =  Typ osi X:
+ simplotpanel.lbl.Unit  =  Jednostka:
+ simplotpanel.lbl.Yaxistypes  =  Typy osi Y:
+ simplotpanel.lbl.Flightevents  =  Wydarzenia lotu:
+ simplotpanel.but.All  =  Wszystkie
+ simplotpanel.but.None  =  \u017Badne
+ simplotpanel.but.NewYaxisplottype  =  Nowy typ osi Y
+ simplotpanel.but.Plotflight  =  Narysuj wykres lotu
+ simplotpanel.lbl.Axis  =  O\u015B:
+ simplotpanel.but.ttip.Removethisplot  =  Usu\u0144 ten wykres
+ simplotpanel.Desc  =  Dane zostan\u0105 umieszczone na wykresie w porz\u0105dku chronologicznym, nawet je\u017Celi o\u015B X nie jest typu czasowego.
+ simplotpanel.OptionPane.lbl1  =  Maksymalna liczba wykresów to 15.
+ simplotpanel.OptionPane.lbl2  =  Nie mo\u017Cna doda\u0107 wykresu
+ simplotpanel.AUTO_NAME  =  Auto
+ simplotpanel.LEFT_NAME  =  Lewo
+ simplotpanel.RIGHT_NAME  =  Prawo
+ simplotpanel.CUSTOM  =  Dowolny
+ SimulationPlotPanel.error.noPlotSelected  =  Dodaj co najmniej jedn\u0105 zmienn\u0105 do umieszczenia na osi Y.
+ SimulationPlotPanel.error.noPlotSelected.title  =  Brak danych nadaj\u0105cych si\u0119 do stworzenia wykresu
+ ! Component add buttons
+ compaddbuttons.Bodycompandfinsets  =  Cz\u0119\u015Bci sk\u0142adowe korpusu i zestawy stateczników
+ compaddbuttons.Nosecone  =  G\u0142owica
+ compaddbuttons.Bodytube  =  Korpus rakiety
+ compaddbuttons.Transition  =  Talia przej\u015Bciowa
+ compaddbuttons.Trapezoidal  =  Trapezoidalny
+ compaddbuttons.Elliptical  =  Eliptyczny
+ compaddbuttons.Freeform  =  Kszta\u0142t niestandardowy
+ compaddbuttons.Launchlug  =  Zaczep startowy
+ compaddbuttons.Innercomponent  =  Cz\u0119\u015B\u0107 wewn\u0119trzna 
+ compaddbuttons.Innertube  =  Rura wewn\u0119trzna
+ compaddbuttons.Coupler  =  \u0141\u0105cznik
+ compaddbuttons.Centeringring  =  Pier\u015Bcie\u0144\ncentruj\u0105cy
+ compaddbuttons.Bulkhead  =  Przegroda
+ compaddbuttons.Engineblock  =  Blokada\nsilnika
+ compaddbuttons.Massobjects  =  Balasty
+ compaddbuttons.Parachute  =  Spadochron
+ compaddbuttons.Streamer  =  Ta\u015Bma
+ compaddbuttons.Shockcord  =  Linka amortyzuj\u0105ca
+ compaddbuttons.Masscomponent  =  Balast\n
+ compaddbuttons.Donotaskmeagain  =  Nie pytaj ponownie
+ compaddbuttons.Selectcomppos  =  Wybierz po\u0142o\u017Cenie cz\u0119\u015Bci
+ compaddbuttons.lbl.Youcanchange  =  Domy\u015Bln\u0105 operacj\u0119 mo\u017Cna zmieni\u0107 w ustawieniach.
+ compaddbuttons.lbl.insertcomp  =  Wstawi\u0107 cz\u0119\u015B\u0107 za obecn\u0105 cz\u0119\u015Bci\u0105, czy na ko\u0144cu?
+ compaddbuttons.askPosition.Inserthere  =  Wstaw tutaj
+ compaddbuttons.askPosition.Addtotheend  =  Dodaj na ko\u0144cu
+ compaddbuttons.askPosition.Cancel  =  Anuluj
+ ! Component Analysis Dialog
+ componentanalysisdlg.componentanalysis  =  Analiza cz\u0119\u015Bci
+ componentanalysisdlg.lbl.winddir  =  Kierunek wiatru:
+ componentanalysisdlg.TitledBorder.warnings  =  Ostrze\u017Cenia:
+ componentanalysisdlg.ToggleBut.worst  =  Najgorszy
+ componentanalysisdlg.lbl.angleofattack  =  K\u0105t natarcia:
+ componentanalysisdlg.lbl.machnumber  =  Liczba Macha:
+ componentanalysisdlg.lbl.rollrate  =  Tempo obrotu:
+ componentanalysisdlg.lbl.activestages  =  Aktywne stopnie:
+ componentanalysisdlg.lbl.motorconf  =  Konfiguracja silnika:
+ componentanalysisdlg.TabStability.Col  =  Cz\u0119\u015B\u0107
+ componentanalysisdlg.TabStability  =  Stabilno\u015B\u0107
+ componentanalysisdlg.TabStability.ttip  =  Informacje dotycz\u0105ce stabilno\u015Bci
+ componentanalysisdlg.dragTableModel.Col.Component  =  Cz\u0119\u015B\u0107
+ componentanalysisdlg.dragTableModel.Col.Pressure  =  <html>Ci\u015Bnienie C<sub>D</sub>
+ componentanalysisdlg.dragTableModel.Col.Base  =  <html>Baza C<sub>D</sub>
+ componentanalysisdlg.dragTableModel.Col.friction  =  <html>Tarcie C<sub>D</sub>
+ componentanalysisdlg.dragTableModel.Col.total  =  <html>Razem C<sub>D</sub>
+ componentanalysisdlg.dragTabchar  =  Charakterystyka oporu
+ componentanalysisdlg.dragTabchar.ttip  =  Charakterystyka oporu
+ componentanalysisdlg.rollTableModel.Col.component  =  Cz\u0119\u015B\u0107
+ componentanalysisdlg.rollTableModel.Col.rollforc  =  Wspó\u0142czynnik wymuszania obrotu
+ componentanalysisdlg.rollTableModel.Col.rolldamp  =  Wspó\u0142czynnik hamowania obrotu
+ componentanalysisdlg.rollTableModel.Col.total  =  <html>Razem C<sub>I</sub>
+ componentanalysisdlg.rollTableModel  =  Dynamika obrotu
+ componentanalysisdlg.rollTableModel.ttip  =  Dynamika obrotu
+ componentanalysisdlg.println.closingmethod  =  Metoda zamykania:
+ componentanalysisdlg.println.settingnam  =  USTAWIANIE WARTO\u015ACI NAN
+ componentanalysisdlg.lbl.reflenght  =  D\u0142ugo\u015B\u0107 wzorcowa:
+ componentanalysisdlg.lbl.refarea  =  Powierzchnia wzorcowa:
+ !componentanalysisdlg.But.close 
+ componentanalysisdlg.TabStability.Col.Component  =  Cz\u0119\u015B\u0107
+ ! Custom Material dialog
+ custmatdlg.title.Custommaterial  =  Materia\u0142 niestandardowy
+ custmatdlg.lbl.Materialname  =  Nazwa materia\u0142u:
+ custmatdlg.lbl.Materialtype  =  Rodzaj materia\u0142u:
+ custmatdlg.lbl.Materialdensity  =  G\u0119sto\u015B\u0107 materia\u0142u:
+ custmatdlg.checkbox.Addmaterial  =  Dodaj materia\u0142 do bazy danych
+ ! Ring Component Config
+ ringcompcfg.OuterRadius  =  Promie\u0144 zewn\u0119trzny
+ ringcompcfg.Automatic  =  Automatyczne
+ ringcompcfg.InnerRadius  =  Promie\u0144 wewn\u0119trzny 
+ ringcompcfg.Thickness  =  Grubo\u015B\u0107
+ ringcompcfg.Length  =  D\u0142ugo\u015B\u0107
+ ringcompcfg.Positionrelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ ringcompcfg.plus  =  plus
+ ringcompcfg.PositionValue  =  Warto\u015B\u0107 po\u0142o\u017Cenia
+ ringcompcfg.Radialdistance  =  Odleg\u0142o\u015B\u0107 wzgl\u0119dem \u015Brodka:
+ ringcompcfg.Distancefrom  =  Odleg\u0142o\u015B\u0107 od osi centralnej rakiety
+ ringcompcfg.Radialdirection  =  Kierunek wzgl\u0119dem \u015Brodka:
+ ringcompcfg.radialdirectionfrom  =  Kierunek prostopad\u0142y do osi centralnej rakiety
+ ringcompcfg.but.Reset  =  Reset
+ ringcompcfg.but.Resetcomponant  =  Resetuj po\u0142o\u017Cenie cz\u0119\u015Bci wzgl\u0119dem osi rakiety
+ ringcompcfg.EngineBlock.desc  =  <html><b>Blokada silnika</b> unieruchamia silnik wewn\u0105trz elementu pe\u0142ni\u0105cego funkcj\u0119 gniazda silnikowego.<br><br>Aby doda\u0107 silnik, stwórz najpierw <b>Korpus rakiety</b> lub <b>rur\u0119 wewn\u0119trzn\u0105</b> i oznacz j\u0105 jako gniazdo silnika w zak\u0142adce <em>Silnik</em>.
+ ringcompcfg.note.desc  =  Uwaga: Rura wewn\u0119trzna nie wp\u0142ywa na aerodynamik\u0119 rakiety, nawet je\u017Celi znajduje si\u0119 poza korpusem.
+ ! Body Tube Config
+ BodyTubecfg.lbl.Bodytubelength  =  D\u0142ugo\u015B\u0107 korpusu:
+ BodyTubecfg.lbl.Outerdiameter  =  \u015Arednica zewn\u0119trzna:
+ BodyTubecfg.lbl.Innerdiameter  =  \u015Arednica wewn\u0119trzna:
+ BodyTubecfg.lbl.Wallthickness  =  Grubo\u015B\u0107 \u015Bciany:
+ BodyTubecfg.tab.General  =  Ogólne
+ BodyTubecfg.tab.Generalproperties  =  Ogólne w\u0142a\u015Bciwo\u015Bci
+ BodyTubecfg.tab.Motor  =  Silnik
+ BodyTubecfg.tab.Motormountconf  =  Konfiguracja gniazda silnika
+ BodyTubecfg.checkbox.Automatic  =  Auto
+ BodyTubecfg.checkbox.Filled  =  Wype\u0142nione
+ ! FinSetConfig
+ FinSetConfig.tab.Fintabs  =  Wypustki statecznika
+ FinSetConfig.tab.Through-the-wall  =  Wypustki przez\u015Bcienne stateczników
+ FinSetConfig.but.Converttofreeform  =  Zamie\u0144 na kszta\u0142t niestandardowy
+ FinSetConfig.but.Converttofreeform.ttip  =  Zmie\u0144 bie\u017C\u0105cy zestaw stateczników na niestandardowy
+ FinSetConfig.Convertfinset  =  Zmie\u0144 zestaw stateczników
+ FinSetConfig.but.Splitfins  =  Rozdziel stateczniki
+ FinSetConfig.but.Splitfins.ttip  =  Rozdziel zestaw stateczników na pojedyncze stateczniki
+ FinSetConfig.but.AutoCalc  =  Oblicz automatycznie
+ FinSetConfig.lbl.Through-the-wall   =  Wypustki przez\u015Bcienne stateczników:
+ FinSetConfig.lbl.Tablength = Dugo\u015B\u0107 wypustki
+ FinSetConfig.ttip.Tablength  =  D\u0142ugo\u015B\u0107 wypustki statecznika.
+ FinSetConfig.lbl.Tabheight  =  Wysoko\u015B\u0107 wypustki
+ FinSetConfig.ttip.Tabheight  =  Wysoko\u015B\u0107 wypustki statecznika w p\u0142aszczy\u017Anie prostopad\u0142ej do korpusu.
+ FinSetConfig.lbl.Tabposition  =  Po\u0142o\u017Cenie wypustki:
+ FinSetConfig.ttip.Tabposition  =  Po\u0142o\u017Cenie wypustki statecznika.
+ FinSetConfig.lbl.relativeto  =  w stosunku do
+ !FinMarkingGuide
+ FinMarkingGuide.lbl.Front  =  Przód
+ ! MotorDatabaseLoadingDialog
+ MotorDbLoadDlg.title  =  Wgrywanie silników
+ MotorDbLoadDlg.Loadingmotors  =  Wgrywanie silników...
+ ! RocketConfig
+ RocketCfg.lbl.Designname  =  Nazwa projektu:
+ RocketCfg.lbl.Designer  =  Projektant:
+ RocketCfg.lbl.Comments  =  Uwagi:
+ RocketCfg.lbl.Revisionhistory  =  Historia zmian:
+ RocketCfg.lbl.Material  =  Materia\u0142:
+ ! ShockCordConfig
+ ShockCordCfg.lbl.Shockcordlength  =  D\u0142ugo\u015B\u0107 linki amortyzuj\u0105cej
+ ! RocketComponentConfig
+ RocketCompCfg.lbl.Componentname  =  Nazwa cz\u0119\u015Bci:
+ RocketCompCfg.ttip.Thecomponentname  =  Nazwa cz\u0119\u015Bci sk\u0142adowej rakiety.
+ RocketCompCfg.tab.Override  =  Wymu\u015B
+ RocketCompCfg.tab.MassandCGoverride  =  Opcje wymuszenia ci\u0119\u017Caru oraz \u015Brodka ci\u0119\u017Cko\u015Bci
+ RocketCompCfg.tab.Figure  =  Wygl\u0105d
+ RocketCompCfg.tab.Figstyleopt  =  Styl kszta\u0142tu
+ RocketCompCfg.tab.Comment  =  Uwagi
+ RocketCompCfg.tab.Specifyacomment  =  Dodaj uwagi do cz\u0119\u015Bci
+ RocketCompCfg.lbl.Mass  =  Masa:
+ RocketCompCfg.lbl.Componentmass  =  Masa cz\u0119\u015Bci:
+ RocketCompCfg.lbl.overriddento  =  (wymuszone do
+ RocketCompCfg.lbl.overriddenby  =  (wymuszone przez
+ RocketCompCfg.lbl.Componentmaterial  =  Materia\u0142 cz\u0119\u015Bci:
+ RocketCompCfg.lbl.Componentfinish  =  Wyko\u0144czenie cz\u0119\u015Bci:
+ RocketCompCfg.lbl.ttip.componentmaterialaffects  =  Materia\u0142 cz\u0119\u015Bci ma wp\u0142yw na jej ci\u0119\u017Car.
+ RocketCompCfg.combo.ttip.componentmaterialaffects  =  Materia\u0142 cz\u0119\u015Bci ma wp\u0142yw na jej ci\u0119\u017Car.
+ RocketCompCfg.lbl.longA1  =  <html>Wyko\u0144czenie cz\u0119\u015Bci ma wp\u0142yw na jej opór aerodynamiczny.<br>
+ RocketCompCfg.lbl.longA2  =  Wskazana warto\u015B\u0107 okre\u015Bla przeci\u0119tn\u0105 chropowato\u015B\u0107 powierzchni.
+ RocketCompCfg.but.Setforall  =  Ustaw dla wszystkich
+ RocketCompCfg.but.ttip.Setforall  =  Nadaj to wyko\u0144czenie wszystkim cz\u0119\u015Bci\u0105 sk\u0142adow\u0105 rakiety.
+ RocketCompCfg.lbl.Overridemassorcenter  =  Wymu\u015B ci\u0119\u017Car b\u0105d\u017A \u015Brodek ci\u0119\u017Cko\u015Bci dla 
+ RocketCompCfg.checkbox.Overridemass  =  Wymu\u015B ci\u0119\u017Car:
+ RocketCompCfg.checkbox.Overridecenterofgrav  =  Wymu\u015B \u015Brodek ci\u0119\u017Cko\u015Bci:
+ RocketCompCfg.checkbox.OverridemassandCG  =  Wymu\u015B ci\u0119\u017Car oraz \u015Brodek ci\u0119\u017Cko\u015Bci wszystkich dodatkowych cz\u0119\u015Bci sk\u0142adowych
+ RocketCompCfg.lbl.longB1  =  <html>Wymuszony ci\u0119\u017Car nie uwzgl\u0119dnia silników.<br>
+ RocketCompCfg.lbl.longB2  =  \u015Arodek ci\u0119\u017Cko\u015Bci jest mierzony od przodu 
+ RocketCompCfg.lbl.Commentsonthe  =  Uwagi -
+ RocketCompCfg.lbl.Figurestyle  =  Styl wygl\u0105du:
+ RocketCompCfg.lbl.Componentcolor  =  Kolor cz\u0119\u015Bci:
+ RocketCompCfg.lbl.Choosecolor  =  Wybierz kolor
+ RocketCompCfg.checkbox.Usedefaultcolor  =  Ustaw kolor domy\u015Blny
+ RocketCompCfg.lbl.Complinestyle  =  Styl linii:
+ RocketCompCfg.but.Saveasdefstyle  =  Zapisz jako styl domy\u015Blny
+ RocketCompCfg.lbl.Diameter  =  \u015Arednica:
+ RocketCompCfg.lbl.Length  =  D\u0142ugo\u015B\u0107:
+ RocketCompCfg.lbl.Thickness  =  Grubo\u015B\u0107:
+ RocketCompCfg.checkbox.Endcapped  =  Zasklepiony koniec
+ RocketCompCfg.ttip.Endcapped  =  Czy koniec wpustu jest zasklepiony.
+ RocketCompCfg.title.Noseconeshoulder  =  Wpust g\u0142owicy
+ RocketCompCfg.title.Aftshoulder  =  Wpust tylny
+ RocketCompCfg.border.Foreshoulder  =  Wpust przedni
+ !RocketCompCfg.lbl.Length 
+ ! BulkheadConfig
+ BulkheadCfg.tab.Diameter  =  \u015Arednica:
+ BulkheadCfg.tab.Thickness  =  Grubo\u015B\u0107:
+ BulkheadCfg.tab.General  =  Ogólne
+ BulkheadCfg.tab.Generalproperties  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ !CenteringRingConfig
+ CenteringRingCfg.tab.Outerdiam  =  \u015Arednica zewn\u0119trzna:
+ CenteringRingCfg.tab.Innerdiam  =  \u015Arednica wewn\u0119trzna:
+ CenteringRingCfg.tab.Thickness  =  Grubo\u015B\u0107:
+ CenteringRingCfg.tab.General  =  Ogólne
+ CenteringRingCfg.tab.Generalproperties  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ !ComponentConfigDialog
+ ComponentCfgDlg.configuration  =  konfiguracja
+ ComponentCfgDlg.configuration1  = 
+ ComponentCfgDlg.Modify  =  Zmodyfikuj
+ !StageConfig
+ StageConfig.tab.Separation  =  Separacja
+ StageConfig.tab.Separation.ttip  =  Opcje oddzielenia cz\u0142onu
+ StageConfig.separation.lbl.title  =  Ustal moment oddzielenia cz\u0142onu:
+ StageConfig.separation.lbl.plus  =  plus
+ StageConfig.separation.lbl.seconds  =  sek.
+ !EllipticalFinSetConfig
+ EllipticalFinSetCfg.Nbroffins  =  Liczba stateczników:
+ EllipticalFinSetCfg.Rotation  =  Rotacja:
+ EllipticalFinSetCfg.Fincant  =  Nachylenie stateczników:
+ EllipticalFinSetCfg.Rootchord  =  Kraw\u0119d\u017A podstawy:
+ EllipticalFinSetCfg.Height  =  Wysoko\u015B\u0107:
+ EllipticalFinSetCfg.Positionrelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ EllipticalFinSetCfg.plus  =  plus
+ EllipticalFinSetCfg.FincrossSection  =  Przekrój statecznika:
+ EllipticalFinSetCfg.Thickness  =  Grubo\u015B\u0107:
+ EllipticalFinSetCfg.General  =  Ogólne
+ EllipticalFinSetCfg.Generalproperties  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ EllipticalFinSetCfg.ttip.Fincant  =  K\u0105t nachylenia stateczników wzgl\u0119dem korpusu.
+ !FreeformFinSetConfig
+ FreeformFinSetCfg.tab.General  =  Ogólne
+ FreeformFinSetCfg.tab.ttip.General  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ FreeformFinSetCfg.tab.Shape  =  Kszta\u0142t
+ FreeformFinSetCfg.tab.ttip.Finshape  =  Kszta\u0142t stateczników
+ FreeformFinSetCfg.lbl.Numberoffins  =  Liczba stateczników:
+ FreeformFinSetCfg.lbl.Finrotation  =  Rotacja stateczników:
+ FreeformFinSetCfg.lbl.Fincant  =  Nachylenie stateczników:
+ FreeformFinSetCfg.lbl.ttip.Fincant  =  K\u0105t nachylenia stateczników wzgl\u0119dem korpusu.
+ FreeformFinSetCfg.lbl.Posrelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ FreeformFinSetCfg.lbl.plus  =  plus
+ FreeformFinSetCfg.lbl.FincrossSection  =  Przekrój statecznika:
+ FreeformFinSetCfg.lbl.Thickness  =  Grubo\u015B\u0107:
+ ! doubleClick1 + 2 form the message "Double-click to edit", split approximately at the middle
+ FreeformFinSetConfig.lbl.doubleClick1  =  Kliknij dwukrotnie
+ FreeformFinSetConfig.lbl.doubleClick2  =  aby edytowa\u0107
+ FreeformFinSetConfig.lbl.clickDrag  =  Kliknij i przeci\u0105gnij: Dodaj i przesuwaj punkty
+ FreeformFinSetConfig.lbl.ctrlClick  =  Ctrl+klik: Usu\u0144 punkt
+ FreeformFinSetConfig.lbl.scaleFin  =  Skaluj statecznik
+ !InnerTubeConfig
+ InnerTubeCfg.tab.Motor  =  Silnik
+ InnerTubeCfg.tab.ttip.Motor  =  Konfiguracja gniazda silnika
+ InnerTubeCfg.tab.Cluster  =  Grupa
+ InnerTubeCfg.tab.ttip.Cluster  =  Konfiguracja grupy
+ InnerTubeCfg.tab.Radialpos  =  Po\u0142o\u017Cenie wzgl\u0119dem \u015Brodka
+ InnerTubeCfg.tab.ttip.Radialpos  =  Po\u0142o\u017Cenie wzgl\u0119dem \u015Brodka
+ InnerTubeCfg.lbl.Selectclustercfg  =  Wybierz konfiguracj\u0119 grupy:
+ InnerTubeCfg.lbl.TubeSep  =  Separacja rur:
+ InnerTubeCfg.lbl.ttip.TubeSep  =  Separacja rur, 1,0 
+ InnerTubeCfg.lbl.Rotation  =  Rotacja:
+ InnerTubeCfg.lbl.ttip.Rotation  =  Konfiguracja k\u0105ta rotacji grupy
+ InnerTubeCfg.lbl.Rotangle  =  Konfiguracja k\u0105ta rotacji grupy
+ InnerTubeCfg.but.Splitcluster  =  Rozdziel grup\u0119
+ InnerTubeCfg.lbl.longA1  =  <html>Rozdziel grup\u0119 na oddzielne cz\u0119\u015Bci.<br>
+ InnerTubeCfg.lbl.longA2  =  To polecenie powoduje równie\u017C duplikacj\u0119 wszystkich cz\u0119\u015Bci do\u0142\u0105czonych do danej rury wewn\u0119trznej.
+ InnerTubeCfg.but.Resetsettings  =  Przywró\u0107 ustawienia domy\u015Blne
+ InnerTubeCfg.but.ttip.Resetsettings  =  Przywró\u0107 oddzielenie oraz rotacje do ich warto\u015Bci domy\u015Blnych
+ ! LaunchLugConfig
+ LaunchLugCfg.lbl.Length  =  D\u0142ugo\u015B\u0107:
+ LaunchLugCfg.lbl.Outerdiam  =  \u015Arednica zewn\u0119trzna:
+ LaunchLugCfg.lbl.Innerdiam  =  \u015Arednica wewn\u0119trzna:
+ LaunchLugCfg.lbl.Thickness  =  Grubo\u015B\u0107:
+ LaunchLugCfg.lbl.Radialpos  =  Po\u0142o\u017Cenie wzgl\u0119dem \u015Brodka:
+ LaunchLugCfg.lbl.Posrelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ LaunchLugCfg.lbl.plus  =  plus
+ LaunchLugCfg.tab.General  =  Ogólne
+ LaunchLugCfg.tab.Generalprop  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ ! MassComponentConfig
+ MassComponentCfg.lbl.Mass  =  Masa:
+ MassComponentCfg.lbl.Length  =  D\u0142ugo\u015B\u0107:
+ MassComponentCfg.lbl.Diameter  =  \u015Arednica:
+ MassComponentCfg.lbl.PosRelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ MassComponentCfg.lbl.plus  =  plus
+ MassComponentCfg.tab.General  =  Ogólne
+ MassComponentCfg.tab.ttip.General  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ MassComponentCfg.tab.Radialpos  =  Po\u0142o\u017Cenie wzgl\u0119dem \u015Brodka
+ MassComponentCfg.tab.ttip.Radialpos  =  Konfiguracja po\u0142o\u017Cenia wzgl\u0119dem \u015Brodka
+ MassComponentCfg.lbl.Radialdistance  =  Odleg\u0142o\u015B\u0107 wzgl\u0119dem \u015Brodka:
+ MassComponentCfg.lbl.Radialdirection  =  Kierunek wzgl\u0119dem \u015Brodka:
+ MassComponentCfg.but.Reset  =  Reset
+ ! MotorConfig
+ MotorCfg.checkbox.compmotormount  =  Ta cz\u0119\u015B\u0107 jest gniazdem silnika
+ MotorCfg.lbl.Motorcfg  =  Konfiguracja silnika:
+ MotorCfg.but.New  =  Nowy
+ MotorCfg.lbl.Currentmotor  =  Obecny silnik:
+ MotorCfg.lbl.Motoroverhang  =  Wysuni\u0119cie silnika:
+ MotorCfg.lbl.Ignitionat  =  Zap\u0142on w chwili:
+ MotorCfg.lbl.plus  =  plus
+ MotorCfg.lbl.seconds  =  sek.
+ MotorCfg.lbl.longA1  =  Obecny model ma tylko jeden stopie\u0144.
+ MotorCfg.lbl.longA2  =  Stopnie mog\u0105 by\u0107 dodawane poprzez klikni\u0119cie \"Nowy stopie\u0144\".
+ MotorCfg.lbl.longB1  =  Obecny model ma
+ MotorCfg.lbl.longB2  =  stopnie.
+ MotorCfg.but.Selectmotor  =  Wybierz silnik
+ MotorCfg.but.Removemotor  =  Usu\u0144 silnik
+ MotorCfg.lbl.motorLabel  =  \u017Badne
+ ! NoseConeConfig
+ NoseConeCfg.lbl.Noseconeshape  =  Kszta\u0142t g\u0142owicy:
+ NoseConeCfg.lbl.Shapeparam  =  Parametr kszta\u0142tu
+ NoseConeCfg.lbl.Noseconelength  =  D\u0142ugo\u015B\u0107 g\u0142owicy:
+ NoseConeCfg.lbl.Basediam  =  \u015Arednica podstawy:
+ NoseConeCfg.checkbox.Automatic  =  Auto
+ NoseConeCfg.lbl.Wallthickness  =  Grubo\u015B\u0107 \u015Bciany:
+ NoseConeCfg.checkbox.Filled  =  Wype\u0142nione
+ NoseConeCfg.tab.General  =  Ogólne
+ NoseConeCfg.tab.ttip.General  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ NoseConeCfg.tab.Shoulder  =  Wpust
+ NoseConeCfg.tab.ttip.Shoulder  =  Parametry wpustu
+ ! ParachuteConfig
+ ParachuteCfg.lbl.Canopy  =  Czasza:
+ ParachuteCfg.lbl.Diameter  =  \u015Arednica:
+ ParachuteCfg.lbl.Material  =  Materia\u0142:
+ ParachuteCfg.combo.MaterialModel  =  Materia\u0142 cz\u0119\u015Bci ma wp\u0142yw na jej ci\u0119\u017Car.
+ ParachuteCfg.lbl.longA1  =  <html>Wspó\u0142czynnik oporu C<sub>D</sub>
+ ParachuteCfg.lbl.longB1  =  <html>Wspó\u0142czynnik oporu na jednostk\u0119 powierzchni ta\u015Bmy.<br>
+ ParachuteCfg.lbl.longB2  =  Du\u017Cy wspó\u0142czynnik oporu skutkuje zmniejszeniem szybko\u015Bci opadania.
+ ParachuteCfg.lbl.longB3  =  Standardowa wielko\u015B\u0107 dla spadochronów wynosi 0.8.
+ ParachuteCfg.but.Reset  =  Reset
+ ParachuteCfg.lbl.Shroudlines  =  Linki no\u015Bne:
+ ParachuteCfg.lbl.Numberoflines  =  Liczba linek:
+ ParachuteCfg.lbl.Linelength  =  D\u0142ugo\u015B\u0107 linek:
+ ParachuteCfg.lbl.Material  =  Materia\u0142:
+ ParachuteCfg.lbl.Posrelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ ParachuteCfg.lbl.plus  =  plus
+ ParachuteCfg.lbl.Packedlength  =  D\u0142ugo\u015B\u0107 po zwini\u0119ciu:
+ ParachuteCfg.lbl.Packeddiam  =  \u015Arednica po zwini\u0119ciu:
+ ParachuteCfg.lbl.Deploysat  =  Aktywacja w chwili:
+ ParachuteCfg.lbl.seconds  =  sek.
+ ParachuteCfg.lbl.Altitude  =  Wysoko\u015B\u0107:
+ ParachuteCfg.tab.General  =  Ogólne
+ ParachuteCfg.tab.ttip.General  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ ParachuteCfg.tab.Radialpos  =  Po\u0142o\u017Cenie wzgl\u0119dem \u015Brodka
+ ParachuteCfg.tab.ttip.Radialpos  =  Konfiguracja po\u0142o\u017Cenia wzgl\u0119dem \u015Brodka
+ ParachuteCfg.lbl.Radialdistance  =  Odleg\u0142o\u015B\u0107 od \u015Brodka:
+ ParachuteCfg.lbl.Radialdirection  =  Kierunek wzgl\u0119dem \u015Brodka:
+ ParachuteCfg.but.Reset  =  Reset
+ ParachuteCfg.lbl.plusdelay  =  plus
+ ! ShockCordConfig
+ ShockCordCfg.lbl.Shockcordlength  =  D\u0142ugo\u015B\u0107 linki amortyzuj\u0105cej
+ ShockCordCfg.lbl.Shockcordmaterial = Materia\u0142 linki amortyzuj\u0105cej:
+ ShockCordCfg.lbl.Posrelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ ShockCordCfg.lbl.plus  =  plus
+ ShockCordCfg.lbl.Packedlength  =  D\u0142ugo\u015B\u0107 po zwini\u0119ciu:
+ ShockCordCfg.lbl.Packeddiam  =  \u015Arednica po zwini\u0119ciu:
+ ShockCordCfg.tab.General  =  Ogólne
+ ShockCordCfg.tab.ttip.General  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ !SleeveConfig
+ SleeveCfg.tab.Outerdiam  =  \u015Arednica zewn\u0119trzna:
+ SleeveCfg.tab.Innerdiam  =  \u015Arednica wewn\u0119trzna:
+ SleeveCfg.tab.Wallthickness  =  Grubo\u015B\u0107 \u015Bciany:
+ SleeveCfg.tab.Length  =  D\u0142ugo\u015B\u0107:
+ SleeveCfg.tab.General  =  Ogólne
+ SleeveCfg.tab.Generalproperties  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ ! StreamerConfig
+ StreamerCfg.lbl.Striplength  =  D\u0142ugo\u015B\u0107 paska:
+ StreamerCfg.lbl.Stripwidth  =  Szeroko\u015B\u0107 paska:
+ StreamerCfg.lbl.Striparea  =  Powierzchnia paska:
+ StreamerCfg.lbl.Aspectratio  =  Format:
+ StreamerCfg.lbl.Material  =  Materia\u0142:
+ StreamerCfg.combo.ttip.MaterialModel  =  Materia\u0142 cz\u0119\u015Bci ma wp\u0142yw na jej ci\u0119\u017Car.
+ StreamerCfg.lbl.longA1  =  <html>Wspó\u0142czynnik oporu C<sub>D</sub>
+ StreamerCfg.lbl.longB1  =  <html>Wspó\u0142czynnik oporu na jednostk\u0119 powierzchni ta\u015Bmy.<br>
+ StreamerCfg.lbl.longB2  =  Du\u017Cy wspó\u0142czynnik oporu skutkuje zmniejszeniem szybko\u015Bci opadania.
+ StreamerCfg.lbl.Automatic  =  Auto
+ StreamerCfg.lbl.longC1  =  Wspó\u0142czynnik oporu zale\u017Cy od powierzchni ta\u015Bmy.
+ StreamerCfg.lbl.Posrelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ StreamerCfg.lbl.plus  =  plus
+ StreamerCfg.lbl.Packedlength  =  D\u0142ugo\u015B\u0107 po zwini\u0119ciu:
+ StreamerCfg.lbl.Packeddiam  =  \u015Arednica po zwini\u0119ciu:
+ StreamerCfg.lbl.Deploysat  =  Aktywacja w chwili:
+ StreamerCfg.lbl.seconds  =  sek.
+ StreamerCfg.lbl.Altitude  =  Wysoko\u015B\u0107:
+ StreamerCfg.tab.General  =  Ogólne
+ StreamerCfg.tab.ttip.General  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ StreamerCfg.tab.Radialpos  =  Po\u0142o\u017Cenie wzgl\u0119dem \u015Brodka
+ StreamerCfg.tab.ttip.Radialpos  =  Konfiguracja po\u0142o\u017Cenia wzgl\u0119dem \u015Brodka
+ StreamerCfg.lbl.Radialdistance  =  Odleg\u0142o\u015B\u0107 od \u015Brodka:
+ StreamerCfg.lbl.Radialdirection  =  Kierunek wzgl\u0119dem \u015Brodka:
+ StreamerCfg.but.Reset  =  Reset
+ StreamerCfg.lbl.plusdelay  =  plus
+ ! ThicknessRingComponentConfig
+ ThicknessRingCompCfg.tab.Outerdiam  =  \u015Arednica zewn\u0119trzna:
+ ThicknessRingCompCfg.tab.Innerdiam  =  \u015Arednica wewn\u0119trzna:
+ ThicknessRingCompCfg.tab.Wallthickness  =  Grubo\u015B\u0107 \u015Bciany:
+ ThicknessRingCompCfg.tab.Length  =  D\u0142ugo\u015B\u0107:
+ ThicknessRingCompCfg.tab.General  =  Ogólne
+ ThicknessRingCompCfg.tab.Generalprop  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ ! TransitionConfig
+ TransitionCfg.lbl.Transitionshape  =  Kszta\u0142t talii przej\u015Bciowej
+ TransitionCfg.checkbox.Clipped  =  Przyci\u0119ta
+ TransitionCfg.lbl.Shapeparam  =  Parametr kszta\u0142tu
+ TransitionCfg.lbl.Transitionlength  =  D\u0142ugo\u015B\u0107 przej\u015Bciówki:
+ TransitionCfg.lbl.Forediam  =  \u015Arednica przednia:
+ TransitionCfg.checkbox.Automatic  =  Auto
+ TransitionCfg.lbl.Aftdiam  =  \u015Arednica tylna:
+ TransitionCfg.lbl.Wallthickness  =  Grubo\u015B\u0107 \u015Bciany:
+ TransitionCfg.checkbox.Filled  =  Wype\u0142nione
+ TransitionCfg.tab.General  =  Ogólne
+ TransitionCfg.tab.Generalproperties  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ TransitionCfg.tab.Shoulder  =  Wpust
+ TransitionCfg.tab.Shoulderproperties  =  Parametry wpustu
+ ! TrapezoidFinSetConfig
+ TrapezoidFinSetCfg.lbl.Nbroffins  =  Liczba stateczników:
+ TrapezoidFinSetCfg.lbl.ttip.Nbroffins  =  Liczba stateczników w zestawie.
+ TrapezoidFinSetCfg.lbl.Finrotation  =  Rotacja stateczników:
+ TrapezoidFinSetCfg.lbl.ttip.Finrotation  =  K\u0105t nachylenia pierwszego statecznika w zestawie.
+ TrapezoidFinSetCfg.lbl.Fincant  =  Nachylenie stateczników:
+ TrapezoidFinSetCfg.lbl.ttip.Fincant  = K\u0105t nachylenia stateczników wzgl\u0119dem korpusu.
+ TrapezoidFinSetCfg.lbl.Rootchord  =  Kraw\u0119d\u017A podstawy:
+ TrapezoidFinSetCfg.lbl.Tipchord  =  Kraw\u0119d\u017A zewn\u0119trzna:
+ TrapezoidFinSetCfg.lbl.Height  =  Wysoko\u015B\u0107:
+ TrapezoidFinSetCfg.lbl.Sweeplength  =  D\u0142ugo\u015B\u0107 przesuni\u0119cia:
+ TrapezoidFinSetCfg.lbl.Sweepangle  =  K\u0105t przesuni\u0119cia:
+ TrapezoidFinSetCfg.lbl.FincrossSection  =  Przekrój statecznika:
+ TrapezoidFinSetCfg.lbl.Thickness  =  Grubo\u015B\u0107:
+ TrapezoidFinSetCfg.lbl.Posrelativeto  =  Po\u0142o\u017Cenie wzgl\u0119dem:
+ TrapezoidFinSetCfg.lbl.plus  =  plus
+ TrapezoidFinSetCfg.tab.General  =  Ogólne
+ TrapezoidFinSetCfg.tab.Generalproperties  =  W\u0142a\u015Bciwo\u015Bci ogólne
+ !MotorConfigurationModel
+ MotorCfgModel.Editcfg  =  Edytuj konfiguracje
+ ! StorageOptionChooser
+ StorageOptChooser.lbl.Simdatatostore  =  Dane symulacji do zapisania:
+ StorageOptChooser.rdbut.Allsimdata  =  Wszystkie dane symulacji:
+ StorageOptChooser.lbl.longA1  =  <html>Zapisz wszystkie dane z symulacji.<br>
+ StorageOptChooser.lbl.longA2  =  To mo\u017Ce bardzo zwi\u0119kszy\u0107 rozmiar plików!
+ StorageOptChooser.rdbut.Every  =  Co
+ StorageOptChooser.lbl.longB1  =  <html>Zapisz warto\u015Bci daj\u0105ce si\u0119 przedstawi\u0107 na wykresie w powy\u017Cszych odst\u0119pach.<br>
+ StorageOptChooser.lbl.longB2  =  Wi\u0119ksze warto\u015Bci przek\u0142adaj\u0105 si\u0119 na mniejsze pliki.
+ StorageOptChooser.lbl.seconds  =  sek.
+ StorageOptChooser.rdbut.Onlyprimfig  =  Tylko dane podstawowe
+ StorageOptChooser.lbl.longC1  =  <html>Zapisz tylko warto\u015Bci ukazane w tabeli podsumowuj\u0105cej symulacj\u0119.<br>
+ StorageOptChooser.lbl.longC2  =  Przy tym ustawieniu pliki s\u0105 najmniejsze.
+ StorageOptChooser.checkbox.Compfile  =  Kompresuj plik
+ StorageOptChooser.lbl.UsingComp  =  Kompresowanie pliku zmniejsza znacznie jego rozmiar.
+ StorageOptChooser.lbl.longD1  =  Szacunkowy rozmiar pliku przy bie\u017C\u0105cych ustawieniach.
+ StorageOptChooser.ttip.Saveopt  =  Zapisz opcje
+ StorageOptChooser.lbl.Estfilesize  =  Przybli\u017Cony rozmiar pliku:
+ StorageOptChooser.lbl.Saveopt  =  Zapisz opcje
+ ! ThrustCurveMotorSelectionPanel
+ TCMotorSelPan.lbl.Selrocketmotor  =  Wybierz silnik rakiety:
+ TCMotorSelPan.checkbox.hideSimilar  =  Ukryj bardzo podobne krzywe ci\u0105gu.
+ TCMotorSelPan.SHOW_DESCRIPTIONS.desc1  =  Poka\u017C wszystkie silniki
+ TCMotorSelPan.SHOW_DESCRIPTIONS.desc2  =  Poka\u017C silniki ze \u015Brednic\u0105 mniejsza ni\u017C \u015Brednica gniazda silnika
+ TCMotorSelPan.SHOW_DESCRIPTIONS.desc3  =  Poka\u017C silniki ze \u015Brednic\u0105 równa \u015Brednicy gniazda silnika
+ TCMotorSelPan.lbl.Motormountdia  =  \u015Arednica gniazda silnika:
+ TCMotorSelPan.lbl.Search  =  Szukaj:
+ TCMotorSelPan.lbl.Selectthrustcurve  =  Wybierz krzyw\u0105 si\u0142y ci\u0105gu:
+ TCMotorSelPan.lbl.Ejectionchargedelay  =  Opó\u017Anienie odpalenia \u0142adunku odrzucaj\u0105cego:
+ TCMotorSelPan.equalsIgnoreCase.None  =  \u017Badne
+ TCMotorSelPan.lbl.NumberofsecondsorNone  =  (liczba sekund lub \"Brak\")
+ TCMotorSelPan.lbl.Totalimpulse  =  Ca\u0142kowity impuls:
+ TCMotorSelPan.lbl.Avgthrust  =  \u015Arednia si\u0142a ci\u0105gu:
+ TCMotorSelPan.lbl.Maxthrust  =  Maks. si\u0142a ci\u0105gu:
+ TCMotorSelPan.lbl.Burntime  =  Czas spalania paliwa w silniku:
+ TCMotorSelPan.lbl.Launchmass  =  Masa startowa:
+ TCMotorSelPan.lbl.Emptymass  =  Masa pustej rakiety:
+ TCMotorSelPan.lbl.Datapoints  =  Punkty pomiarowe:
+ TCMotorSelPan.lbl.Digest  =  Podsumowanie:
+ TCMotorSelPan.title.Thrustcurve  =  Krzywa si\u0142y ci\u0105gu:
+ TCMotorSelPan.title.Thrust  =  Ci\u0105g
+ TCMotorSelPan.delayBox.None  =  \u017Badne
+ ! PlotDialog
+ PlotDialog.title.Flightdataplot  =  Wykres danych lotu
+ PlotDialog.Chart.Simulatedflight  =  Lot symulowany
+ PlotDialog.CheckBox.Showdatapoints  =  Poka\u017C punkty pomiarowe
+ PlotDialog.lbl.Chart  =  Kliknij i przeci\u0105gnij w dó\u0142 + prawo aby powi\u0119kszy\u0107; góra + lewo aby pomniejszy\u0107
+ ! "main" prefix is used for the main application dialog
+ # FIXME: Rename the description keys
+ main.menu.file  =  Plik
+ main.menu.file.desc  =  Czynno\u015Bci zwi\u0105zane z obs\u0142ug\u0105 plików
+ main.menu.file.new  =  Nowy
+ main.menu.file.new.desc  =  Stwórz nowy projekt rakiety
+ main.menu.file.open  =  Otwórz...
+ BasicFrame.item.Openrocketdesign  =  Otwórz projekt rakiety
+ main.menu.file.openExample  =  Otwórz przyk\u0142ad...
+ BasicFrame.item.Openexamplerocketdesign  =  Otwórz przyk\u0142adowy projekt rakiety
+ main.menu.file.save  =  Zapisz
+ BasicFrame.item.SavecurRocketdesign  =  Zapisz obecny projekt rakiety
+ main.menu.file.saveAs  =  Zapisz jako...
+ BasicFrame.item.SavecurRocketdesnewfile  =  Zapisz obecny projekt rakiety w nowym pliku
+ main.menu.file.print  =  Drukuj / Eksportuj do PDF...
+ main.menu.file.print.desc  =  Drukuj lub zapisz jako PDF list\u0119 cz\u0119\u015Bci i szablony stateczników.
+ main.menu.file.close  =  Zamknij
+ BasicFrame.item.Closedesign  =  Zamknij bie\u017C\u0105cy projekt rakiety
+ main.menu.file.quit  =  Wyjd\u017A
+ BasicFrame.item.Quitprogram  =  Wyjd\u017A z programu
+ main.menu.edit  =  Edycja
+ BasicFrame.menu.Rocketedt  =  Edytowanie rakiety
+ main.menu.edit.undo  =  Cofnij
+ main.menu.edit.undo.desc  =  Cofnij poprzedni\u0105 czynno\u015B\u0107
+ main.menu.edit.redo  =  Powtórz
+ main.menu.edit.redo.desc  =  Powtórz poprzednio cofni\u0119t\u0105 czynno\u015B\u0107
+ main.menu.edit.cut  =  Wytnij
+ main.menu.edit.copy  =  Kopiuj
+ main.menu.edit.paste  =  Wklej
+ main.menu.edit.delete  =  Usu\u0144
+ main.menu.edit.resize  =  Skaluj...
+ main.menu.edit.resize.desc  =  Skaluj cz\u0119\u015Bci modelu rakiety...
+ main.menu.edit.preferences  =  Ustawienia
+ main.menu.edit.preferences.desc  =  Edytuj ustawienia programu
+ main.menu.analyze  =  Analiza
+ main.menu.analyze.desc  =  Analiza rakiety
+ main.menu.analyze.componentAnalysis  =  Analiza cz\u0119\u015Bci
+ main.menu.analyze.componentAnalysis.desc  =  Analizuj oddzielnie poszczególne cz\u0119\u015Bci sk\u0142adóe rakiety
+ main.menu.analyze.optimization  =  Optymalizacja rakiety
+ main.menu.analyze.optimization.desc  =  Ogólna optymalizacja projektu rakiety
+ main.menu.help  =  Pomoc
+ main.menu.help.desc  =  Informacje o programie OpenRocket
+ main.menu.help.tours  =  Instrukcje krok po kroku
+ main.menu.help.tours.desc  =  Przejd\u017A przez instrukcje krok po kroku w programie OpenRocket
+ main.menu.help.license  =  Licencja
+ main.menu.help.license.desc  =  Informacja o licencji programu OpenRocket
+ main.menu.help.bugReport  =  Raport o b\u0142\u0119dach
+ main.menu.help.bugReport.desc  =  Informacja o zg\u0142aszaniu problemów, b\u0142\u0119dów i usterek w programie OpenRocket
+ main.menu.help.debugLog  =  Rejestr debuggera
+ main.menu.help.debugLog.desc  =  Przegl\u0105daj rejestr debuggera programu OpenRocket
+ main.menu.help.about  =  Informacja
+ main.menu.help.about.desc  =  Informacja o prawach autorskich do programu OpenRocket
+ main.menu.debug  =  Debugowanie
+ main.menu.debug.whatisthismenu  =  Co to za okno?
+ main.menu.debug.createtestrocket  =  Stwórz rakiet\u0119 testow\u0105
+ ! database
+ ! Translate here all material database
+ !
+ ! Material database
+ ! BULK_MATERIAL
+ material.acrylic  =  Akryl
+ material.aluminum  =  Aluminium
+ material.balsa  =  Balsa
+ material.basswood  =  Lipa
+ material.birch  =  Brzoza
+ material.brass  =  Mosi\u0105dz
+ material.cardboard  =  Karton
+ material.carbon_fiber  =  W\u0142ókno w\u0119glowe
+ material.cork  =  Korek
+ material.depron_xps  =  Depron (XPS)
+ material.fiberglass  =  W\u0142ókno szklane
+ material.kraft_phenolic  =  Kraft fenolowy
+ material.maple  =  Klon
+ material.paper_office  =  Papier (biurowy)
+ material.pine  =  Sosna
+ material.plywood_birch  =  Sklejka (brzoza)
+ material.polycarbonate_lexan  =  Poliw\u0119glan (Lexan)
+ material.polystyrene  =  Polistyren
+ material.pvc  =  PVC
+ material.spruce  =  \u015Awierk
+ material.steel  =  Stal
+ material.styrofoam_generic_eps  =  Styropian (zwyk\u0142y EPS)
+ material.styrofoam_blue_foam_xps  =  Styropian \"kolorowy\" (XPS)
+ material.titanium  =  Tytan
+ material.quantum_tubing  =  Tuby kwantowe
+ material.blue_tube  =  Blue tube
+ !SURFACE_MATERIAL
+ material.ripstop_nylon  =  Nylon Rip-stop
+ material.mylar  =  Mylar
+ material.polyethylene_thin  =  Polietylen (cienki)
+ material.polyethylene_heavy  =  Polietylen (ci\u0119\u017Cki)
+ material.silk  =  Jedwab
+ material.paper_office  =  Papier (biurowy)
+ material.cellophane  =  Celofan
+ material.crepe_paper  =  Papier marszczony, krepina
+ ! LINE_MATERIAL
+ material.thread_heavy_duty  =  Ni\u0107 (wytrzyma\u0142a)
+ material.elastic_cord_round_2_mm_1_16_in  =  Przewód elastyczny (okr\u0105g\u0142y 2mm)
+ material.elastic_cord_flat_6_mm_1_4_in  =  Przewód elastyczny (p\u0142aski 6mm)
+ material.elastic_cord_flat_12_mm_1_2_in  =  Przewód elastyczny (p\u0142aski 12 mm)
+ material.elastic_cord_flat_19_mm_3_4_in  =  Przewód elastyczny (p\u0142aski 19 mm)
+ material.elastic_cord_flat_25_mm_1_in  =  Przewód elastyczny (p\u0142aski 25mm)
+ material.braided_nylon_2_mm_1_16_in  =  Nylon spleciony (2 mm)
+ material.braided_nylon_3_mm_1_8_in  =  Nylon spleciony (3 mm)
+ material.tubular_nylon_11_mm_7_16_in  =  Nylon rurkowy (11 mm)
+ material.tubular_nylon_14_mm_9_16_in  =  Nylon rurkowy (14 mm)
+ material.tubular_nylon_25_mm_1_in  =  Nylon rurkowy (25 mm)
+ ! ExternalComponent
+ ExternalComponent.Rough  =  Chropowate
+ ExternalComponent.Unfinished  =  Niewyko\u0144czone
+ ExternalComponent.Regularpaint  =  Zwyk\u0142a farba
+ ExternalComponent.Smoothpaint  =  G\u0142adka farba
+ ExternalComponent.Polished  =  Wypolerowany
+ ! LineStyle
+ LineStyle.Solid  =  Ci\u0105g\u0142a
+ LineStyle.Dashed  =  Kreskowana
+ LineStyle.Dotted  =  Kropkowana
+ LineStyle.Dash-dotted  =  Kreska-kropka
+ LineStyle.Defaultstyle  =  Domy\u015Blny
+ ! Shape
+ Shape.Conical  =  Sto\u017Ckowy
+ Shape.Conical.desc1  =  G\u0142owica sto\u017Ckowa ma przekrój w kszta\u0142cie trójk\u0105ta.
+ Shape.Conical.desc2  =  Sto\u017Ckowa talia przej\u015Bciowa ma proste boki.
+ Shape.Ogive  =  Ostro\u0142uk
+ Shape.Ogive.desc1  =  G\u0142owica w kszta\u0142cie ostro\u0142uku ma przekrój b\u0119d\u0105cy fragmentem okr\u0119gu.  Warto\u015B\u0107 parametru kszta\u0142tu równa 1 tworzy <b>ostro\u0142uk styczny</b>, który zapewnia g\u0142adkie po\u0142\u0105czenie g\u0142owicy z korpusem rakiety. Warto\u015Bci poni\u017Cej 1 tworz\u0105 <b>ostro\u0142uki sieczne</b>.
+ Shape.Ogive.desc2  =  Talia przej\u015Bciowa w kszta\u0142cie ostro\u0142uku ma przekrój b\u0119d\u0105cy fragmentem okr\u0119gu.  
+ Shape.Ellipsoid  =  Elipsoida
+ Shape.Ellipsoid.desc1  =  G\u0142owica elipsoidalna ma przekrój w kszta\u0142cie pó\u0142elipsy o osiach g\u0142ównych o d\u0142ugo\u015Bci 2&times;<i>d\u0142ugo\u015B\u0107</i> i <i>\u015Brednica</i>.
+ Shape.Ellipsoid.desc2  =  Elipsoidalna talia przej\u015Bciowa ma przekrój w kszta\u0142cie pó\u0142elipsy o osiach g\u0142ównych o d\u0142ugo\u015Bci 2&times;<i>d\u0142ugo\u015B\u0107</i> i <i>\u015Brednica</i>.  Je\u017Celi talia przej\u015Bciowa nie jest przyci\u0119ta, to \u015Brodek przekroju jest wybrzuszony przez promie\u0144 tworz\u0105cy.
+ Shape.Powerseries  =  Seria pot\u0119gowa
+ Shape.Powerseries.desc1  =  G\u0142owica serii pot\u0119gowej ma przekrój w kszta\u0142cie: <i>promie\u0144</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>d\u0142ugo\u015B\u0107</i>)<sup><i>k</i></sup> gdzie<i>k</i> jest parametrem kszta\u0142tu.  Dla <i>k</i> równego 0,5 mamy pot\u0119g\u0119 o stopniu 1/2, co nam daje g\u0142owic\u0119 paraboliczn\u0105. Dla <i>k</i> wynosz\u0105cego 0,75 dostajemy pot\u0119g\u0119 stopnia 3/4, za\u015B dla k wynosz\u0105cego 1 otrzymujemy g\u0142owic\u0119 sto\u017Ckow\u0105.
+ Shape.Powerseries.desc2  =  Talia przej\u015Bciowa serii pot\u0119gowej ma przekrój w kszta\u0142cie: <i>promie\u0144</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>d\u0142ugo\u015B\u0107</i>)<sup><i>k</i></sup> gdzie<i>k</i> jest parametrem kszta\u0142tu.  Dla <i>k</i> równego 0,5 mamy pot\u0119g\u0119 o stopniu 1/2, co nam daje paraboliczn\u0105 tali\u0119 orzej\u015Bciow\u0105. Dla <i>k</i> wynosz\u0105cego 0,75 dostajemy pot\u0119g\u0119 stopnia 3/4, za\u015B dla k wynosz\u0105cego 1 otrzymujemy sto\u017Ckow\u0105 tali\u0119 przej\u015Bciow\u0105.
+ Shape.Parabolicseries  =  Seria paraboliczna
+ Shape.Parabolicseries.desc1  =  G\u0142owica paraboliczna ma przekrój w kszta\u0142cie paraboli.  Parametr kszta\u0142tu okre\u015Bla odcinek paraboli, który zostanie u\u017Cyty.  Warto\u015B\u0107 parametru kszta\u0142tu równa 1 tworzy <b>pe\u0142n\u0105 parabol\u0119</b>, która jest styczna do korpusu rakiety, 0,75 tworzy <b> 3/4 paraboli</b>, 0,5 tworzy <b>1/2 paraboli</b> oraz 0 tworzy g\u0142owic\u0119 <b>sto\u017Ckow\u0105</b>rakiety.
+ Shape.Parabolicseries.desc2  =  Talia przej\u015Bciowa paraboliczna ma przekrój w kszta\u0142cie paraboli.  Parametr kszta\u0142tu okre\u015Bla odcinek paraboli, który zostanie u\u017Cyty.  Warto\u015B\u0107 parametru kszta\u0142tu równa 1 tworzy <b>pe\u0142n\u0105 parabole</b>, która jest styczna do tylnego ko\u0144ca, 0,75 tworzy <b> 3/4 paraboli</b>, 0,5 tworzy <b>1/2 paraboli</b> oraz 0 tworzy <b>sto\u017Ckow\u0105</b> tali\u0119 przej\u015Bciow\u0105 
+ Shape.Haackseries  =  Seria Haacka
+ Shape.Haackseries.desc1  =  Seria g\u0142owic Haacka zosta\u0142a tak zaprojektowana, aby osi\u0105gn\u0105\u0107 minimalny opór.  Warto\u015B\u0107 parametru kszta\u0142tu równa 0 tworzy g\u0142owic\u0119 <b>LD-Haack</b> lub <b>Von Karman</b>, która minimalizuje opór przy ustalonej d\u0142ugo\u015Bci i \u015Brednicy g\u0142owicy. Warto\u015B\u0107 parametru kszta\u0142tu równa 0.333 tworzy g\u0142owic\u0119 <b>LV-Haack</b> która minimalizuje opór przy ustalonej d\u0142ugo\u015Bci i obj\u0119to\u015Bci g\u0142owicy.
+ Shape.Haackseries.desc2  =  Seria <i>g\u0142owic</i> Haacka zosta\u0142a tak zaprojektowana, aby osi\u0105gn\u0105\u0107 minimalny opór.  Talie przej\u015Bciowe zaprojektowane wed\u0142ug tej metody maj\u0105 podobny kszta\u0142t, ale niekoniecznie zapewniaj\u0105 optymalny opór talii przej\u015Bciowej. Warto\u015B\u0107 parametru kszta\u0142tu równa 0 tworzy kszta\u0142t <b>LD-Haack</b> lub <b>Von Karman</b>, za\u015B warto\u015B\u0107 równa 0,333 tworzy kszta\u0142t <b>LV-Haack</b>.
+ ! RocketComponent
+ RocketComponent.Position.TOP  =  Góra cz\u0119\u015Bci podstawowej
+ RocketComponent.Position.MIDDLE  =  \u015Arodek cz\u0119\u015Bci podstawowej
+ RocketComponent.Position.BOTTOM  =  Dó\u0142 cz\u0119\u015Bci podstawowej
+ RocketComponent.Position.AFTER  =  Za cz\u0119\u015Bci\u0105 podstawow\u0105
+ RocketComponent.Position.ABSOLUTE  =  Czubek g\u0142owicy
+ ! LaunchLug
+ LaunchLug.Launchlug  =  Zaczep startowy
+ ! NoseCone
+ NoseCone.NoseCone  =  G\u0142owica
+ ! Transition
+ Transition.Transition  =  Talia przej\u015Bciowa
+ !Stage
+ Stage.Stage  =  Stopie\u0144
+ Stage.SeparationEvent.UPPER_IGNITION  =  Zap\u0142on silnika wy\u017Cszego stopnia
+ Stage.SeparationEvent.IGNITION  =  Zap\u0142on silnika bie\u017C\u0105cego stopnia
+ Stage.SeparationEvent.BURNOUT  =  Wyga\u015Bni\u0119cie silnika bie\u017C\u0105cego stopnia
+ Stage.SeparationEvent.EJECTION  =  \u0141adunek odrzucaj\u0105cy bie\u017C\u0105cego stopnia
+ Stage.SeparationEvent.LAUNCH  =  Start
+ Stage.SeparationEvent.NEVER  =  Nigdy
+ ! BodyTube
+ BodyTube.BodyTube  =  Korpus rakiety
+ ! TubeCoupler
+ TubeCoupler.TubeCoupler  =  \u0141\u0105cznik rur
+ !InnerTube
+ InnerTube.InnerTube  =  Rura wewn\u0119trzna
+ ! TrapezoidFinSet
+ TrapezoidFinSet.TrapezoidFinSet  =  Zestaw stateczników trapezoidalnych
+ ! FreeformFinSet
+ FreeformFinSet.FreeformFinSet  =   Zestaw stateczników o niestandardowym kszta\u0142cie
+ !MassComponent
+ MassComponent.MassComponent  =  Balast
+ ! Parachute
+ Parachute.Parachute  =  Spadochron
+ ! ShockCord
+ ShockCord.ShockCord  =  Linka amortyzuj\u0105ca
+ ! Bulkhead
+ Bulkhead.Bulkhead  =  Przegroda
+ !Rocket
+ Rocket.motorCount.Nomotor  =  [bez silników]
+ Rocket.compname.Rocket  =  Rakieta
+ !MotorMount
+ MotorMount.IgnitionEvent.AUTOMATIC  =  Rakieta
+ MotorMount.IgnitionEvent.LAUNCH  =  Start
+ MotorMount.IgnitionEvent.EJECTION_CHARGE  =  Pierwszy \u0142adunek odrzucaj\u0105cy poprzedniego stopnia
+ MotorMount.IgnitionEvent.BURNOUT  =  Pierwsze wypalenie poprzedniego stopnia
+ MotorMount.IgnitionEvent.NEVER  =  Nigdy
+ !ComponentIcons
+ ComponentIcons.Nosecone  =  G\u0142owica
+ ComponentIcons.Bodytube  =  Korpus rakiety
+ ComponentIcons.Transition  =  Talia przej\u015Bciowa
+ ComponentIcons.Trapezoidalfinset  =  Zestaw stateczników trapezoidalnych
+ ComponentIcons.Ellipticalfinset  =  Zestaw stateczników o kszta\u0142cie eliptycznym
+ ComponentIcons.Freeformfinset  =  Zestaw stateczników o niestandardowym kszta\u0142cie
+ ComponentIcons.Launchlug  =  Zaczep startowy
+ ComponentIcons.Innertube  =  Rura wewn\u0119trzna
+ ComponentIcons.Tubecoupler  =  \u0141\u0105cznik rur
+ ComponentIcons.Centeringring  =  Pier\u015Bcie\u0144 centruj\u0105cy
+ ComponentIcons.Bulkhead  =  Przegroda
+ ComponentIcons.Engineblock  =  Blokada silnika
+ ComponentIcons.Parachute  =  Spadochron
+ ComponentIcons.Streamer  =  Ta\u015Bma
+ ComponentIcons.Shockcord  =  Linka amortyzuj\u0105ca
+ ComponentIcons.Masscomponent  =  Balast
+ ComponentIcons.disabled  =  (nieaktywny)
+ ! StageAction
+ StageAction.Stage  =  Stopie\u0144
+ ! RecoveryDevice
+ RecoveryDevice.DeployEvent.LAUNCH  =  Start (plus NN sekund)
+ RecoveryDevice.DeployEvent.EJECTION  =  Pierwszy \u0142adunek odrzucaj\u0105cy poprzedniego stopnia
+ RecoveryDevice.DeployEvent.APOGEE  =  Apogeum
+ RecoveryDevice.DeployEvent.ALTITUDE  =  Wysoko\u015B\u0107 bezwzgl\u0119dna podczas opadania
+ RecoveryDevice.DeployEvent.CURRENT_STAGE_SEPARATION  =  Oddzielenie bie\u017C\u0105cego stopnia
+ RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION  =  Oddzielenie ni\u017Cszego stopnia
+ RecoveryDevice.DeployEvent.NEVER  =  Nigdy
+ ! FlightEvent
+ FlightEvent.Type.LAUNCH  =  Start
+ FlightEvent.Type.IGNITION  =  Zap\u0142on silnika
+ FlightEvent.Type.LIFTOFF  =  Start
+ FlightEvent.Type.LAUNCHROD  =  Opuszczenie pr\u0119ta startowego
+ FlightEvent.Type.BURNOUT  =  Wypalenie silnika
+ FlightEvent.Type.EJECTION_CHARGE  =  \u0141adunek odrzucaj\u0105cy
+ FlightEvent.Type.STAGE_SEPARATION  =  Separacja stopnia
+ FlightEvent.Type.APOGEE  =  Apogeum
+ FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT  =  Aktywacja uk\u0142adu odzysku
+ FlightEvent.Type.GROUND_HIT  =  Uderzenie w ziemi\u0119
+ FlightEvent.Type.SIMULATION_END  =  Koniec symulacji
+ FlightEvent.Type.ALTITUDE  =  Zmiana wysoko\u015Bci
+ ! ThrustCurveMotorColumns
+ TCurveMotorCol.MANUFACTURER  =  Producent
+ TCurveMotorCol.DESIGNATION  =  Oznaczenie
+ TCurveMotorCol.TYPE  =  Typ
+ TCurveMotorCol.DIAMETER  =  \u015Arednica
+ TCurveMotorCol.LENGTH  =  D\u0142ugo\u015B\u0107
+ ! RocketInfo
+ RocketInfo.lengthLine.Length  =  D\u0142ugo\u015B\u0107
+ RocketInfo.lengthLine.maxdiameter  =  , maks. \u015Brednica
+ RocketInfo.massText1  =  Masa z silnikami
+ RocketInfo.massText2  =  Masa bez silników
+ RocketInfo.at  =  przy M
+ RocketInfo.cgText  =  \u015AC:
+ RocketInfo.cpText  =  \u015AP:
+ RocketInfo.stabText  =  Stabilno\u015B\u0107:
+ RocketInfo.Warning  =  Ostrze\u017Cenie:
+ RocketInfo.Calculating  =  Obliczanie...
+ RocketInfo.Apogee  =  Apogeum:
+ RocketInfo.Maxvelocity  =  Max. pr\u0119dko\u015B\u0107:
+ RocketInfo.Maxacceleration  =  Max. przy\u015Bpieszenie:
+ RocketInfo.apogeeValue  =  N/D
+ RocketInfo.Mach  =  ( Mach
+ RocketInfo.velocityValue  =  N/D
+ RocketInfo.accelerationValue  =  N/D
+ ! FinSet
+ FinSet.CrossSection.SQUARE  =  Kwadratowy
+ FinSet.CrossSection.ROUNDED  =  Zaokr\u0105glony
+ FinSet.CrossSection.AIRFOIL  =  Profil lotniczy
+ FinSet.TabRelativePosition.FRONT  =  Przedni kraniec kraw\u0119dzi podstawy
+ FinSet.TabRelativePosition.CENTER  =  \u015Arodek kraw\u0119dzi podstawy
+ FinSet.TabRelativePosition.END  =  Tylny kraniec kraw\u0119dzi podstawy
+ ! FlightDataType
+ FlightDataType.TYPE_TIME  =  Czas
+ FlightDataType.TYPE_ALTITUDE  =  Wysoko\u015B\u0107
+ FlightDataType.TYPE_VELOCITY_Z  =  Pr\u0119dko\u015B\u0107 pionowa
+ FlightDataType.TYPE_ACCELERATION_Z  =  Przyspieszenie pionowe
+ FlightDataType.TYPE_VELOCITY_TOTAL  =  Pr\u0119dko\u015B\u0107 ca\u0142kowita
+ FlightDataType.TYPE_ACCELERATION_TOTAL  =  Przyspieszenie ca\u0142kowite
+ FlightDataType.TYPE_POSITION_X  =  Pozycja do nawietrznej
+ FlightDataType.TYPE_POSITION_Y  =  Pozycja równoleg\u0142a do wiatru
+ FlightDataType.TYPE_POSITION_XY  =  Odleg\u0142o\u015B\u0107 boczna
+ FlightDataType.TYPE_POSITION_DIRECTION  =  Kierunek boczny
+ FlightDataType.TYPE_VELOCITY_XY  =  Pr\u0119dko\u015B\u0107 boczna
+ FlightDataType.TYPE_ACCELERATION_XY  =  Przyspieszenie boczne
+ FlightDataType.TYPE_AOA  =  K\u0105t natarcia
+ FlightDataType.TYPE_ROLL_RATE  =  Tempo obrotu
+ FlightDataType.TYPE_PITCH_RATE  =  Tempo nachylenia
+ FlightDataType.TYPE_YAW_RATE  =  Tempo przesuni\u0119cia
+ FlightDataType.TYPE_MASS  =  Masa
+ FlightDataType.TYPE_LONGITUDINAL_INERTIA  =  Wzd\u0142u\u017Cny moment bezw\u0142adno\u015Bci
+ FlightDataType.TYPE_ROTATIONAL_INERTIA  =  Rotacyjny moment bezw\u0142adno\u015Bci
+ FlightDataType.TYPE_CP_LOCATION  =  Po\u0142o\u017Cenie \u015AP
+ FlightDataType.TYPE_CG_LOCATION  =  Po\u0142o\u017Cenie \u015AC
+ FlightDataType.TYPE_STABILITY  =  Zapas stabilno\u015Bci w kalibrach
+ FlightDataType.TYPE_MACH_NUMBER  =  Liczba Macha
+ FlightDataType.TYPE_REYNOLDS_NUMBER  =  Liczba Reynoldsa
+ FlightDataType.TYPE_THRUST_FORCE  =  Si\u0142a si\u0105gu
+ FlightDataType.TYPE_DRAG_FORCE  =  Si\u0142a oporu
+ FlightDataType.TYPE_DRAG_COEFF  =  Wspó\u0142czynnik oporu
+ FlightDataType.TYPE_AXIAL_DRAG_COEFF  =  Osiowy wspó\u0142czynnik oporu
+ FlightDataType.TYPE_FRICTION_DRAG_COEFF  =  Wspó\u0142czynnik oporu w wyniku tarcia
+ FlightDataType.TYPE_PRESSURE_DRAG_COEFF  =  Wspó\u0142czynnik oporu w wyniku ci\u015Bnienia
+ FlightDataType.TYPE_BASE_DRAG_COEFF  =  Bazowy wspó\u0142czynnik oporu
+ FlightDataType.TYPE_NORMAL_FORCE_COEFF  =  Wspó\u0142czynnik si\u0142y normalnej
+ FlightDataType.TYPE_PITCH_MOMENT_COEFF  =  Wspó\u0142czynnik momentu nachylenia
+ FlightDataType.TYPE_YAW_MOMENT_COEFF  =  Wspó\u0142czynnik momentu przesuni\u0119cia
+ FlightDataType.TYPE_SIDE_FORCE_COEFF  =  Wspó\u0142czynnik si\u0142y bocznej
+ FlightDataType.TYPE_ROLL_MOMENT_COEFF  =  Wspó\u0142czynnik momentu obrotu
+ FlightDataType.TYPE_ROLL_FORCING_COEFF  =  Wspó\u0142czynnik wymuszania obrotu
+ FlightDataType.TYPE_ROLL_DAMPING_COEFF  =  Wspó\u0142czynnik hamowania obrotu
+ FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF  =  Wspó\u0142czynnik hamowania nachylenia
+ FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF  =  Wspó\u0142czynnik hamowania przesuni\u0119cia
+ FlightDataType.TYPE_REFERENCE_LENGTH  =  D\u0142ugo\u015B\u0107 odniesienia
+ FlightDataType.TYPE_REFERENCE_AREA  =  Powierzchnia odniesienia
+ FlightDataType.TYPE_ORIENTATION_THETA  =  Orientacja pionowa (zenit)
+ FlightDataType.TYPE_ORIENTATION_PHI  =  Orientacja boczna (azymut)
+ FlightDataType.TYPE_WIND_VELOCITY  =  Pr\u0119dko\u015B\u0107 wiatru
+ FlightDataType.TYPE_AIR_TEMPERATURE  =  Temperatura powietrza
+ FlightDataType.TYPE_AIR_PRESSURE  =  Ci\u015Bnienie powietrza
+ FlightDataType.TYPE_SPEED_OF_SOUND  =  Pr\u0119dko\u015B\u0107 d\u017Awi\u0119ku
+ FlightDataType.TYPE_TIME_STEP  =  Krok czasowy symulacji
+ FlightDataType.TYPE_COMPUTATION_TIME  =  Czas obliczania
+ FlightDataType.TYPE_LATITUDE  =  Szeroko\u015B\u0107 geograficzna
+ FlightDataType.TYPE_LONGITUDE  =  Dugo\u015B\u0107 geograficzna
+ FlightDataType.TYPE_CORIOLIS_ACCELERATION  =  Przyspieszenie Coriolisa
+ ! PlotConfiguration
+ PlotConfiguration.Verticalmotion  =  Ruch pionowy w funkcji czasu
+ PlotConfiguration.Totalmotion  =  Ruch ca\u0142kowity w funkcji czasu
+ PlotConfiguration.Flightside  =  Profil boczny lotu
+ PlotConfiguration.Stability  =  Stabilno\u015B\u0107 w funkcji czasu
+ PlotConfiguration.Dragcoef  =  Wspó\u0142czynnik oporu wzgl\u0119dem liczby Macha
+ PlotConfiguration.Rollcharacteristics  =  Charakterystyka obrotu
+ PlotConfiguration.Angleofattack  =  K\u0105t natarcia i orientacja w funkcji czasu
+ PlotConfiguration.Simulationtime  =  Krok czasowy symulacji i czas obliczania
+ ! Warning
+ Warning.LargeAOA.str1  =  Wyst\u0105pi\u0142 du\u017Cy k\u0105t natarcia.
+ Warning.LargeAOA.str2  =  Wyst\u0105pi\u0142 du\u017Cy k\u0105t natarcia (
+ Warning.DISCONTINUITY  =  Nieci\u0105g\u0142o\u015B\u0107 \u015Brednicy rakiety.
+ Warning.THICK_FIN  =  Grube stateczniki mog\u0105 nie by\u0107 modelowane dok\u0142adnie.
+ Warning.JAGGED_EDGED_FIN  =  Stateczniki o nieregularnych kraw\u0119dziach mog\u0105 zmniejszy\u0107 dok\u0142adno\u015B\u0107 prognoz.
+ Warning.LISTENERS_AFFECTED  =  Detektory zmodyfikowa\u0142y symulacj\u0119 lotu
+ Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING  =  Uk\u0142ad odzysku zosta\u0142 aktywowany przy wci\u0105\u017C pracuj\u0105cym silniku.
+ Warning.FILE_INVALID_PARAMETER  =  Wyst\u0105pi\u0142 niew\u0142a\u015Bciwy parametr - zignorowano.
+ ! Scale dialog
+ ScaleDialog.lbl.scaleRocket  =  Ca\u0142a rakieta
+ ScaleDialog.lbl.scaleSubselection  =  Zaznaczenie i cz\u0119\u015Bci dodatkowe
+ ScaleDialog.lbl.scaleSelection  =  Tylko wybrana cz\u0119\u015B\u0107
+ ScaleDialog.title  =  Skaluj model
+ ScaleDialog.lbl.scale  =  Skala:
+ ScaleDialog.lbl.scale.ttip  =  Wybierz, czy chcesz skalowa\u0107 ca\u0142y model, czy tylko wybran\u0105 cz\u0119\u015B\u0107
+ ScaleDialog.lbl.scaling  =  Skalowanie do zastosowania:
+ ScaleDialog.lbl.scaling.ttip  =  Rozmiar wynikowy, warto\u015Bci powy\u017Cej 100% powi\u0119kszaj\u0105, za\u015B warto\u015Bci poni\u017Cej 100% zmniejszaj\u0105 model.
+ ! The scaleFrom/scaleTo pair creates a phrase "Scale from [...] to [...]"
+ ScaleDialog.lbl.scaleFrom  =  Skaluj od
+ ScaleDialog.lbl.scaleTo  =  do
+ ScaleDialog.lbl.scaleFromTo.ttip  =  Okre\u015Bl skalowanie w oparciu o d\u0142ugo\u015B\u0107 oryginaln\u0105 i wynikow\u0105.
+ ScaleDialog.checkbox.scaleMass  =  Aktualizuj warto\u015B\u0107 masy nominalnej
+ ScaleDialog.checkbox.scaleMass.ttip  =  Skaluj balast, mno\u017C\u0105c ci\u0119\u017Car przez wspó\u0142czynnik skali podniesiony do sze\u015Bcianu
+ ScaleDialog.button.scale  =  Skala
+ ScaleDialog.undo.scaleRocket  =  Skaluj rakiet\u0119
+ ScaleDialog.undo.scaleComponent  =  Skaluj cz\u0119\u015B\u0107
+
+ ScaleDialog.undo.scaleComponents  =  Skaluj cz\u0119\u015Bci
+ !icons
+ Icons.Undo  =  Cofnij
+ Icons.Redo  =  Powtórz
+ OpenRocketPrintable.Partsdetail  =  Szczegó\u0142y cz\u0119\u015Bci
+ OpenRocketPrintable.Fintemplates  =  Szablony stateczników
+ OpenRocketPrintable.Transitiontemplates  =  Szablony talii przej\u015Bciowych
+ OpenRocketPrintable.Noseconetemplates  =  Szablony g\u0142owic
+ OpenRocketPrintable.Finmarkingguide  =  Instrukcja oznaczania stateczników
+ OpenRocketPrintable.DesignReport  =  Raport projektu
+ OpenRocketPrintable.Centeringringtemplates  =  Pier\u015Bcie\u0144 centruj\u0105cy
+ OpenRocketDocument.Redo  =  Powtórz
+ OpenRocketDocument.Undo  =  Cofnij
+ !EllipticalFinSet
+ EllipticalFinSet.Ellipticalfinset  =  Zestaw stateczników o kszta\u0142cie eliptycznym
+ ! Optimization
+ ! Modifiers
+ optimization.modifier.nosecone.length  =  D\u0142ugo\u015B\u0107
+ optimization.modifier.nosecone.length.desc  =  Optymalizuj d\u0142ugo\u015B\u0107 g\u0142owicy.
+ optimization.modifier.nosecone.diameter  =  \u015Arednica
+ optimization.modifier.nosecone.diameter.desc  =  Optymalizuj \u015Brednice podstawy g\u0142owicy.
+ optimization.modifier.nosecone.thickness  =  Grubo\u015B\u0107
+ optimization.modifier.nosecone.thickness.desc  =  Optymalizuj grubo\u015B\u0107 \u015Bcian g\u0142owicy.
+ optimization.modifier.nosecone.shapeparameter  =  Parametr kszta\u0142tu
+ optimization.modifier.nosecone.shapeparameter.desc  =  Optymalizuj parametr kszta\u0142tu g\u0142owicy.
+ optimization.modifier.transition.length  =  D\u0142ugo\u015B\u0107
+ optimization.modifier.transition.length.desc  =  Optymalizuj d\u0142ugo\u015B\u0107 talii przej\u015Bciowej.
+ optimization.modifier.transition.forediameter  =  \u015Arednica przednia:
+ optimization.modifier.transition.forediameter.desc  =  Optymalizuj przedni\u0105 \u015Brednic\u0119 talii przej\u015Bciowej.
+ optimization.modifier.transition.aftdiameter  =  \u015Arednica tylna:
+ optimization.modifier.transition.aftdiameter.desc  =  Optymalizuj tylna \u015Brednic\u0119 talii przej\u015Bciowej.
+ optimization.modifier.transition.thickness  =  Grubo\u015B\u0107
+ optimization.modifier.transition.thickness.desc  =  Optymalizuj grubo\u015B\u0107 \u015Bcian talii przej\u015Bciowej.
+ optimization.modifier.transition.shapeparameter  =  Parametr kszta\u0142tu
+ optimization.modifier.transition.shapeparameter.desc  =  Optymalizuj parametr kszta\u0142tu talii przej\u015Bciowej.
+ optimization.modifier.bodytube.length  =  D\u0142ugo\u015B\u0107
+ optimization.modifier.bodytube.length.desc  =  Optymalizuj d\u0142ugo\u015B\u0107 korpusu.
+ optimization.modifier.bodytube.outerDiameter  =  \u015Arednica zewn\u0119trzna
+ optimization.modifier.bodytube.outerDiameter.desc  =  Optymalizuj zewn\u0119trzn\u0105 \u015Brednic\u0119 korpusu zachowuj\u0105c grubo\u015B\u0107 \u015Bcian.
+ optimization.modifier.bodytube.thickness  =  Grubo\u015B\u0107
+ optimization.modifier.bodytube.thickness.desc  =  Optymalizuj grubo\u015B\u0107 \u015Bcian korpusu.
+ optimization.modifier.trapezoidfinset.rootChord  =  Kraw\u0119d\u017A podstawy
+ optimization.modifier.trapezoidfinset.rootChord.desc  =  Optymalizuj d\u0142ugo\u015B\u0107 kraw\u0119dzi podstawy zestawu stateczników (d\u0142ugo\u015B\u0107 kraw\u0119dzi statecznika przylegaj\u0105cej do korpusu rakiety).
+ optimization.modifier.trapezoidfinset.tipChord  =  Kraw\u0119d\u017A zewn\u0119trzna
+ optimization.modifier.trapezoidfinset.tipChord.desc  =  Optymalizuj d\u0142ugo\u015B\u0107 kraw\u0119dzi zewn\u0119trznej zestawu stateczników (d\u0142ugo\u015B\u0107 zewn\u0119trznej kraw\u0119dzi statecznika)
+ optimization.modifier.trapezoidfinset.sweep   =  Przesuni\u0119cie
+ optimization.modifier.trapezoidfinset.sweep.desc  =  Optymalizuj przesuni\u0119cie zestawu stateczników (przesuni\u0119cie zewn\u0119trznego kra\u0144ca kraw\u0119dzi natarcia wzgl\u0119dem kra\u0144ca przylegaj\u0105cego do korpusu rakiety).
+ optimization.modifier.trapezoidfinset.height  =  Wysoko\u015B\u0107
+ optimization.modifier.trapezoidfinset.height.desc  =  Optymalizuj wysoko\u015B\u0107 zestawu stateczników (po\u0142owa rozpi\u0119to\u015Bci).
+ optimization.modifier.ellipticalfinset.length  =  Kraw\u0119d\u017A podstawy
+ optimization.modifier.ellipticalfinset.length.desc  =  Optymalizuj d\u0142ugo\u015B\u0107 kraw\u0119dzi podstawy zestawu stateczników.
+ optimization.modifier.ellipticalfinset.height  =  Wysoko\u015B\u0107
+ optimization.modifier.ellipticalfinset.height.desc  =  Optymalizuj wysoko\u015B\u0107 zestawu stateczników (po\u0142owa rozpi\u0119to\u015Bci).
+ optimization.modifier.finset.cant  =  K\u0105t nachylenia
+ optimization.modifier.finset.cant.desc  =  Optymalizuj k\u0105t nachylenia zestawu stateczników.
+ optimization.modifier.finset.position  =  Pozycja
+ optimization.modifier.finset.position.desc  =  Optymalizuj po\u0142o\u017Cenie zestawu stateczników wzd\u0142u\u017C korpusu rakiety.
+ optimization.modifier.launchlug.length  =  D\u0142ugo\u015B\u0107
+ optimization.modifier.launchlug.length.desc  =  Optymalizuj d\u0142ugo\u015B\u0107 zaczepu startowego.
+ optimization.modifier.launchlug.outerDiameter  =  \u015Arednica zewn\u0119trzna
+ optimization.modifier.launchlug.outerDiameter.desc  =  Optymalizuj \u015Brednic\u0119 zewn\u0119trzn\u0105 zaczepu startowego.
+ optimization.modifier.launchlug.thickness  =  Grubo\u015B\u0107
+ optimization.modifier.launchlug.thickness.desc  =  Optymalizuj grubo\u015B\u0107 zaczepu startowego zachowuj\u0105c sta\u0142\u0105 \u015Brednic\u0119 zewn\u0119trzn\u0105.
+ optimization.modifier.launchlug.position  =  Pozycja
+ optimization.modifier.launchlug.position.desc  =  Optymalizuj po\u0142o\u017Cenie zaczepu startowego wzd\u0142u\u017C korpusu rakiety.
+ optimization.modifier.internalcomponent.position  =  Pozycja
+ optimization.modifier.internalcomponent.position.desc  =  Optymalizuj po\u0142o\u017Cenie wzgl\u0119dem cz\u0119\u015Bci podstawowej.
+ optimization.modifier.masscomponent.mass  =  Masa
+ optimization.modifier.masscomponent.mass.desc  =  Optymalizuj ci\u0119\u017Car balastu.
+ optimization.modifier.parachute.diameter  =  \u015Arednica
+ optimization.modifier.parachute.diameter.desc  =  Optymalizuj \u015Brednic\u0119 czaszy spadochronu.
+ optimization.modifier.parachute.coefficient  =  Wspó\u0142czynnik oporu
+ optimization.modifier.parachute.coefficient.desc  =  Optymalizuj wspó\u0142czynnik oporu spadochronu.  Standardowe spadochrony maj\u0105 wspó\u0142czynnik oporu oko\u0142o 0,8.
+ optimization.modifier.streamer.length  =  D\u0142ugo\u015B\u0107
+ optimization.modifier.streamer.length.desc  =  Optymalizuj d\u0142ugo\u015B\u0107 ta\u015Bmy.
+ optimization.modifier.streamer.width  =  Szeroko\u015B\u0107
+ optimization.modifier.streamer.width.desc  =  Optymalizuj szeroko\u015B\u0107 ta\u015Bmy.
+ optimization.modifier.streamer.aspectRatio  =  Format
+ optimization.modifier.streamer.aspectRatio.desc  =  Optymalizuj format ta\u015Bmy (d\u0142ugo\u015B\u0107/szeroko\u015B\u0107).  NIE nale\u017Cy jednocze\u015Bnie ustawia\u0107 poszczególnych wymiarów ta\u015Bmy oraz jej formatu.
+ optimization.modifier.streamer.coefficient  =  Wspó\u0142czynnik oporu
+ optimization.modifier.streamer.coefficient.desc  =  Optymalizuj wspó\u0142czynnik oporu ta\u015Bmy.
+ optimization.modifier.recoverydevice.deployDelay  =  Opó\u017Anienie aktywacji
+ optimization.modifier.recoverydevice.deployDelay.desc  =  Optymalizuj opó\u017Anienie aktywacji uk\u0142adu odzysku.
+ optimization.modifier.recoverydevice.deployAltitude  =  Wysoko\u015B\u0107 aktywacji
+ optimization.modifier.recoverydevice.deployAltitude.desc  =  Optymalizuj wysoko\u015B\u0107 aktywacji uk\u0142adu odzysku.
+ optimization.modifier.rocketcomponent.overrideMass  =  Wymu\u015B ci\u0119\u017Car
+ optimization.modifier.rocketcomponent.overrideMass.desc  =  Optymalizuj wymuszony ci\u0119\u017Car cz\u0119\u015Bci.
+ optimization.modifier.rocketcomponent.overrideCG  =  Wymu\u015B \u015AC
+ optimization.modifier.rocketcomponent.overrideCG.desc  =  Optymalizuj wymuszony \u015Brodek ci\u0119\u017Cko\u015Bci cz\u0119\u015Bci.
+ optimization.modifier.motormount.overhang  =  Wysuni\u0119cie silnika
+ optimization.modifier.motormount.overhang.desc  =  Optymalizuj wysuni\u0119cie silnika.
+ optimization.modifier.motormount.delay  =  Opó\u017Anienie zap\u0142onu silnika
+ optimization.modifier.motormount.delay.desc  =  Optymalizuj opó\u017Anienie zap\u0142onu silnika.
+ ! General rocket design optimization dialog
+ GeneralOptimizationDialog.title  =  Optymalizacja rakiety
+ GeneralOptimizationDialog.goal.maximize  =  Maksymalizuj warto\u015B\u0107
+ GeneralOptimizationDialog.goal.minimize  =  Minimalizuj warto\u015B\u0107
+ GeneralOptimizationDialog.goal.seek  =  D\u0105\u017C do warto\u015Bci
+ GeneralOptimizationDialog.btn.start  =  Rozpocznij optymalizacj\u0119
+ GeneralOptimizationDialog.btn.stop  =  Zatrzymaj optymalizacj\u0119
+ GeneralOptimizationDialog.lbl.paramsToOptimize  =  Parametry do optymalizacji:
+ GeneralOptimizationDialog.btn.add  =  Dodaj
+ GeneralOptimizationDialog.btn.add.ttip  =  Dodaj wybrany parametr do optymalizacji
+ GeneralOptimizationDialog.btn.remove  =  Usu\u0144
+ GeneralOptimizationDialog.btn.remove.ttip  =  Usu\u0144 wybrany parametr z listy do optymalizacji
+ GeneralOptimizationDialog.btn.removeAll  =  Usu\u0144 wszystko
+ GeneralOptimizationDialog.btn.removeAll.ttip  =  Usu\u0144 wszystkie parametry z listy do optymalizacji
+ GeneralOptimizationDialog.lbl.availableParams  =  Dost\u0119pne parametry:
+ GeneralOptimizationDialog.lbl.optimizationOpts  =  Opcje optymalizacji:
+ GeneralOptimizationDialog.lbl.optimizeSim  =  Optymalizuj symulacj\u0119:
+ GeneralOptimizationDialog.lbl.optimizeSim.ttip  =  Wybierz symulacj\u0119 do optymalizacji
+ GeneralOptimizationDialog.lbl.optimizeValue  =  Warto\u015B\u0107 optymalizowana:
+ GeneralOptimizationDialog.lbl.optimizeValue.ttip  =  Wybierz warto\u015B\u0107, która ma zosta\u0107 poddana optymalizacji
+ GeneralOptimizationDialog.lbl.optimizeGoal  =  Cel optymalizacji:
+ GeneralOptimizationDialog.lbl.optimizeGoal.ttip  =  Wybierz cel optymalizacji
+ GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip  =  Dowolna warto\u015B\u0107, do której ma d\u0105\u017Cy\u0107 proces optymalizacji
+ GeneralOptimizationDialog.lbl.requireStability  =  Wymagana stabilno\u015B\u0107
+ GeneralOptimizationDialog.lbl.requireMinStability  =  Stabilno\u015B\u0107 minimalna:
+ GeneralOptimizationDialog.lbl.requireMinStability.ttip  =  Ustal minimalny zapas stabilno\u015Bci modelu
+ GeneralOptimizationDialog.lbl.requireMaxStability  =  Stabilno\u015B\u0107 maksymalna:
+ GeneralOptimizationDialog.lbl.requireMaxStability.ttip  =  Ustal maksymalny zapas stabilno\u015Bci modelu
+ GeneralOptimizationDialog.status.bestValue  =  Najlepsza warto\u015B\u0107:
+ GeneralOptimizationDialog.status.bestValue.ttip  =  Najlepsza dotychczas znaleziona warto\u015B\u0107 optymalizacji.
+ GeneralOptimizationDialog.status.stepCount  =  Liczba kroków:
+ GeneralOptimizationDialog.status.stepCount.ttip  =  Liczba przeprowadzonych kroków optymalizacji.
+ GeneralOptimizationDialog.status.evalCount  =  Ewaluacje:
+ GeneralOptimizationDialog.status.evalCount.ttip  =  Ca\u0142kowita liczba wykonanych ewaluacji funkcji (dla symulacji).
+ GeneralOptimizationDialog.status.stepSize  =  Wielko\u015B\u0107 kroku:
+ GeneralOptimizationDialog.status.stepSize.ttip  =  Wielko\u015B\u0107 bie\u017C\u0105cego kroku optymalizacji (w stosunku do zakresów parametru optymalizacji)
+ GeneralOptimizationDialog.btn.plotPath  =  Rysuj \u015Bcie\u017Ck\u0119 optymalizacji
+ GeneralOptimizationDialog.btn.plotPath.ttip  =  Rysuj wykres \u015Bcie\u017Cki optymalizacji (tylko jedno- i dwuwymiarowa optymalizacja)
+ GeneralOptimizationDialog.btn.save  =  Zapisz \u015Bcie\u017Ck\u0119
+ GeneralOptimizationDialog.btn.save.ttip  =  Zapisz wyniki ewaluacji funkcji (dla symulacji) jako plik CSV.
+ GeneralOptimizationDialog.btn.apply  =  Zastosuj optymalizacj\u0119
+ GeneralOptimizationDialog.btn.apply.ttip  =  Zastosuj wyniki optymalizacji do projektu rakiety
+ GeneralOptimizationDialog.btn.reset  =  Reset
+ GeneralOptimizationDialog.btn.reset.ttip  =  Przywró\u0107 projekt rakiety do stanu obecnego
+ GeneralOptimizationDialog.btn.close  =  Zamknij
+ GeneralOptimizationDialog.btn.close.ttip  =  Zamknij okno bez wprowadzania zmian do projektu rakiety
+ GeneralOptimizationDialog.error.selectParams.text  =  Wybierz parametry do optymalizowania spo\u015Bród dost\u0119pnych parametrów.
+ GeneralOptimizationDialog.error.selectParams.title  =  Wybierz parametry optymalizacji
+ GeneralOptimizationDialog.error.optimizationFailure.text  =  Optymalizacja nie zosta\u0142a przeprowadzona:
+ GeneralOptimizationDialog.error.optimizationFailure.title  =  Optymalizacja zako\u0144czy\u0142a si\u0119 niepowodzeniem
+ GeneralOptimizationDialog.undoText  =  Zastosuj optymalizacj\u0119
+ GeneralOptimizationDialog.basicSimulationName  =  Symulacja podstawowa
+ GeneralOptimizationDialog.noSimulationName  =  Brak symulacji
+ GeneralOptimizationDialog.table.col.parameter  =  Parametr
+ GeneralOptimizationDialog.table.col.current  =  Bie\u017C\u0105cy
+ GeneralOptimizationDialog.table.col.min  =  Minimalny
+ GeneralOptimizationDialog.table.col.max  =  Maksymalny
+ GeneralOptimizationDialog.export.header  =  Dodaj wiersz nag\u0142ówka
+ GeneralOptimizationDialog.export.header.ttip  =  Dodaj wiersz nag\u0142ówka jako pierwszy wiersz zawieraj\u0105cy opisy pól.
+ GeneralOptimizationDialog.export.stability  =  Stabilno\u015B\u0107
+ ! Dialog for plotting optimization results
+ OptimizationPlotDialog.title  =  Wyniki optymalizacji
+ OptimizationPlotDialog.lbl.zoomInstructions  =  Kliknij i przeci\u0105gnij w dó\u0142 + prawo aby powi\u0119kszy\u0107; góra + lewo aby pomniejszy\u0107
+ OptimizationPlotDialog.plot1d.title  =  Wynik optymalizacji
+ OptimizationPlotDialog.plot1d.series  =  Wynik optymalizacji
+ OptimizationPlotDialog.plot2d.title  =  \u015Acie\u017Cka optymalizacji
+ OptimizationPlotDialog.plot2d.path  =  \u015Acie\u017Cka optymalizacji
+ OptimizationPlotDialog.plot2d.evals  =  Ewaluacje
+ OptimizationPlotDialog.plot.ttip.stability  =  Stabilno\u015B\u0107:
+ OptimizationPlotDialog.plot.label.optimum  =  Optymalna
+ ! Optimization parameters
+ MaximumAltitudeParameter.name  =  Wysoko\u015B\u0107 apogeum
+ MaximumVelocityParameter.name  =  Pr\u0119dko\u015B\u0107 maksymalna
+ MaximumAccelerationParameter.name  =  Przyspieszenie maksymalne
+ StabilityParameter.name  =  Stabilno\u015B\u0107
+ GroundHitVelocityParameter.name  =  Pr\u0119dko\u015B\u0107 przyziemienia
+ LandingDistanceParameter.name  =  Oddalenie miejsca l\u0105dowania
+ TotalFlightTimeParameter.name  =  Ca\u0142kowity czas lotu
+ DeploymentVelocityParameter.name  =  Pr\u0119dko\u015B\u0107 w chwili wyzwolenia spadochronu
+ ! Compass directions drawn on a compass rose.
+ CompassRose.lbl.north  =  N
+ CompassRose.lbl.east   =  E
+ CompassRose.lbl.south  =  S
+ CompassRose.lbl.west   =  W
+ ! Compass directions with subdirections.  These might not be localized even if the directions on the compass rose are.
+ CompassSelectionButton.lbl.N  =  N
+ CompassSelectionButton.lbl.NE  =  NE
+ CompassSelectionButton.lbl.E  =  E
+ CompassSelectionButton.lbl.SE  =  SE
+ CompassSelectionButton.lbl.S  =  S
+ CompassSelectionButton.lbl.SW  =  SW
+ CompassSelectionButton.lbl.W  =  W
+ CompassSelectionButton.lbl.NW  =  NW
+ SlideShowDialog.btn.next  =  Dalej
+ SlideShowDialog.btn.prev  =  Wstecz
+ SlideShowLinkListener.error.title  =  Nie znaleziono instrukcji
+ SlideShowLinkListener.error.msg  =  Przepraszamy, wybrana instrukcja nie zosta\u0142a jeszcze napisana.
+ GuidedTourSelectionDialog.title  =  Instrukcje krok po kroku
+ GuidedTourSelectionDialog.lbl.selectTour  =  Wybierz instrukcj\u0119 krok po kroku:
+ GuidedTourSelectionDialog.lbl.description  =  Opis instrukcji:
+ GuidedTourSelectionDialog.lbl.length  =  Liczba slajdów:
+ GuidedTourSelectionDialog.btn.start  =  Rozpocznij!
+ ! Custom Fin BMP Importer
+ CustomFinImport.button.label  =  Importuj z obrazka
+ CustomFinImport.badFinImage  =  Niew\u0142a\u015Bciwy obraz Statecznika. Upewnij si\u0119, \u017Ce kolor statecznika jest czarny lub ciemny, a kszta\u0142t statecznika przylega do dolnej kraw\u0119dzi obrazu.
+ CustomFinImport.errorLoadingFile  =  B\u0142\u0105d przy \u0142adowaniu pliku:
+ CustomFinImport.errorParsingFile  =  B\u0142\u0105d podczas przetwarzania obrazu statecznika: 
+ CustomFinImport.undo  =  Importuj zestaw stateczników o niestandardowym kszta\u0142cie
+ CustomFinImport.error.title  =  B\u0142\u0105d podczas wgrywania profilu statecznika
+ CustomFinImport.error.badimage  =  Okre\u015Blenie kszta\u0142tu statecznika z obrazu nie by\u0142o mo\u017Cliwe
+ CustomFinImport.description  =  Obraz zostanie automatycznie zamieniony na czarno-bia\u0142y (statecznik w kolorze czarnym), wi\u0119c upewnij si\u0119, \u017Ce kszta\u0142t statecznika jest wype\u0142niony ciemnym kolorem, a t\u0142o jest bia\u0142e lub jasne. Podstawa statecznika musi przylega\u0107 do dolnej kraw\u0119dzi obrazu.
+ PresetModel.lbl.select  =  Wybierz ustawienia:
+ PresetModel.lbl.database  =  Z bazy danych...
+ ! Component Preset Chooser Dialog
+ ComponentPresetChooserDialog.title  =  Wybierz ustawienia cz\u0119\u015Bci
+ ComponentPresetChooserDialog.filter.label  =  Filtr:
+ ComponentPresetChooserDialog.checkbox.filterAftDiameter  =  Dopasuj tyln\u0105 \u015Brednic\u0119
+ ComponentPresetChooserDialog.checkbox.filterForeDiameter  =  Dopasuj przedni\u0105 \u015Brednic\u0119
+ ComponentPresetChooserDialog.menu.sortAsc  =  Szereguj rosn\u0105co
+ ComponentPresetChooserDialog.menu.sortDesc  =  Szereguj malej\u0105co
+ ComponentPresetChooserDialog.menu.units  =  Jednostki
+ ComponentPresetChooserDialog.checkbox.showAllCompatible  =  Poka\u017C wszystkie kompatybilne
+ table.column.Favorite  =  Ulubione
+ table.column.Manufacturer  =  Producent
+ table.column.PartNo  =  Numer cz\u0119\u015Bci
+ table.column.Description  =  Opis
+ table.column.Type  =  Typ
+ table.column.Length  =  D\u0142ugo\u015B\u0107
+ table.column.Width  =  Szeroko\u015B\u0107
+ table.column.InnerDiameter  =  \u015Arednica wewn\u0119trzna
+ table.column.OuterDiameter  =  \u015Arednica zewn\u0119trzna
+ table.column.AftOuterDiameter  =  Tylna \u015Brednica zewn\u0119trzna
+ table.column.AftShoulderLength  =  Tylna d\u0142ugo\u015B\u0107 wpustu
+ table.column.AftShoulderDiameter  =  Tylna \u015Brednica wpustu
+ table.column.ForeShoulderLength  =  Przednia d\u0142ugo\u015B\u0107 wpustu
+ table.column.ForeShoulderDiameter  =  Przednia \u015Brednica wpustu
+ table.column.ForeOuterDiameter  =  Przednia \u015Brednica zewn\u0119trzna
+ table.column.Shape  =  Kszta\u0142t
+ table.column.Material  =  Materia\u0142
+ table.column.Finish  =  Wyko\u0144czenie
+ table.column.Thickness  =  Grubo\u015B\u0107
+ table.column.Filled  =  Wype\u0142nione
+ table.column.Mass  =  Masa
+ table.column.Diameter  =  \u015Arednica
+ table.column.Sides  =  Boki
+ table.column.LineCount  =  Liczba linek
+ table.column.LineLength  =  D\u0142ugo\u015B\u0107 linki
+ table.column.LineMaterial  =  Materia\u0142 linek
index 9edc5acf8ab4095e12e70adfb7f13914c0a9fbda..6731930e8e5d6771c8cadabf77b508392c61a475 100644 (file)
@@ -1,6 +1,5 @@
-
 #
-# Russian base translation file
+# English base translation file
 #
 # Should you need to add new logical keys here is the proposed method
 #
 #    "The file '{filename}' exists."
 # They are pieces that are inserted dynamically.
 #
+
+
 ! Set to the name of the current translation file (used for debugging purposes)
 debug.currentFile = messages_ru.properties
 
 ! RocketActions
-RocketActions.checkbox.Donotaskmeagain= \u0411\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C
-RocketActions.lbl.Youcanchangedefop= \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u044B\u0439 \u043F\u043E\u0440\u044F\u0434\u043E\u043A \u0440\u0430\u0431\u043E\u0442\u044B \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445.
-RocketActions.showConfirmDialog.lbl1= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442?
-RocketActions.showConfirmDialog.lbl2= <html><i> \u042D\u0442\u0430 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430 </i>
-RocketActions.showConfirmDialog.title= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0440\u0430\u0441\u0447\u0435\u0442
-RocketActions.DelCompAct.Delete= \u0423\u0434\u0430\u043B\u0438\u0442\u044C
-RocketActions.DelCompAct.ttip.Delete= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442.
-RocketActions.DelSimuAct.Delete= \u0423\u0434\u0430\u043B\u0438\u0442\u044C
-RocketActions.DelSimuAct.ttip.Delete= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442.
-RocketActions.DelAct.Delete= \u0423\u0434\u0430\u043B\u0438\u0442\u044C
-RocketActions.DelAct.ttip.Delete= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 \u0438\u043B\u0438 \u0440\u0430\u0441\u0447\u0435\u0442.
-RocketActions.CutAction.Cut= \u0412\u044B\u0440\u0435\u0437\u0430\u0442\u044C
-RocketActions.CutAction.ttip.Cut= \u0412\u044B\u0440\u0435\u0437\u0430\u0442\u044C \u044D\u0442\u043E\u0442 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 \u0438\u043B\u0438 \u0440\u0430\u0441\u0447\u0435\u0442 \u0432 \u0431\u0443\u0444\u0435\u0440 \u0438 \u0443\u0434\u0430\u043B\u0438\u0442\u044C \u0435\u0433\u043E \u0438\u0437 \u043F\u0440\u043E\u0435\u043A\u0442\u0430
-RocketActions.CopyAct.Copy= \u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C
-RocketActions.CopyAct.ttip.Copy= \u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u044D\u0442\u043E\u0442 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 (\u0438 \u043F\u043E\u0434\u0447\u0438\u043D\u0435\u043D\u043D\u044B\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u044B) \u0432 \u0431\u0443\u0444\u0435\u0440.
-RocketActions.PasteAct.Paste= \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C 
-RocketActions.PasteAct.ttip.Paste= \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 \u0438\u043B\u0438 \u0440\u0430\u0441\u0447\u0435\u0442 \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0435 \u0432 \u043F\u0440\u043E\u0435\u043A\u0442.
-RocketActions.EditAct.Edit= \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C
-RocketActions.EditAct.ttip.Edit= \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442.
-RocketActions.NewStageAct.Newstage= \u041D\u043E\u0432\u0430\u044F \u0441\u0442\u0443\u043F\u0435\u043D\u044C
-RocketActions.NewStageAct.ttip.Newstage= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043D\u043E\u0432\u0443\u044E \u0441\u0442\u0443\u043F\u0435\u043D\u044C \u043A \u043F\u0440\u043E\u0435\u043A\u0442\u0443 \u0440\u0430\u043A\u0435\u0442\u044B.
-RocketActions.ActBoosterstage= \u0421\u0442\u0443\u043F\u0435\u043D\u044C \u0443\u0441\u043A\u043E\u0440\u0438\u0442\u0435\u043B\u044F
-RocketActions.MoveUpAct.Moveup= \u041F\u0435\u0440\u0435\u043C\u0435\u0441\u0442\u0438\u0442\u044C \u0432\u0432\u0435\u0440\u0445
-RocketActions.MoveUpAct.ttip.Moveup= \u041F\u0435\u0440\u0435\u043C\u0435\u0441\u0442\u0438\u0442\u044C \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 \u0432\u044B\u0448\u0435.
-RocketActions.MoveDownAct.Movedown= \u041F\u0435\u0440\u0435\u043C\u0435\u0441\u0442\u0438\u0442\u044C \u0432\u043D\u0438\u0437
-RocketActions.MoveDownAct.ttip.Movedown= \u041F\u0435\u0440\u0435\u043C\u0435\u0441\u0442\u0438\u0442\u044C \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 \u043D\u0438\u0436\u0435.
+RocketActions.checkbox.Donotaskmeagain = \u0411\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c
+RocketActions.lbl.Youcanchangedefop = \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445.
+RocketActions.showConfirmDialog.lbl1 = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044b?
+RocketActions.showConfirmDialog.lbl2 = <html><i>\u042d\u0442\u0443 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c.</i>
+RocketActions.showConfirmDialog.title = \u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u0432
+RocketActions.DelCompAct.Delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c
+RocketActions.DelCompAct.ttip.Delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442.
+RocketActions.DelSimuAct.Delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c
+RocketActions.DelSimuAct.ttip.Delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u0441\u0447\u0435\u0442.
+RocketActions.DelAct.Delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c
+RocketActions.DelAct.ttip.Delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438\u043b\u0438 \u0440\u0430\u0441\u0447\u0435\u0442.
+RocketActions.CutAction.Cut = \u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c
+RocketActions.CutAction.ttip.Cut = \u041f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438\u043b\u0438 \u0440\u0430\u0441\u0447\u0435\u0442 \u0432 \u0431\u0443\u0444\u0435\u0440 \u043e\u0431\u043c\u0435\u043d\u0430 \u0438 \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u0438\u0437 \u0441\u0445\u0435\u043c\u044b.
+RocketActions.CopyAct.Copy = \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c
+RocketActions.CopyAct.ttip.Copy = \u0421\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438 \u0435\u0433\u043e \u043f\u043e\u0434\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b \u0432 \u0431\u0443\u0444\u0435\u0440 \u043e\u0431\u043c\u0435\u043d\u0430.
+RocketActions.PasteAct.Paste = \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c
+RocketActions.PasteAct.ttip.Paste = \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0438\u043b\u0438 \u0440\u0430\u0441\u0447\u0435\u0442 \u0438\u0437 \u0431\u0443\u0444\u0435\u0440\u0430 \u043e\u0431\u043c\u0435\u043d\u0430.
+RocketActions.EditAct.Edit = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c
+RocketActions.EditAct.ttip.Edit = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442.
+RocketActions.NewStageAct.Newstage = \u041d\u043e\u0432\u0430\u044f \u0441\u0442\u0443\u043f\u0435\u043d\u044c
+RocketActions.NewStageAct.ttip.Newstage = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0441\u0442\u0443\u043f\u0435\u043d\u044c \u0432 \u0441\u0445\u0435\u043c\u0443.
+RocketActions.ActBoosterstage = \u0420\u0430\u0437\u0433\u043e\u043d\u043d\u0430\u044f \u0441\u0442\u0443\u043f\u0435\u043d\u044c
+RocketActions.MoveUpAct.Moveup = \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u0432\u0435\u0440\u0445
+RocketActions.MoveUpAct.ttip.Moveup = \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0432\u0432\u0435\u0440\u0445.
+RocketActions.MoveDownAct.Movedown = \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u043d\u0438\u0437
+RocketActions.MoveDownAct.ttip.Movedown = \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0432\u043d\u0438\u0437.
 
 ! RocketPanel
-RocketPanel.FigTypeAct.Sideview= \u0412\u0438\u0434 \u0441\u0431\u043E\u043A\u0443
-RocketPanel.FigTypeAct.ttip.Sideview= \u0412\u0438\u0434 \u0441\u0431\u043E\u043A\u0443
-RocketPanel.FigTypeAct.Backview= \u0412\u0438\u0434 \u0441\u0437\u0430\u0434\u0438
-RocketPanel.FigTypeAct.ttip.Backview= \u0412\u0438\u0434 \u0441\u043F\u0435\u0440\u0435\u0434\u0438
-RocketPanel.lbl.Motorcfg= \u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F:
-RocketPanel.lbl.infoMessage= <html>Click to select &nbsp;&nbsp; Shift+click to select other &nbsp;&nbsp; Double-click to edit &nbsp;&nbsp; Click+drag to move
+RocketPanel.FigTypeAct.Sideview = \u0412\u0438\u0434 \u0441\u0431\u043e\u043a\u0443
+RocketPanel.FigTypeAct.ttip.Sideview = \u0412\u0438\u0434 \u0441\u0431\u043e\u043a\u0443
+RocketPanel.FigTypeAct.Backview = \u0412\u0438\u0434 \u0441\u0437\u0430\u0434\u0438
+RocketPanel.FigTypeAct.ttip.Backview = \u0412\u0438\u0434 \u0441\u0437\u0430\u0434\u0438
+RocketPanel.FigViewAct.2D = \u0412\u0438\u0434 2D
+RocketPanel.FigViewAct.ttip.2D = \u0412\u0438\u0434 2D
+RocketPanel.FigViewAct.3D = \u0412\u0438\u0434 3D
+RocketPanel.FigViewAct.ttip.3D = \u0412\u0438\u0434 3D
+RocketPanel.lbl.Motorcfg = \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439:
+RocketPanel.lbl.infoMessage = <html>\u041a\u043b\u0438\u043a \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 &nbsp;&nbsp; Shift+\u043a\u043b\u0438\u043a \u0434\u043b\u044f \u0441\u043c\u0435\u043d\u044b \u0432\u044b\u0431\u043e\u0440\u0430 &nbsp;&nbsp; \u0414\u0432\u043e\u0439\u043d\u043e\u0439 \u043a\u043b\u0438\u043a \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f &nbsp;&nbsp; \u041a\u043b\u0438\u043a+\u0442\u0430\u0449\u0438\u0442\u044c \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f
 
 
 ! BasicFrame
-BasicFrame.SimpleFileFilter1= \u0412\u0441\u0435 \u043F\u0440\u043E\u0435\u043A\u0442\u044B \u0440\u0430\u043A\u0435\u0442 (*.ork, *.rkt)
-BasicFrame.SimpleFileFilter2= \u041F\u0440\u043E\u0435\u043A\u0442\u044B \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 OpenRocket (*.ork)
-BasicFrame.SimpleFileFilter3= \u041F\u0440\u043E\u0435\u043A\u0442\u044B \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 RockSim (*.rkt)
-BasicFrame.tab.Rocketdesign= \u041F\u0440\u043E\u0435\u043A\u0442 \u0440\u0430\u043A\u0435\u0442\u044B
-BasicFrame.tab.Flightsim= \u041C\u043E\u0434\u0435\u043B\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u043F\u043E\u043B\u0435\u0442\u0430
-BasicFrame.title.Addnewcomp= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442
-BasicFrame.dlg.lbl1= \u041F\u0440\u043E\u0435\u043A\u0442 '
-BasicFrame.dlg.lbl2= '\u043D\u0435 \u0431\u044B\u043B \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D.
-BasicFrame.dlg.lbl3= \u0425\u043E\u0442\u0438\u0442\u0435 \u0435\u0433\u043E \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C?
-BasicFrame.dlg.title= \u041F\u0440\u043E\u0435\u043A\u0442 \u043D\u0435 \u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D
-BasicFrame.StageName.Sustainer= \u041C\u0430\u0440\u0448\u0435\u0432\u0430\u044F \u0441\u0442\u0443\u043F\u0435\u043D\u044C
-BasicFrame.WarningDialog.txt1= \u0421\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u044B \u0432\u043E\u0437\u043D\u0438\u043A\u043B\u0438 \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0440\u0430\u0431\u043E\u0442\u044B
-BasicFrame.WarningDialog.txt2= \u041D\u0435\u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u043C\u043E\u0433\u043B\u0438 \u0431\u044B\u0442\u044C \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D\u044B \u043D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E.
-BasicFrame.WarningDialog.title= \u041F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u0435 \u043F\u0440\u0438 \u043E\u0442\u043A\u0440\u044B\u0442\u0438\u0438 \u0444\u0430\u0439\u043B\u0430
+BasicFrame.tab.Rocketdesign = \u041f\u0440\u043e\u0435\u043a\u0442 \u0440\u0430\u043a\u0435\u0442\u044b
+BasicFrame.tab.Flightsim = \u041c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u043b\u0435\u0442\u0430
+BasicFrame.title.Addnewcomp = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+BasicFrame.dlg.lbl1 = \u041f\u0440\u043e\u0435\u043a\u0442 '
+BasicFrame.dlg.lbl2 = ' \u043d\u0435 \u0431\u044b\u043b \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d.
+BasicFrame.dlg.lbl3 = \u0425\u043e\u0442\u0438\u0442\u0435 \u0435\u0433\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c?
+BasicFrame.dlg.title = \u041f\u0440\u043e\u0435\u043a\u0442 \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d
+BasicFrame.StageName.Sustainer = \u041c\u0430\u0440\u0448\u0435\u0432\u0430\u044f \u0441\u0442\u0443\u043f\u0435\u043d\u044c
+BasicFrame.WarningDialog.txt1 = \u0412\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u0444\u0430\u0439\u043b\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0438 \u043e\u0448\u0438\u0431\u043a\u0438:
+BasicFrame.WarningDialog.txt2 = \u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0441\u0445\u0435\u043c\u0430 \u0431\u044b\u043b\u0430 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u0430 \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u043b\u0438 \u043d\u0435\u0432\u0435\u0440\u043d\u043e.
+BasicFrame.WarningDialog.title = \u041f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u044f \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u0444\u0430\u0439\u043b\u0430
 
 
 ! General error messages used in multiple contexts
-error.fileExists.title= \u0424\u0430\u0439\u043B \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
-error.fileExists.desc= \u0424\u0430\u0439\u043B '{filename}' \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u0425\u043E\u0442\u0438\u0442\u0435 \u0435\u0433\u043E \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0438\u0441\u0430\u0442\u044C?
+error.fileExists.title = \u0424\u0430\u0439\u043b \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
+error.fileExists.desc = \u0424\u0430\u0439\u043b '{filename}' \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c?
 
-error.writing.title= \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u0437\u0430\u043F\u0438\u0441\u0438 \u0444\u0430\u0439\u043B\u0430
-error.writing.desc= \u0412\u043E\u0437\u043D\u0438\u043A\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u0437\u0430\u043F\u0438\u0441\u0438 \u0432 \u0444\u0430\u0439\u043B:
+error.writing.title = \u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u043f\u0438\u0441\u0438 \u0444\u0430\u0439\u043b\u0430
+error.writing.desc = \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0444\u0430\u0439\u043b\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430:
 
 
 ! Labels used in buttons of dialog windows
 # TODO: Rename these to "btn.xxx"
-button.ok= OK
-button.cancel= \u041E\u0442\u043C\u0435\u043D\u0430
-button.close= \u0417\u0430\u043A\u0440\u044B\u0442\u044C
+button.ok = \u041e\u041a
+button.cancel = \u041e\u0442\u043c\u0435\u043d\u0430
+button.close = \u0417\u0430\u043a\u0440\u044b\u0442\u044c
 
 ! Common labels used in buttons of dialog windows
-dlg.but.ok= OK
-dlg.but.cancel= \u041E\u0442\u043C\u0435\u043D\u0430
-dlg.but.close= \u0417\u0430\u043A\u0440\u044B\u0442\u044C
-
+dlg.but.ok = \u041e\u041a
+dlg.but.cancel = \u041e\u0442\u043c\u0435\u043d\u0430
+dlg.but.close = \u0417\u0430\u043a\u0440\u044b\u0442\u044c
 
 ! General file type names
-filetypes.pdf= PDF \u0444\u0430\u0439\u043B
+filetypes.pdf = \u0424\u0430\u0439\u043b\u044b PDF (*.pdf)
+BasicFrame.SimpleFileFilter1 = \u0412\u0441\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0440\u0430\u043a\u0435\u0442 (*.ork; *.rkt)
+BasicFrame.SimpleFileFilter2 = \u0424\u0430\u0439\u043b\u044b OpenRocket (*.ork)
+BasicFrame.SimpleFileFilter3 = \u0424\u0430\u0439\u043b\u044b RockSim (*.rkt)
+BasicFrame.SimpleFileFilter4 = \u0417\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0438 OpenRocket (*.orc)
+filetypes.images = \u0424\u0430\u0439\u043b\u044b \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439
 
 
 ! About Dialog
-AboutDialog.lbl.version= \u0412\u0435\u0440\u0441\u0438\u044F
+AboutDialog.lbl.version = \u0412\u0435\u0440\u0441\u0438\u044f
 ! The texts below provide additional credits for the translation maintainer
 ! - In AboutDialog.lbl.translation replace "English" with the current language.
 ! - AboutDialog.lbl.translator is the translator / group name (may be empty)
 ! - AboutDialog.lbl.translatorWebsite is a URL to the translator / group (may be empty)
 ! - AboutDialog.lbl.translatorIcon is the file name of an icon under pix/translators/ (may be empty)
-AboutDialog.lbl.translation= \u0420\u0443\u0441\u0441\u043A\u0438\u0439 \u043F\u0435\u0440\u0435\u0432\u043E\u0434 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D:
-AboutDialog.lbl.translator=
-AboutDialog.lbl.translatorWebsite= 
-AboutDialog.lbl.translatorIcon 
+AboutDialog.lbl.translation = Russian translation by:
+AboutDialog.lbl.translator = UncleRus
+AboutDialog.lbl.translatorWebsite 
+AboutDialog.lbl.translatorIcon = 
 
 
 ! Print dialog
-PrintDialog.title= \u041F\u0435\u0447\u0430\u0442\u044C \u0438\u043B\u0438 \u044D\u043A\u0441\u043F\u043E\u0440\u0442
-PrintDialog.but.previewAndPrint= \u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u0438 \u043F\u0435\u0447\u0430\u0442\u044C
-PrintDialog.checkbox.showByStage= \u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u043E \u0441\u0442\u0443\u043F\u0435\u043D\u044F\u043C
-PrintDialog.lbl.selectElements= \u0412\u044B\u0431\u0440\u0430\u0442\u044C \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u0434\u043B\u044F \u043F\u0435\u0447\u0430\u0442\u0438:
-printdlg.but.saveaspdf= \u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u043A\u0430\u043A PDF
-printdlg.but.preview= \u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440
-printdlg.but.settings= \u041D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438
-PrintDialog.error.preview.title= \u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440
-PrintDialog.error.preview.desc1= \u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u043E\u0442\u043A\u0440\u044B\u0442\u044C \u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 PDF:
-PrintDialog.error.preview.desc2= \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u043E\u043F\u0446\u0438\u044E "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0432 PDF".
-
+PrintDialog.title = \u041f\u0435\u0447\u0430\u0442\u044c \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442
+PrintDialog.but.previewAndPrint = \u041f\u0440\u0435\u0434\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u043f\u0435\u0447\u0430\u0442\u0438
+PrintDialog.checkbox.showByStage = \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e \u0441\u0442\u0443\u043f\u0435\u043d\u044f\u043c
+PrintDialog.lbl.selectElements = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b:
+printdlg.but.saveaspdf = \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 PDF
+printdlg.but.preview = \u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440
+printdlg.but.settings = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
+PrintDialog.error.preview.title = \u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440.
+PrintDialog.error.preview.desc1 = \u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u0435\u0434\u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 PDF.
+PrintDialog.error.preview.desc2 = \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u043f\u0446\u0438\u0435\u0439 "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 PDF"
 
 !PrintSettingsDialog
-PrintSettingsDialog.title= \u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u043F\u0435\u0447\u0430\u0442\u0438
-PrintSettingsDialog.lbl.Templatefillcolor= \u0426\u0432\u0435\u0442 \u0437\u0430\u043B\u0438\u0432\u043A\u0438 \u0448\u0430\u0431\u043B\u043E\u043D\u0430:
-PrintSettingsDialog.lbl.Templatebordercolor= \u0426\u0432\u0435\u0442 \u0440\u0430\u043C\u043A\u0438 \u0448\u0430\u0431\u043B\u043E\u043D\u0430:
-PrintSettingsDialog.lbl.Papersize= \u0424\u043E\u0440\u043C\u0430\u0442 \u043B\u0438\u0441\u0442\u0430:
-PrintSettingsDialog.lbl.Paperorientation= \u041E\u0440\u0438\u0435\u043D\u0442\u0430\u0446\u0438\u044F \u043B\u0438\u0441\u0442\u0430:
-PrintSettingsDialog.but.Reset= \u0421\u0431\u0440\u043E\u0441 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043E\u043A
-PrintSettingsDialog.but.Close= \u0417\u0430\u043A\u0440\u044B\u0442\u044C
+PrintSettingsDialog.title = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0435\u0447\u0430\u0442\u0438
+PrintSettingsDialog.lbl.Templatefillcolor = \u0426\u0432\u0435\u0442 \u0437\u0430\u043b\u0438\u0432\u043a\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432:
+PrintSettingsDialog.lbl.Templatebordercolor = \u0426\u0432\u0435\u0442 \u043e\u0431\u0432\u043e\u0434\u043a\u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432:
+PrintSettingsDialog.lbl.Papersize = \u0420\u0430\u0437\u0432\u043c\u0435\u0440 \u0431\u0443\u043c\u0430\u0433\u0438:
+PrintSettingsDialog.lbl.Paperorientation = \u041e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0431\u0443\u043c\u0430\u0433\u0438:
+PrintSettingsDialog.but.Reset = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c
+PrintSettingsDialog.but.Close = \u0417\u0430\u043a\u0440\u044b\u0442\u044c
 
 
 ! Bug Report dialog
-bugreport.dlg.title= \u041E\u0442\u0447\u0435\u0442 \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445
-bugreport.dlg.but.Sendbugreport= \u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043E\u0442\u0447\u0435\u0442 \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445
-bugreport.dlg.but.Sendbugreport.Ttip= \u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u044F\u0442\u044C \u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0447\u0438\u043A\u0430\u043C OpenRocket \u043E\u0442\u0447\u0435\u0442 \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445.
-bugreport.dlg.successmsg1= Bug report successfully sent. \u041E\u0442\u0447\u0435\u0442 \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D \u0443\u0441\u043F\u0435\u0448\u043D\u043E.
-bugreport.dlg.successmsg2= \u0421\u043F\u0430\u0441\u0438\u0431\u043E \u0437\u0430 \u0412\u0430\u0448\u0435 \u0443\u0447\u0430\u0441\u0442\u0438\u0435 \u0432 \u0441\u043E\u0432\u0435\u0440\u0448\u0435\u043D\u0441\u0442\u0432\u043E\u0432\u0430\u043D\u0438\u0438 OpenRoket!
-bugreport.dlg.successmsg3= \u041E\u0442\u0447\u0435\u0442 \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445 \u043E\u0442\u043F\u0440\u0430\u0432\u043B\u0435\u043D
-bugreport.dlg.connectedInternet= <html>\u0415\u0441\u043B\u0438 \u0443 \u0412\u0430\u0441 \u0435\u0441\u0442\u044C \u0441\u043E\u0435\u0434\u0438\u043D\u0435\u043D\u0438\u0435 \u0441 \u0418\u043D\u0442\u0435\u0440\u043D\u0435\u0442\u043E\u043C, \u043F\u0440\u043E\u0441\u0442\u043E \u043D\u0430\u0436\u043C\u0438\u0442\u0435 <em>\u041E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043E\u0442\u0447\u0435\u0442 \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445</em>.
-bugreport.dlg.otherwise= \u0412 \u043F\u0440\u043E\u0442\u0438\u0432\u043D\u043E\u043C \u0441\u043B\u0443\u0447\u0430\u0435 \u043E\u0442\u043F\u0440\u0430\u0432\u0442\u0435 \u0442\u0435\u043A\u0441\u0442 \u043F\u043E\u0434 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\u043C \u043F\u043E \u0430\u0434\u0440\u0435\u0441\u0443:
-bugreport.lbl.Theinformation= \u0418\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u043F\u0440\u0438\u0432\u0435\u0434\u0435\u043D\u043D\u0430\u044F \u0432\u044B\u0448\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u0430 \u0432 \u043E\u0431\u0449\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0439 \u043E\u0442\u0447\u0435\u0442 \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044C, \u0447\u0442\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\u0435 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u0438 \u043A\u043E\u0442\u043E\u0440\u0443\u044E \u0412\u044B \u043D\u0435 \u0445\u043E\u0442\u0438\u0442\u0435 \u0440\u0430\u0441\u043F\u0440\u043E\u0441\u0442\u0440\u0430\u043D\u044F\u0442\u044C \u043F\u0443\u0431\u043B\u0438\u0447\u043D\u043E.
-bugreport.dlg.failedmsg1= \u041F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430 OpenRocket \u043D\u0435 \u0441\u043C\u043E\u0433\u043B\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043E\u0442\u0447\u0435\u0442 \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445:
-bugreport.dlg.failedmsg2= \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u0442\u0438 \u043E\u0442\u0447\u0435\u0442 \u0432\u0440\u0443\u0447\u043D\u0443\u044E
-bugreport.dlg.failedmsg3= Error sending report
-bugreport.reportDialog.txt= <html><b>\u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0441\u043E\u043E\u0431\u0449\u0438\u0442\u044C \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445 OpenRocket \u0437\u0430\u043F\u043E\u043B\u043D\u0438\u0432 \u0444\u043E\u0440\u043C\u0443 \u043F\u043E\u0434 \u044D\u0442\u0438\u043C \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435\u043C.</b><br>\u0422\u0430\u043A\u0436\u0435 \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0441\u043E\u043E\u0431\u0449\u0438\u0442\u044C \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0430\u0445 \u0438 \u043F\u043E\u0441\u043B\u0430\u0442\u044C \u043E\u0431\u0440\u0430\u0437\u0435\u0446 \u043D\u0430 \u0441\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043E\u0442\u0447\u0438\u043A\u043E\u0432.
-bugreport.reportDialog.txt2= <html><b>\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0434\u043E\u0431\u0430\u0432\u0442\u0435 \u043A\u043E\u0440\u043E\u0442\u043A\u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0432\u0430\u0448\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0432 \u043C\u043E\u043C\u0435\u043D\u0442 \u043F\u043E\u044F\u0432\u043B\u0435\u043D\u0438\u044F \u0434\u0435\u0444\u0435\u043A\u0442\u0430.</b>
-bugreport.dlg.provideDescription= \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0441\u043D\u0430\u0447\u0430\u043B\u0430 \u043E\u043F\u0438\u0448\u0438\u0442\u0435 \u0434\u0435\u0444\u0435\u043A\u0442.
-bugreport.dlg.provideDescription.title= \u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0434\u0435\u0444\u0435\u043A\u0442\u0430 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442
+bugreport.dlg.title = \u041e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445
+bugreport.dlg.but.Sendbugreport = \u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445
+bugreport.dlg.but.Sendbugreport.Ttip = \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c OpenRocket.
+bugreport.dlg.successmsg1 = \u041e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d.
+bugreport.dlg.successmsg2 = \u0421\u043f\u0430\u0441\u0438\u0431\u043e \u0437\u0430 \u0412\u0430\u0448\u0435 \u0443\u0447\u0430\u0441\u0442\u0438\u0435 \u0432 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u0438 OpenRoket!
+bugreport.dlg.successmsg3 = \u041e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d
+bugreport.dlg.connectedInternet = <html>\u0415\u0441\u043b\u0438 \u0443 \u0412\u0430\u0441 \u0435\u0441\u0442\u044c \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0435 \u0441 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u043e\u043c, \u043f\u0440\u043e\u0441\u0442\u043e \u043d\u0430\u0436\u043c\u0438\u0442\u0435 <em>\u041e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445</em>.
+bugreport.dlg.otherwise = \u0412 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u0442\u0435\u043a\u0441\u0442 \u043f\u043e\u0434 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443:
+bugreport.lbl.Theinformation = \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f \u0432\u044b\u0448\u0435, \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0432 \u043e\u0431\u0449\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445. \u0423\u0431\u0435\u0434\u0438\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0412\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0442\u044c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e.
+bugreport.dlg.failedmsg1 = \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 OpenRocket \u043d\u0435 \u0441\u043c\u043e\u0433\u043b\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445:
+bugreport.dlg.failedmsg2 = \u041e\u0442\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u043e\u0442\u0447\u0435\u0442 \u0432\u0440\u0443\u0447\u043d\u0443\u044e, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430
+bugreport.dlg.failedmsg3 = \u041e\u0448\u0438\u0431\u043a\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u043e\u0442\u0447\u0435\u0442\u0430
+bugreport.reportDialog.txt = <html><b>\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 OpenRocket, \u0437\u0430\u043f\u043e\u043b\u043d\u0438\u0432 \u0444\u043e\u0440\u043c\u0443 \u043f\u043e\u0434 \u044d\u0442\u0438\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c.</b><br>\u0422\u0430\u043a\u0436\u0435 \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0438\u0442\u044c \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0438 \u043f\u0440\u0438\u043a\u0440\u0435\u043f\u0438\u0442\u044c \u0432\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0430\u0439\u0442\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432.
+bugreport.reportDialog.txt2 = <html><b>\u0414\u043e\u0431\u0430\u0432\u044c\u0442\u0435, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043a\u0440\u0430\u0442\u043a\u043e\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0412\u0430\u0448\u0438\u0445 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043a\u0438.</b>
+bugreport.dlg.provideDescription = \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0438\u0448\u0438\u0442\u0435 \u043e\u0448\u0438\u0431\u043a\u0443.
+bugreport.dlg.provideDescription.title = \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0448\u0438\u0431\u043a\u0438
 
 
 ! Debug log dialog
-debuglogdlg.but.clear= \u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C
-debuglogdlg.OpenRocketdebuglog= \u0416\u0443\u0440\u043D\u0430\u043B \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0434\u0435\u0444\u0435\u043A\u0442\u043E\u0432 OpenRocket
-debuglogdlg.Displayloglines= \u041F\u043E\u043A\u0430\u0437\u0430\u0442\u044C \u0437\u0430\u043F\u0438\u0441\u0438 \u0436\u0443\u0440\u043D\u0430\u043B\u0430:
-debuglogdlg.Follow= \u0421\u043B\u0435\u0434\u0438\u0442\u044C
-debuglogdlg.col.Time= \u0412\u0440\u0435\u043C\u044F
-debuglogdlg.col.Level= \u0423\u0440\u043E\u0432\u0435\u043D\u044C
-debuglogdlg.col.Location= \u041F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435
-debuglogdlg.col.Message= \u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435
-debuglogdlg.lbl.Loglinenbr= \u041D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u043E\u043A\u0438 \u0436\u0443\u0440\u043D\u0430\u043B\u0430:
-debuglogdlg.lbl.Time= \u0412\u0440\u0435\u043C\u044F:
-debuglogdlg.lbl.Level= \u0423\u0440\u043E\u0432\u0435\u043D\u044C:
-debuglogdlg.lbl.Location= \u041F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435:
-debuglogdlg.lbl.Logmessage= \u0421\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0436\u0443\u0440\u043D\u0430\u043B\u0430:
-debuglogdlg.lbl.Stacktrace= \u0422\u0440\u0430\u0441\u0441\u0438\u0440\u043E\u0432\u043A\u0430 \u0441\u0442\u0435\u043A\u0430:
-
+debuglogdlg.but.clear = \u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c
+debuglogdlg.OpenRocketdebuglog = \u0416\u0443\u0440\u043d\u0430\u043b \u043e\u0442\u043b\u0430\u0434\u043a\u0438 OpenRocket
+debuglogdlg.Displayloglines = \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0437\u0430\u043f\u0438\u0441\u0438:
+debuglogdlg.Follow = \u0421\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c
+debuglogdlg.col.Time = \u0412\u0440\u0435\u043c\u044f
+debuglogdlg.col.Level = \u0423\u0440\u043e\u0432\u0435\u043d\u044c
+debuglogdlg.col.Location = \u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+debuglogdlg.col.Message = \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435
+debuglogdlg.lbl.Loglinenbr = \u041d\u043e\u043c\u0435\u0440 \u0441\u0442\u0440\u043e\u043a\u0438 \u0436\u0443\u0440\u043d\u0430\u043b\u0430:
+debuglogdlg.lbl.Time = \u0412\u0440\u0435\u043c\u044f:
+debuglogdlg.lbl.Level = \u0423\u0440\u043e\u0432\u0435\u043d\u044c:
+debuglogdlg.lbl.Location = \u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435:
+debuglogdlg.lbl.Logmessage = \u0421\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435:
+debuglogdlg.lbl.Stacktrace = \u0421\u0442\u0435\u043a \u0432\u044b\u0437\u043e\u0432\u043e\u0432:
+
+
+! MotorChooserDialog
+MotorChooserDialog.title = \u0412\u044b\u0431\u043e\u0440 \u0440\u0430\u043a\u0435\u0442\u043d\u043e\u0433\u043e \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
 
 ! Edit Motor configuration dialog
-edtmotorconfdlg.but.removemotor= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C
-edtmotorconfdlg.but.Selectmotor= \u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C
-edtmotorconfdlg.but.Removeconfiguration= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E
-edtmotorconfdlg.but.Newconfiguration= \u041D\u043E\u0432\u0430\u044F \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F
-edtmotorconfdlg.lbl.Motormounts= <html><b>\u041A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F:</b>
-edtmotorconfdlg.title.Editmotorconf= \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F
-edtmotorconfdlg.selectcomp= <html>\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u0434\u043B\u044F \u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u044F \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F:
-edtmotorconfdlg.lbl.Motorconfig= <html><b>\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F:</b>
-edtmotorconfdlg.lbl.Configname= \u0423\u0441\u043B\u043E\u0432\u043D\u043E\u0435 \u043D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438:
-edtmotorconfdlg.lbl.Leavenamedefault= \u041D\u0435 \u0432\u0432\u043E\u0434\u0438\u0442\u0435 \u0438\u043C\u044F \u0434\u043B\u044F \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E\u0433\u043E \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u044F
+edtmotorconfdlg.but.removemotor = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c
+edtmotorconfdlg.but.Selectmotor = \u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c
+edtmotorconfdlg.but.Removeconfiguration = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e
+edtmotorconfdlg.but.Newconfiguration = \u041d\u043e\u0432\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f
+edtmotorconfdlg.lbl.Motormounts = <html><b>\u041a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439:</b>
+edtmotorconfdlg.title.Editmotorconf = \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439
+edtmotorconfdlg.selectcomp = <html>\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u044f\u0432\u043b\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u044f\u043c\u0438 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439:
+edtmotorconfdlg.lbl.Motorconfig = <html><b>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439:</b>
+edtmotorconfdlg.lbl.Configname = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438:
+edtmotorconfdlg.lbl.Leavenamedefault = \u041e\u0441\u0442\u0430\u0432\u044c\u0442\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043f\u0443\u0441\u0442\u044b\u043c \u0434\u043b\u044f \u0438\u043c\u0435\u043d\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e.
 
 ! Example design dialog
-exdesigndlg.but.open= \u041E\u0442\u043A\u0440\u044B\u0442\u044C
-exdesigndlg.lbl.Selectexample= \u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043F\u0440\u0438\u043C\u0435\u0440 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u0434\u043B\u044F \u043E\u0442\u043A\u0440\u044B\u0442\u0438\u044F:
-exdesigndlg.lbl.Openexampledesign= \u041E\u0442\u043A\u0440\u044B\u0442\u044C \u043F\u0440\u0438\u043C\u0435\u0440 \u043F\u0440\u043E\u0435\u043A\u0442\u0430
-exdesigndlg.lbl.Exampledesignsnotfound= \u041F\u0440\u0438\u043C\u0435\u0440 \u043F\u0440\u043E\u0435\u043A\u0442\u0430 \u043D\u0435 \u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D.
-exdesigndlg.lbl.Examplesnotfound= \u041F\u0440\u0438\u043C\u0435\u0440 \u043D\u0435 \u043E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D
+exdesigndlg.but.open = \u041e\u0442\u043a\u0440\u044b\u0442\u044c
+exdesigndlg.lbl.Selectexample = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u043e\u0435\u043a\u0442\u0430:
+exdesigndlg.lbl.Openexampledesign = \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u043f\u0440\u043e\u0435\u043a\u0442\u0430
+exdesigndlg.lbl.Exampledesignsnotfound = \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b.
+exdesigndlg.lbl.Examplesnotfound = \u041f\u0440\u0438\u043c\u0435\u0440\u044b \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b
 
 
 ! Material edit panel
-matedtpan.but.new= \u041D\u043E\u0432\u044B\u0439
-matedtpan.but.edit= \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C
-matedtpan.but.delete= \u0423\u0434\u0430\u043B\u0438\u0442\u044C
-matedtpan.but.revertall= \u0412\u043E\u0441\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0432\u0441\u0435
-matedtpan.col.Material= \u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
-matedtpan.col.Type= \u0422\u0438\u043F
-matedtpan.col.Density= \u041F\u043B\u043E\u0442\u043D\u043E\u0441\u0442\u044C
-matedtpan.col.but.ttip.New= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
-matedtpan.title.Addcustmaterial= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0437\u0430\u043A\u0430\u0437\u043D\u043E\u0439 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
-matedtpan.but.ttip.edit= \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0441\u0443\u0449\u0435\u0442\u0432\u0443\u044E\u0448\u0438\u0439 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
-matedtpan.title.Editmaterial= \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
-matedtpan.title2.Editmaterial= \u0412\u0441\u0442\u0440\u043E\u0435\u043D\u043D\u044B\u0435 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B \u043D\u0435 \u043C\u043E\u0433\u0443\u0442 \u0431\u044B\u0442\u044C \u043C\u043E\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u043E\u0432\u0430\u043D\u044B.
-matedtpan.but.ttip.delete= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0441\u043E\u0437\u0434\u0430\u043D\u043D\u044B\u0439 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
-matedtpan.but.ttip.revertall= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u0441\u0435 \u0441\u043E\u0437\u0434\u0430\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B
-matedtpan.title.Deletealluser-defined= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u0441\u0435 \u0441\u043E\u0437\u0434\u0430\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B?
-matedtpan.title.Revertall= \u0412\u043E\u0441\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0432\u0441\u0435?
-matedtpan.lbl.edtmaterials= \u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u043E\u0432 \u043D\u0435 \u043F\u043E\u0432\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u043F\u0440\u043E\u0435\u043A\u0442\u044B \u0440\u0430\u043A\u0435\u0442.
+matedtpan.but.new = \u041d\u043e\u0432\u044b\u0439
+matedtpan.but.edit = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c
+matedtpan.but.delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c
+matedtpan.but.revertall = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0441\u0435
+matedtpan.col.Material = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b
+matedtpan.col.Type = \u0422\u0438\u043f
+matedtpan.col.Density = \u041f\u043b\u043e\u0442\u043d\u043e\u0441\u0442\u044c
+matedtpan.col.but.ttip.New = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b
+matedtpan.title.Addcustmaterial = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b
+matedtpan.but.ttip.edit = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b
+matedtpan.title.Editmaterial = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b?
+matedtpan.title2.Editmaterial = \u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u043d\u0435\u043b\u044c\u0437\u044f \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c.
+matedtpan.but.ttip.delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b
+matedtpan.but.ttip.revertall = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b
+matedtpan.title.Deletealluser-defined = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b?
+matedtpan.title.Revertall = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0441\u0435?
+matedtpan.lbl.edtmaterials = <html><i>\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u043e\u0432 \u043d\u0435 \u043f\u043e\u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0440\u0430\u043a\u0435\u0442.</i>
 
 !MaterialModel
-MaterialModel.title.Material= \u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
-MaterialModel.title.Defcustmat= \u0421\u043E\u0437\u0434\u0430\u0442\u044C \u0437\u0430\u043A\u0430\u0437\u043D\u043E\u0439 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
+MaterialModel.title.Material = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b
+MaterialModel.title.Defcustmat = \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430
 
 
 ! Preference dialog
-pref.dlg.but.add= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C
-pref.dlg.but.reset= \u0421\u0431\u0440\u043E\u0441
-pref.dlg.but.checknow= \u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C
-pref.dlg.but.defaultmetric= \u041C\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043A\u0430\u044F \u0441\u0438\u0441\u0442\u0435\u043C\u0430
-pref.dlg.but.defaultimperial= \u0418\u043C\u043F\u0435\u0440\u0441\u043A\u0430\u044F \u0441\u0438\u0441\u0442\u0435\u043C\u0430
-pref.dlg.title.Preferences= \u041F\u0440\u0435\u0434\u043F\u043E\u0447\u0442\u0435\u043D\u0438\u044F 
-pref.dlg.tab.Units= \u0415\u0434\u0438\u043D\u0438\u0446\u044B \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F
-pref.dlg.tab.Defaultunits= \u0418\u0434\u0438\u043D\u0438\u0446\u044B \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
-pref.dlg.tab.Materials= \u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B
-pref.dlg.tab.Custommaterials= \u0417\u0430\u043A\u0430\u0437\u043D\u044B\u0435 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B
-pref.dlg.tab.Options= \u041E\u043F\u0446\u0438\u0438
-pref.dlg.tab.Miscellaneousoptions= \u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u043E\u043F\u0446\u0438\u0438
-pref.dlg.lbl.Positiontoinsert= \u041F\u043E\u0437\u0438\u0446\u0438\u044F \u0434\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u044F \u043D\u043E\u0432\u043E\u0433\u043E \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u0430:
-pref.dlg.lbl.Confirmdeletion= \u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C \u0443\u0434\u0430\u043B\u0435\u043D\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
-pref.dlg.lbl.User-definedthrust= \u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u043D\u044B\u0435 \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C \u043A\u0440\u0438\u0432\u044B\u0435 \u0442\u044F\u0433\u0438:
-pref.dlg.Allthrustcurvefiles= \u0412\u0441\u0435 \u0442\u0438\u043F\u044B \u0444\u0430\u0439\u043B\u043E\u0432 \u0442\u044F\u0433\u0438 (*.eng; *.rse; *.zip; directories)
-pref.dlg.RASPfiles= \u0424\u0430\u0438\u043B\u044B \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 RASP (*.eng)
-pref.dlg.RockSimfiles= \u0424\u0430\u0438\u043B\u044B \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0435\u0439 \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 RockSim (*.rse)
-pref.dlg.ZIParchives= ZIP \u0430\u0440\u0445\u0438\u0432 (*.zip)
-pref.dlg.checkbox.Checkupdates= \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0442\u044C \u043D\u0430\u043B\u0438\u0447\u0438\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043F\u0440\u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0435
-pref.dlg.ttip.Checkupdatesnow= \u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u043D\u0430\u043B\u0438\u0447\u0438\u0435 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438
-pref.dlg.lbl.Selectprefunits=\u041E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u0435 \u0435\u0434\u0438\u043D\u0438\u0446\u044B \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F:
-pref.dlg.lbl.Rocketdimensions= \u0420\u0430\u0437\u043C\u0435\u0440\u044B \u0440\u0430\u043A\u0435\u0442\u044B:
-pref.dlg.lbl.Linedensity= \u041B\u0438\u043D\u0435\u0439\u043D\u0430\u044F \u043F\u043B\u043E\u0442\u043D\u043E\u0441\u0442\u044C:
-pref.dlg.lbl.Motordimensions= \u0420\u0430\u0437\u043C\u0435\u0440\u044B \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F:
-pref.dlg.lbl.Surfacedensity= \u041F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u043D\u0430\u044F \u043F\u043B\u043E\u0442\u043D\u043E\u0441\u0442\u044C:
-pref.dlg.lbl.Distance= \u0420\u0430\u0441\u0441\u0442\u043E\u044F\u043D\u0438\u0435:
-pref.dlg.lbl.Bulkdensity= \u041E\u0431\u044A\u0435\u043C\u043D\u0430\u044F \u043F\u043B\u043E\u0442\u043D\u043E\u0441\u0442\u044C:
-pref.dlg.lbl.Velocity= \u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C:
-pref.dlg.lbl.Surfaceroughness= \u0428\u0435\u0440\u043E\u0445\u043E\u0432\u0430\u0442\u043E\u0441\u0442\u044C \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u0438:
-pref.dlg.lbl.Acceleration= \u0423\u0441\u043A\u043E\u0440\u0435\u043D\u0438\u0435:
-pref.dlg.lbl.Area= \u041F\u043B\u043E\u0448\u0430\u0434\u044C:
-pref.dlg.lbl.Mass= \u041C\u0430\u0441\u0441\u0430:
-pref.dlg.lbl.Angle= \u0423\u0433\u043E\u043B:
-pref.dlg.lbl.Force= \u0421\u0438\u043B\u0430:
-pref.dlg.lbl.Rollrate= \u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u043A\u0440\u0435\u043D\u0430:
-pref.dlg.lbl.Totalimpulse= \u041F\u043E\u043B\u043D\u044B\u0439 \u0438\u043C\u043F\u0443\u043B\u044C\u0441:
-pref.dlg.lbl.Temperature= \u0422\u0435\u043C\u043F\u0435\u0440\u0430\u0442\u0443\u0440\u0430:
-pref.dlg.lbl.Momentofinertia= \u041C\u043E\u043C\u0435\u043D\u0442 \u0438\u043D\u0435\u0440\u0446\u0438\u0438:
-pref.dlg.lbl.Pressure= \u0414\u0430\u0432\u043B\u0435\u043D\u0438\u0435:
-pref.dlg.lbl.Stability= \u0423\u0441\u0442\u043E\u0439\u0447\u0438\u0432\u043E\u0441\u0442\u044C:
-pref.dlg.lbl.FlightTime= \u0412\u0440\u0435\u043C\u044F \u043F\u043E\u043B\u0435\u0442\u0430:
-pref.dlg.lbl.effect1=\u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u043E\u0442\u043E\u0431\u0440\u0430\u0437\u044F\u0442\u0441\u044F \u043F\u0440\u0438 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u043C \u0432\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0438.
-pref.dlg.lbl.Checkingupdates= \u0418\u0434\u0435\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043D\u0430\u043B\u0438\u0447\u0438\u044F \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438...
-pref.dlg.lbl.msg1= \u0412\u043E\u0437\u043D\u0438\u043A\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u0441\u0432\u044F\u0437\u0438 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043E\u043C.
-pref.dlg.lbl.msg2= \u041D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u043F\u043E\u043B\u0443\u0447\u0442\u044C \u043D\u043E\u0432\u0443\u044E \u0432\u0435\u0440\u0441\u0438\u044E
-pref.dlg.lbl.msg3= \u0412\u044B \u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442\u0435 \u0441 \u0441\u0430\u043C\u043E\u0439 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0435\u0439 OpenRocket.
-pref.dlg.lbl.msg4=  \u041D\u0435\u0442 \u043D\u043E\u0432\u043E\u0439 \u0432\u0435\u0440\u0441\u0438\u0438
-pref.dlg.PrefChoiseSelector1= \u0421\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C \u0432\u0441\u0435\u0433\u0434\u0430
-pref.dlg.PrefChoiseSelector2= \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043D\u0443
-pref.dlg.PrefChoiseSelector3= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0432 \u043A\u043E\u043D\u0435\u0446
-pref.dlg.PrefBooleanSelector1= \u0423\u0434\u0430\u043B\u0438\u0442\u044C
-pref.dlg.PrefBooleanSelector2= \u041F\u043E\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044C
-pref.dlg.Add= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C
-pref.dlg.DescriptionArea.Adddirectories= \u0414\u043B\u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 \u043A\u0440\u0438\u0432\u044B\u0445 \u0442\u044F\u0433\u0438 \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0438, \u0444\u0430\u0438\u043B\u044B \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0435\u0439  \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 RASP (*.eng), \u0444\u0430\u0438\u043B\u044B \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0435\u0439  \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435 RockSim (*.rse) \u0438\u043B\u0438 ZIP \u0430\u0440\u0445\u0438\u0432\u044B \u0447\u0435\u0440\u0435\u0437 \u0442\u043E\u0447\u043A\u0443 \u0441 \u0437\u0430\u043F\u044F\u0442\u043E\u0439 (;). \u0418\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u0441\u043A\u0430\u0436\u0443\u0442\u0441\u044F \u043F\u0440\u0438 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u0439 \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0435 OpenRocket.
-
-PreferencesDialog.lbl.language= \u042F\u0437\u044B\u043A \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430:
-PreferencesDialog.languages.default=\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
-PreferencesDialog.lbl.languageEffect=\u042F\u0437\u044B\u043A \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u0441\u044F \u043F\u0440\u0438 \u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0435\u043C \u0437\u0430\u043F\u0443\u0441\u043A\u0435 OpenRocket.
+pref.dlg.but.add = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c
+pref.dlg.but.reset = \u0421\u0431\u0440\u043e\u0441
+pref.dlg.but.checknow = \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0441\u0435\u0439\u0447\u0430\u0441
+pref.dlg.but.defaultmetric = \u041c\u0435\u0442\u0440\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e
+pref.dlg.but.defaultimperial = \u0418\u043c\u043f\u0435\u0440\u0441\u043a\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e
+pref.dlg.title.Preferences = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+pref.dlg.tab.Units = \u0415\u0434\u0438\u043d\u0438\u0446\u044b \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f
+pref.dlg.tab.Defaultunits = \u0415\u0434\u0438\u043d\u0438\u0446\u044b \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e
+pref.dlg.tab.Materials = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b
+pref.dlg.tab.Custommaterials = \u0421\u0432\u043e\u0438 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b
+pref.dlg.tab.Options = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
+pref.dlg.tab.Miscellaneousoptions = \u041f\u0440\u043e\u0447\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
+pref.dlg.lbl.Positiontoinsert = \u041c\u0435\u0441\u0442\u043e \u0434\u043b\u044f \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432:
+pref.dlg.lbl.Confirmdeletion = \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
+pref.dlg.lbl.User-definedthrust = \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u0438 \u0442\u044f\u0433\u0438:
+pref.dlg.lbl.Windspeed = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0435\u0442\u0440\u0430
+pref.dlg.Allthrustcurvefiles = \u0424\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0444\u0438\u043b\u0435\u0439 \u0442\u044f\u0433\u0438 (*.eng; *.rse; *.zip; \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438)
+pref.dlg.RASPfiles = \u0424\u0430\u0439\u043b\u044b \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439 RASP (*.eng)
+pref.dlg.RockSimfiles = \u0424\u0430\u0439\u043b\u044b \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439 RockSim (*.rse)
+pref.dlg.ZIParchives = ZIP-\u0430\u0440\u0445\u0438\u0432\u044b (*.zip)
+pref.dlg.checkbox.Checkupdates = \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435
+pref.dlg.ttip.Checkupdatesnow = \u041f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438
+pref.dlg.lbl.Selectprefunits = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0435\u0434\u0438\u043d\u0438\u0446\u044b \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f:
+pref.dlg.lbl.Rocketdimensions = \u0420\u0430\u0437\u043c\u0435\u0440\u044b \u0440\u0430\u043a\u0435\u0442\u044b:
+pref.dlg.lbl.Linedensity = \u041b\u0438\u043d\u0435\u0439\u043d\u0430\u044f \u043f\u043b\u043e\u0442\u043d\u043e\u0441\u0442\u044c:
+pref.dlg.lbl.Motordimensions = \u0420\u0430\u0437\u043c\u0435\u0440\u044b \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f:
+pref.dlg.lbl.Surfacedensity = \u041f\u043b\u043e\u0442\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0432\u0435\u0440\u0445\u043d\u043e\u0441\u0442\u0435\u0439:
+pref.dlg.lbl.Distance = \u0420\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435:
+pref.dlg.lbl.Bulkdensity = \u041e\u0431\u044a\u0435\u043c\u043d\u0430\u044f \u043f\u043b\u043e\u0442\u043d\u043e\u0441\u0442\u044c:
+pref.dlg.lbl.Velocity = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c:
+pref.dlg.lbl.Surfaceroughness = \u0428\u0435\u0440\u043e\u0445\u043e\u0432\u0430\u0442\u043e\u0441\u0442\u044c:
+pref.dlg.lbl.Acceleration = \u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435:
+pref.dlg.lbl.Area = \u041f\u043b\u043e\u0449\u0430\u0434\u044c:
+pref.dlg.lbl.Mass = \u041c\u0430\u0441\u0441\u0430:
+pref.dlg.lbl.Angle = \u0423\u0433\u043b\u044b:
+pref.dlg.lbl.Force = \u0421\u0438\u043b\u0430:
+pref.dlg.lbl.Rollrate = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043a\u0440\u0435\u043d\u0430:
+pref.dlg.lbl.Totalimpulse = \u041e\u0431\u0449\u0438\u0439 \u0438\u043c\u043f\u0443\u043b\u044c\u0441:
+pref.dlg.lbl.Temperature = \u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430:
+pref.dlg.lbl.Momentofinertia = \u041c\u043e\u043c\u0435\u043d\u0442 \u0438\u043d\u0435\u0440\u0446\u0438\u0438:
+pref.dlg.lbl.Pressure = \u0414\u0430\u0432\u043b\u0435\u043d\u0438\u0435:
+pref.dlg.lbl.Stability = \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c:
+pref.dlg.lbl.FlightTime = \u0412\u0440\u0435\u043c\u044f \u043f\u043e\u043b\u0435\u0442\u0430:
+pref.dlg.lbl.effect1 = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u044b \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b..
+pref.dlg.lbl.Checkingupdates = \u041f\u043e\u0438\u0441\u043a \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439...
+pref.dlg.lbl.msg1 = \u041f\u0440\u0438 \u043f\u043e\u043f\u044b\u0442\u043a\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u0430 \u043e\u0448\u0438\u0431\u043a\u0430.
+pref.dlg.lbl.msg2 = \u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043e\u0431 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f\u0445.
+pref.dlg.lbl.msg3 = \u0412\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442\u0435 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 OpenRocket.
+pref.dlg.lbl.msg4 = \u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u043e.
+pref.dlg.PrefChoiseSelector1 = \u0412\u0441\u0435\u0433\u0434\u0430 \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c
+pref.dlg.PrefChoiseSelector2 = \u0412\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u0441\u0435\u0440\u0435\u0434\u0438\u043d\u0443
+pref.dlg.PrefChoiseSelector3 = \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u043a\u043e\u043d\u0435\u0446
+pref.dlg.PrefBooleanSelector1 = \u0423\u0434\u0430\u043b\u0438\u0442\u044c
+pref.dlg.PrefBooleanSelector2 = \u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c
+pref.dlg.Add = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c
+pref.dlg.DescriptionArea.Adddirectories = \u0414\u043b\u044f \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0432\u043e\u0438\u0445 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439 \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0438, \u0444\u0430\u0439\u043b\u044b \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439 RASP (*.eng), \u0444\u0430\u0439\u043b\u044b \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439 RockSim (*.rse) \u0438\u043b\u0438 ZIP-\u0430\u0440\u0445\u0438\u0432\u044b, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0442\u043e\u0447\u043a\u043e\u0439 \u0441 \u0437\u0430\u043f\u044f\u0442\u043e\u0439 (;). \u0418\u0437\u043c\u043d\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u0441\u0442\u0443\u043f\u044f\u0442 \u0432 \u0441\u0438\u043b\u0443 \u043f\u0440\u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 OpenRocket.
+
+PreferencesDialog.lbl.language = \u042f\u0437\u044b\u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430:
+PreferencesDialog.languages.default = \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0439
+PreferencesDialog.lbl.languageEffect = \u042f\u0437\u044b\u043a \u0441\u043c\u0435\u043d\u0438\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a\u0435 OpenRocket.
 
 ! Simulation edit dialog
-simedtdlg.but.runsimulation=\u0412\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0440\u0430\u0441\u0447\u0435\u0442
-simedtdlg.but.resettodefault= \u0412\u043E\u0441\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
-simedtdlg.but.add= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C
-simedtdlg.but.remove=\u0423\u0434\u0430\u043B\u0438\u0442\u044C
-simedtdlg.title.Editsim=\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
-simedtdlg.lbl.Simname=\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
-simedtdlg.tab.Launchcond=\u0423\u0441\u043B\u043E\u0432\u0438\u044F \u043F\u0443\u0441\u043A\u0430
-simedtdlg.tab.Simopt=\u041E\u043F\u0446\u0438\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
-simedtdlg.tab.Plotdata=\u041F\u043E\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u0433\u0440\u0430\u0444\u0438\u043A
-simedtdlg.tab.Exportdata=\u042D\u043A\u043F\u043E\u0440\u0442 \u0434\u0430\u043D\u043D\u044B\u0445
-simedtdlg.lbl.Motorcfg=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F:
-simedtdlg.lbl.ttip.Motorcfg= \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F.
-simedtdlg.combo.ttip.motorconf= \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044E \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F.
-simedtdlg.lbl.Wind= \u0412\u0435\u0442\u0435\u0440
-simedtdlg.lbl.Averwindspeed= \u0421\u0440\u0435\u0434\u043D\u044F\u044F \u0441\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u0432\u0435\u0442\u0440\u0430:
-simedtdlg.lbl.ttip.Averwindspeed=\u0421\u0440\u0435\u0434\u043D\u044F\u044F \u0441\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u0432\u0435\u0442\u0440\u0430 \u043F\u043E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044E \u043A \u0437\u0435\u043C\u043B\u0435.
-simedtdlg.lbl.Stddeviation= \u0421\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E\u0435 \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0438\u0435:
-simedtdlg.lbl.ttip.Stddeviation= <html> \u0421\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E\u0435 \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0438\u0435 \u0441\u043A\u043E\u0440\u043E\u0441\u0442\u0438 \u0432\u0435\u0442\u0440\u0430. <br> \u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u0432\u0435\u0442\u0440\u0430 \u043D\u0430\u0445\u043E\u0434\u0438\u0442\u0441\u044F \u0432 \u0433\u0440\u0430\u043D\u0438\u0446\u0430\u0445 \u0434\u0432\u0443\u0445 \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u044B\u0445 \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0438\u0439 \u043E\u0442 \u043E\u0442\u0441\u0440\u0435\u0434\u043D\u0435\u0433\u043E \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F  95% \u0432\u0440\u0435\u043C\u0435\u043D\u0438.
-simedtdlg.lbl.Turbulenceintensity= \u0418\u043D\u0442\u0435\u043D\u0441\u0438\u0432\u043D\u043E\u0441\u0442\u044C \u0442\u0443\u0440\u0431\u0443\u043B\u0435\u043D\u0442\u043D\u043E\u0441\u0442\u0438:
-simedtdlg.lbl.ttip.Turbulenceintensity1= <html> \u0418\u043D\u0442\u0435\u043D\u0441\u0438\u0432\u043D\u043E\u0441\u0442\u044C - \u044D\u0442\u043E \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u043E\u0435 \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0438\u0435, \u043F\u043E\u0434\u0435\u043B\u0435\u043D\u043D\u043E\u0435 \u043D\u0430 \u0441\u0440\u0435\u0434\u043D\u044E\u044E \u0441\u043A\u043E\u0440\u043E\u0441\u0442\u0438 \u0432\u0435\u0442\u0440\u0430. <br>
-simedtdlg.lbl.ttip.Turbulenceintensity2= \u0422\u0438\u043F\u0438\u0447\u043D\u044B\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u043D\u0430\u0445\u043E\u0434\u0438\u0442\u0441\u044F \u0432 \u0434\u0438\u0430\u043F\u0430\u0437\u043E\u043D\u0435 \u043E\u0442
-simedtdlg.lbl.ttip.Turbulenceintensity3=\u0434\u043E
-simedtdlg.border.Atmoscond= \u0410\u0442\u043C\u043E\u0441\u0444\u0435\u0440\u043D\u044B\u0435 \u0443\u0441\u043B\u043E\u0432\u0438\u044F
-simedtdlg.checkbox.InterStdAtmosphere= \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u041C\u0435\u0436\u0434\u0443\u043D\u0430\u0440\u043E\u0434\u043D\u0443\u044E \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u0443\u044E \u0430\u0442\u043C\u043E\u0441\u0444\u0435\u0440\u0443
-simedtdlg.checkbox.ttip.InterStdAtmosphere1= <html> \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u041C\u0435\u0436\u0434\u0443\u043D\u0430\u0440\u043E\u0434\u043D\u0443\u044E \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u0443\u044E \u043C\u043E\u0434\u0435\u043B\u044C \u0430\u0442\u043C\u043E\u0441\u0444\u0435\u0440\u044B. <br> \u042D\u0442\u0430 \u043C\u043E\u0434\u0435\u043B\u044C \u0438\u043C\u0435\u0435\u0442 \u0442\u0435\u043C\u043F\u0435\u0440\u0430\u0442\u0443\u0440\u0443
-simedtdlg.checkbox.ttip.InterStdAtmosphere2= \u0438 \u0434\u0430\u0432\u043B\u0435\u043D\u0438\u0438
-simedtdlg.checkbox.ttip.InterStdAtmosphere3= \u043D\u0430 \u0443\u0440\u043E\u0432\u043D\u0435 \u043C\u043E\u0440\u044F.
-simedtdlg.lbl.Temperature=\u0422\u0435\u043C\u043F\u0435\u0440\u0430\u0442\u0443\u0440\u0430:
-simedtdlg.lbl.ttip.Temperature=\u0422\u0435\u043C\u043F\u0435\u0440\u0430\u0442\u0443\u0440\u0430 \u043D\u0430 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0439 \u043F\u043B\u043E\u0449\u0430\u0434\u043A\u0435.
-simedtdlg.lbl.Pressure= \u0414\u0430\u0432\u043B\u0435\u043D\u0438\u0435:
-simedtdlg.lbl.ttip.Pressure=\u0410\u0442\u043C\u043E\u0441\u0444\u0435\u0440\u043D\u043E\u0435 \u0434\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u0430 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0439 \u043F\u043B\u043E\u0449\u0430\u0434\u043A\u0435.
-simedtdlg.lbl.Launchsite=\u0421\u0442\u0430\u0440\u0442\u043E\u0432\u0430\u044F \u043F\u043B\u043E\u0449\u0430\u0434\u043A\u0430
-simedtdlg.lbl.Latitude= \u0428\u0438\u0440\u043E\u0442\u0430:
-simedtdlg.lbl.ttip.Latitude= <html> \u0428\u0438\u0440\u043E\u0442\u0430 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0439 \u043F\u043B\u043E\u0449\u0430\u0434\u043A\u0438 \u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0435\u0442\u0441\u044F \u043D\u0430 \u0433\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u043E\u043D\u043D\u043E\u043C \u043F\u0440\u0438\u0442\u044F\u0436\u0435\u043D\u0438\u0438 \u0417\u0435\u043C\u043B\u0438. <br> \u041F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044E\u0442 \u0421\u0435\u0432\u0435\u0440\u043D\u043E\u043C\u0443 \u043F\u043E\u043B\u0443\u0448\u0430\u0440\u0438\u044E, \u0430 \u043E\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044F - \u044E\u0436\u043D\u043E\u043C\u0443 \u043F\u043E\u043B\u0443\u0448\u0430\u0440\u0438\u0438.
-
-simedtdlg.lbl.Longitude= \u0414\u043E\u043B\u0433\u043E\u0442\u0430:
-simedtdlg.lbl.ttip.Longitude= <html>\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F \u043F\u0440\u043E\u0433\u043D\u043E\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u043F\u043E\u0433\u043E\u0434\u044B \u0438 \u043C\u043E\u0434\u0435\u043B\u0438 \u0432\u044B\u0441\u043E\u0442\u044B.
-
-simedtdlg.lbl.Altitude= \u0412\u044B\u0441\u043E\u0442\u0430:
-simedtdlg.lbl.ttip.Altitude= <html> \u0412\u044B\u0441\u043E\u0442\u0430 \u043F\u0443\u0441\u043A\u0430 \u043D\u0430\u0434 \u0443\u0440\u043E\u0432\u043D\u0435\u043C \u043C\u043E\u0440\u044F. <br> \u0412\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u0440\u0430\u043A\u0435\u0442\u044B \u0432 \u043C\u043E\u0434\u0435\u043B\u0438 \u0430\u0442\u043C\u043E\u0441\u0444\u0435\u0440\u044B.
-simedtdlg.border.Launchrod=\u0421\u0442\u0430\u0440\u0442\u043E\u0432\u044B\u0439 \u0441\u0442\u0435\u0440\u0436\u0435\u043D\u044C
-simedtdlg.lbl.Length= \u0414\u043B\u0438\u043D\u0430:
-simedtdlg.lbl.ttip.Length= \u0414\u043B\u0438\u043D\u0430 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0433\u043E \u0441\u0442\u0435\u0440\u0436\u043D\u044F.
-simedtdlg.lbl.Angle= \u0423\u0433\u043E\u043B \u043D\u0430\u043A\u043B\u043E\u043D\u0430:
-simedtdlg.lbl.ttip.Angle= \u0423\u0433\u043E\u043B \u043E\u0442\u043A\u043B\u043E\u043D\u0435\u043D\u0438\u044F \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0433\u043E \u0441\u0442\u0435\u0440\u0436\u043D\u044F \u043E\u0442 \u0432\u0435\u0440\u0442\u0438\u043A\u0430\u043B\u0438.
-simedtdlg.lbl.Direction= \u041D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435:
-simedtdlg.lbl.ttip.Direction1= <html> \u041D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u0430\u043A\u043B\u043E\u043D\u0430 \u0441\u0442\u0430\u0440\u0442\u043E\u0432\u043E\u0433\u043E \u0441\u0442\u0435\u0440\u0436\u043D\u044F \u043F\u043E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044E \u043A \u0432\u0435\u0442\u0440\u0443. <br>
-simedtdlg.lbl.ttip.Direction2= = \u043A \u0432\u0435\u0442\u0440\u0443,
-simedtdlg.lbl.ttip.Direction3= = \u043E\u0442 \u0432\u0435\u0442\u0440\u0430.
-simedtdlg.border.Simopt=\u041E\u043F\u0446\u0438\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
-simedtdlg.lbl.Calcmethod=\u041C\u0435\u0442\u043E\u0434 \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
-simedtdlg.lbl.ttip.Calcmethod= <html> \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u043D\u044B\u0439 \u043C\u0435\u0442\u043E\u0434 \u0411\u043E\u0440\u0440\u043E\u043C\u0430\u043D\u0430 \u0440\u0430\u0441\u0447\u0438\u0442\u044B\u0432\u0430\u0435\u0442  \u0430\u044D\u0440\u043E\u0434\u0438\u043D\u0430\u043C\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0432\u043E\u0437\u0434\u0435\u0441\u0442\u0432\u0438\u044F \u0441\u043E\u0433\u043B\u0430\u0441\u043D\u043E <br> \u0444\u043E\u0440\u043C\u0443\u043B\u0430\u043C \u0411\u043E\u0440\u0440\u043E\u043C\u0430\u043D\u0430 \u043F\u0435\u0440\u0435\u0440\u0430\u0431\u043E\u0442\u0430\u043D\u043D\u044B\u043C  \u0441 \u0443\u0447\u0435\u0442\u043E\u043C \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0445 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u043E\u0432.
-simedtdlg.lbl.ExtBarrowman=\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u043D\u044B\u0439 \u043C\u0435\u0442\u043E\u0434 \u0411\u043E\u0440\u0440\u043E\u043C\u0430\u043D\u0430
-simedtdlg.lbl.Simmethod=\u041C\u0435\u0442\u043E\u0434 \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
-simedtdlg.lbl.ttip.Simmethod1= <html> \u0420\u0430\u0441\u0447\u0435\u0442 \u0434\u043B\u044F \u0448\u0435\u0441\u0442\u0438 \u0441\u0442\u0435\u043F\u0435\u043D\u0435\u0439 \u0441\u0432\u043E\u0431\u043E\u0434\u044B \u0434\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u0442 \u043F\u043E\u043B\u043D\u0443\u044E \u0441\u0432\u043E\u0431\u043E\u0434\u0443 \u0440\u0430\u043A\u0435\u0442\u044B \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u043F\u043E\u043B\u0435\u0442\u0430.<br>
-simedtdlg.lbl.ttip.Simmethod2= \u0418\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044F \u043E\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043C\u0435\u0442\u043E\u0434\u0430 <sup> </ sup> \u0447\u0438\u0441\u043B\u0435\u043D\u043D\u043E\u0433\u043E \u0438\u043D\u0442\u0435\u0433\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F \u0420\u0443\u043D\u0433\u0435-\u041A\u0443\u0442\u0442\u0430 4\u0433\u043E \u043F\u043E\u0440\u044F\u0434\u043A\u0430.
-simedtdlg.lbl.GeodeticMethod= \u0413\u0435\u043E\u0434\u0435\u0437\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044B:
-simedtdlg.lbl.ttip.GeodeticMethodTip=\u041E\u0442\u043D\u043E\u0441\u044F\u0442\u0441\u044F \u043A \u0440\u0430\u0441\u0447\u0435\u0442\u0443 \u043A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442 \u043D\u0430 \u0437\u0435\u043C\u043D\u043E\u0439 \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u0438. \u0422\u0430\u043A\u0436\u0435 \u0432\u044B\u0447\u0438\u0441\u043B\u044F\u0435\u0442\u0441\u044F\u0432\u043B\u0438\u044F\u043D\u0438\u0435 \u044D\u0444\u0444\u0435\u043A\u0442\u0430 \u041A\u043E\u0440\u0438\u043E\u043B\u0438\u0441\u0430.
-simedtdlg.lbl.Timestep=\u0428\u0430\u0433 \u0432\u0440\u0435\u043C\u0435\u043D\u0438:
-simedtdlg.lbl.ttip.Timestep1= <html> \u0412\u0440\u0435\u043C\u044F \u043C\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043C\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430. <br> \u041C\u0435\u043D\u044C\u0448\u0438\u0439 \u0448\u0430\u0433 \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u043F\u0440\u0438\u0432\u043E\u0434\u0438\u0442 \u043A \u0431\u043E\u043B\u0435\u0435 \u0442\u043E\u0447\u043D\u043E\u043C\u0443, \u043D\u043E \u0431\u043E\u043B\u0435\u0435 \u043C\u0435\u0434\u043B\u0435\u043D\u043D\u043E\u043C\u0443 \u0440\u0430\u0441\u0447\u0435\u0442\u0443. <br>
-simedtdlg.lbl.ttip.Timestep2= \u041C\u0435\u0442\u043E\u0434 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 <sup> </ sup>4\u043E\u0439 \u0441\u0442\u0435\u043F\u0435\u043D\u0438 \u0434\u043E\u0441\u0442\u0430\u0442\u043E\u0447\u043D\u043E \u0442\u043E\u0447\u0435\u043D \u043F\u0440\u0438 \u0448\u0430\u0433\u0435
-simedtdlg.but.ttip.resettodefault= \u0421\u0431\u0440\u043E\u0441 \u0448\u0430\u0433 \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u043A \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u044E \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E (
-simedtdlg.border.Simlist=\u0421\u043B\u0443\u0448\u0430\u0442\u0435\u043B\u044C \u0440\u0430\u0441\u0447\u0435\u0442\u0430
-simedtdlg.txt.longA1= <html> <i> \u0421\u043B\u0443\u0448\u0430\u0442\u0435\u043B\u044C \u0440\u0430\u0441\u0447\u0435\u0442\u0430 </i> \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0434\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E\u0439 \u0444\u0443\u043D\u043A\u0446\u0438\u0435\u0439, \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u044E\u0449\u0435\u0439 \u0438\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u043E\u0435 \u0432\u0437\u0430\u0438\u043C\u043E\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043A\u043E\u0434\u0430 \u043D\u0430\u043F\u0438\u0441\u0430\u043D\u043D\u043E\u0433\u043E \u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u0435\u043B\u0435\u043C\u0441 \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u043E\u0439 \u0440\u0430\u0441\u0447\u0435\u0442\u0430.
-simedtdlg.txt.longA2=\u0421\u043C \u0442\u0435\u0445\u043D\u0438\u0447\u0435\u0441\u043A\u043E\u0435 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 OpenRocke \u0434\u043B\u044F \u0434\u0435\u0442\u0430\u043B\u0435\u0439 \u0421\u043B\u0443\u0448\u0430\u0442\u0435\u043B\u044F \u0440\u0430\u0441\u0447\u0435\u0442\u0430.
-simedtdlg.lbl.Curlist=\u0420\u0430\u0431\u043E\u0442\u0430\u044E\u0449\u0438\u0435 \u0441\u043B\u0443\u0448\u0430\u0442\u0435\u043B\u0438: 
-simedtdlg.lbl.Addsimlist=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u043B\u0443\u0448\u0430\u0442\u0435\u043B\u044C \u0440\u0430\u0441\u0447\u0435\u0442\u0430
-simedtdlg.lbl.Noflightdata=\u041B\u0435\u0442\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044E\u0442.
-simedtdlg.lbl.runsimfirst= \u0417\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u0435 \u0440\u0430\u0441\u0447\u0435\u0442 \u0432 \u043F\u0435\u0440\u0432\u0443\u044E \u043E\u0447\u0435\u0440\u0435\u0434\u044C.
-simedtdlg.chart.Simflight=\u041C\u043E\u0434\u0435\u043B\u0438\u0440\u0443\u0435\u043C\u044B\u0439 \u043F\u043E\u043B\u0435\u0442
-simedtdlg.dlg.Simres=\u0420\u0435\u0437\u0443\u043B\u044C\u0442\u0430\u0442\u044B \u043C\u043E\u0434\u0435\u043B\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u044F
-simedtdlg.IntensityDesc.None=\u041E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442
-simedtdlg.IntensityDesc.Verylow=\u041E\u0447\u0435\u043D\u044C \u043D\u0438\u0437\u043A\u0430\u044F
-simedtdlg.IntensityDesc.Low=\u041D\u0438\u0437\u043A\u0430\u044F
-simedtdlg.IntensityDesc.Medium=\u0421\u0440\u0435\u0434\u043D\u044F\u044F
-simedtdlg.IntensityDesc.High=\u0412\u044B\u0441\u043E\u043A\u0430\u044F
-simedtdlg.IntensityDesc.Veryhigh= \u041E\u0447\u0435\u043D\u044C \u0432\u044B\u0441\u043E\u043A\u0430\u044F
-simedtdlg.IntensityDesc.Extreme= \u042D\u043A\u0441\u0442\u0440\u0435\u043C\u0430\u043B\u044C\u043D\u0430\u044F
-
-GeodeticComputationStrategy.flat.name=\u041F\u043B\u043E\u0441\u043A\u0430\u044F \u0417\u0435\u043C\u043B\u044F
-GeodeticComputationStrategy.flat.desc=\u0412\u044B\u043F\u043E\u043B\u043D\u044F\u0442\u044C \u0432\u044B\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u044F \u0441  \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u0435\u043C \u043F\u0440\u0438\u0431\u043B\u0438\u0436\u0435\u043D\u0438\u044F \u043F\u043B\u043E\u0441\u043A\u043E\u0439 \u0417\u0435\u043C\u043B\u0438. \u0422\u043E\u0447\u043D\u043E\u0441\u0442\u044C \u0434\u043E\u0441\u0442\u0430\u0442\u043E\u0447\u043D\u0430 \u0434\u043B\u044F \u043D\u0438\u0437\u043A\u0438\u0445 \u0432\u044B\u0441\u043E\u0442.
-GeodeticComputationStrategy.spherical.name=\u0421\u0444\u0435\u0440\u0438\u0447\u0435\u0441\u043A\u043E\u0435 \u043F\u0440\u0438\u0431\u043B\u0438\u0436\u0435\u043D\u0438\u0435
-GeodeticComputationStrategy.spherical.desc= <html> \u0412\u044B\u043F\u043E\u043B\u043D\u044F\u0442\u044C \u0433\u0435\u043E\u0434\u0435\u0437\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044B \u0432 \u043F\u0440\u0435\u0434\u043F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0438 \u0441\u0444\u0435\u0440\u0438\u0447\u0435\u0441\u043A\u043E\u0439 \u0417\u0435\u043C\u043B\u0438. <br> \u0422\u043E\u0447\u043D\u043E\u0441\u0442\u044C \u0434\u043E\u0441\u0442\u0430\u0442\u043E\u0447\u043D \u043F\u0440\u0430\u043A\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0434\u043B\u044F \u043B\u044E\u0431\u044B\u0445 \u0446\u0435\u043B\u0435\u0439.
-GeodeticComputationStrategy.wgs84.name= WGS84 \u044D\u043B\u043B\u0438\u043F\u0441\u043E\u0438\u0434
-GeodeticComputationStrategy.wgs84.desc= <html> \u0412\u044B\u043F\u043E\u043B\u043D\u044F\u0442\u044C \u0433\u0435\u043E\u0434\u0435\u0437\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0432\u044B\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u044F \u0434\u043B\u044F WGS84 \u044D\u043B\u043B\u0438\u043F\u0441\u043E\u0438\u0434\u0430 \u043C\u0435\u0442\u043E\u0434\u043E\u043C \u0412\u0438\u043D\u0441\u0435\u043D\u0442\u0440\u0438 <br> \u041C\u0435\u0434\u043B\u0435\u043D\u043D\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442 \u0438\u0437\u043B\u0438\u0448\u043D\u0438\u0439 \u0432 \u0431\u043E\u043B\u044C\u0448\u0438\u043D\u0441\u0442\u0432\u0435 \u0441\u043B\u0443\u0447\u0430\u0435\u0432.
+simedtdlg.but.runsimulation = \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0447\u0435\u0442
+simedtdlg.but.resettodefault = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e
+simedtdlg.but.add = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c
+simedtdlg.but.remove = \u0423\u0434\u0430\u043b\u0438\u0442\u044c
+simedtdlg.title.Editsim = \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+simedtdlg.lbl.Simname = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
+simedtdlg.tab.Launchcond = \u0423\u0441\u043b\u043e\u0432\u0438\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430
+simedtdlg.tab.Simopt = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+simedtdlg.tab.Plotdata = \u0413\u0440\u0430\u0444\u0438\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445
+simedtdlg.tab.CustomExpressions = \u0421\u0432\u043e\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f
+simedtdlg.tab.Exportdata = \u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0434\u0430\u043d\u043d\u044b\u0445
+simedtdlg.lbl.Motorcfg = \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f:
+simedtdlg.lbl.ttip.Motorcfg = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f.
+simedtdlg.combo.ttip.motorconf = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f.
+simedtdlg.lbl.Wind = \u0412\u0435\u0442\u0435\u0440
+simedtdlg.lbl.Averwindspeed = \u0421\u0440\u0435\u0434\u043d\u044f\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0435\u0442\u0440\u0430:
+simedtdlg.lbl.ttip.Averwindspeed = \u0421\u0440\u0435\u0434\u043d\u044f\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0435\u0442\u0440\u0430 \u043f\u043e \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044e \u043a \u0437\u0435\u043c\u043b\u0435.
+simedtdlg.lbl.Stddeviation = \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u0435:
+simedtdlg.lbl.ttip.Stddeviation = <html>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0432\u0435\u0442\u0440\u0430.<br>\u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0435\u0442\u0440\u0430 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0433\u0440\u0430\u043d\u0438\u0446\u0430\u0445 \u0434\u0432\u0443\u0445 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u0439 \u043e\u0442 \u043e\u0442 \u0441\u0440\u0435\u0434\u043d\u0435\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f 95% \u0432\u0440\u0435\u043c\u0435\u043d\u0438.
+simedtdlg.lbl.Turbulenceintensity = \u0418\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0442\u0443\u0440\u0431\u0443\u043b\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u0438:
+simedtdlg.lbl.ttip.Turbulenceintensity1 = <html>\u0418\u043d\u0442\u0435\u043d\u0441\u0438\u0432\u043d\u043e\u0441\u0442\u044c \u0442\u0443\u0440\u0431\u0443\u043b\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u0438 - \u044d\u0442\u043e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u0435, \u043f\u043e\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0435 \u043d\u0430 \u0441\u0440\u0435\u0434\u043d\u044e\u044e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u0432\u0435\u0442\u0440\u0430.<br>
+simedtdlg.lbl.ttip.Turbulenceintensity2 = \u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0435 \u043e\u0442
+simedtdlg.lbl.ttip.Turbulenceintensity3 = \u0434\u043e
+simedtdlg.border.Atmoscond = \u0410\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u043d\u044b\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f
+simedtdlg.checkbox.InterStdAtmosphere = \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043c\u0435\u0436\u0434\u0443\u043d\u0430\u0440\u043e\u0434\u043d\u0443\u044e \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0430\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u0443
+simedtdlg.checkbox.ttip.InterStdAtmosphere1 = <html>\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u043c\u0435\u0436\u0434\u0443\u043d\u0430\u0440\u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0430\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u044b<br>\u0412 \u044d\u0442\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430
+simedtdlg.checkbox.ttip.InterStdAtmosphere2 = \u0438 \u0434\u0430\u0432\u043b\u0435\u043d\u0438\u0435
+simedtdlg.checkbox.ttip.InterStdAtmosphere3 = \u043d\u0430 \u0443\u0440\u043e\u0432\u043d\u0435 \u043c\u043e\u0440\u044f.
+simedtdlg.lbl.Temperature = \u0422\u0435\u043c\u0435\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430:
+simedtdlg.lbl.ttip.Temperature = \u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0435.
+simedtdlg.lbl.Pressure = \u0414\u0430\u0432\u043b\u0435\u043d\u0438\u0435:
+simedtdlg.lbl.ttip.Pressure = \u0410\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u043d\u043e\u0435 \u0434\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0435.
+simedtdlg.lbl.Launchsite = \u0421\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u044f \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0430
+simedtdlg.lbl.Latitude = \u0428\u0438\u0440\u043e\u0442\u0430:
+simedtdlg.lbl.ttip.Latitude = <html>\u0428\u0438\u0440\u043e\u0442\u0430 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0438 \u0441\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0433\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u0442\u044f\u0436\u0435\u043d\u0438\u0438 \u0417\u0435\u043c\u043b\u0438.<br>\u041f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0421\u0435\u0432\u0435\u0440\u043d\u043e\u043c\u0443 \u043f\u043e\u043b\u0443\u0448\u0430\u0440\u0438\u044e, \u0430 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 - \u042e\u0436\u043d\u043e\u043c\u0443 \u043f\u043e\u043b\u0443\u0448\u0430\u0440\u0438\u044e.
+
+simedtdlg.lbl.Longitude = \u0414\u043e\u043b\u0433\u043e\u0442\u0430:
+simedtdlg.lbl.ttip.Longitude = <html>\u0422\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u043e\u0433\u043d\u043e\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u0433\u043e\u0434\u044b \u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432\u044b\u0441\u043e\u0442\u044b.
+
+simedtdlg.lbl.Altitude = \u0412\u044b\u0441\u043e\u0442\u0430:
+simedtdlg.lbl.ttip.Altitude = <html>\u0412\u044b\u0441\u043e\u0442\u0430 \u043f\u0443\u0441\u043a\u0430 \u043d\u0430\u0434 \u0443\u0440\u043e\u0432\u043d\u0435\u043c \u043c\u043e\u0440\u044f.<br>\u0412\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0440\u0430\u043a\u0435\u0442\u044b \u0432 \u043c\u043e\u0434\u0435\u043b\u0438 \u0430\u0442\u043c\u043e\u0441\u0444\u0435\u0440\u044b.
+simedtdlg.border.Launchrod = \u0421\u0442\u0430\u0440\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u0440\u0436\u0435\u043d\u044c
+simedtdlg.lbl.Length = \u0414\u043b\u0438\u043d\u0430:
+simedtdlg.lbl.ttip.Length = \u0414\u043b\u0438\u043d\u0430 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u0440\u0436\u043d\u044f.
+simedtdlg.lbl.Angle = \u0423\u0433\u043e\u043b:
+simedtdlg.lbl.ttip.Angle = \u0423\u0433\u043e\u043b \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u0440\u0436\u043d\u044f \u043e\u0442 \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u0438.
+simedtdlg.lbl.Direction = \u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435:
+simedtdlg.lbl.ttip.Direction1 = <html>\u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u0440\u0436\u043d\u044f \u043f\u043e \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044e \u043a \u0432\u0435\u0442\u0440\u0443.<br>
+simedtdlg.lbl.ttip.Direction2 = \u043a \u0432\u0435\u0442\u0440\u0443,
+simedtdlg.lbl.ttip.Direction3 = \u043e\u0442 \u0432\u0435\u0442\u0440\u0430.
+simedtdlg.border.Simopt = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+simedtdlg.lbl.Calcmethod = \u041c\u0435\u0442\u043e\u0434 \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
+simedtdlg.lbl.ttip.Calcmethod = <html>\u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0411\u043e\u0440\u0440\u043e\u043c\u0430\u043d\u0430 \u0440\u0430\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u0442 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0432\u043e\u0437\u0434\u0435\u0441\u0442\u0432\u0438\u044f \u0441\u043e\u0433\u043b\u0430\u0441\u043d\u043e<br>\u0444\u043e\u0440\u043c\u0443\u043b\u0430\u043c \u0411\u043e\u0440\u0440\u043e\u043c\u0430\u043d\u0430, \u043f\u0435\u0440\u0435\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u043c \u0441 \u0443\u0447\u0435\u0442\u043e\u043c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432.
+simedtdlg.lbl.ExtBarrowman = \u0420\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u0411\u043e\u0440\u0440\u043e\u043c\u0430\u043d\u0430
+simedtdlg.lbl.Simmethod = \u041c\u0435\u0442\u043e\u0434 \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
+simedtdlg.lbl.ttip.Simmethod1 = <html>\u0420\u0430\u0441\u0447\u0435\u0442 \u0434\u043b\u044f \u0448\u0435\u0441\u0442\u0438 \u0441\u0442\u0435\u043f\u0435\u043d\u0435\u0439 \u0441\u0432\u043e\u0431\u043e\u0434\u044b \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043f\u043e\u043b\u043d\u0443\u044e \u0441\u0432\u043e\u0431\u043e\u0434\u0443 \u0440\u0430\u043a\u0435\u0442\u044b \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043b\u0435\u0442\u0430<br>
+simedtdlg.lbl.ttip.Simmethod2 = \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0435\u0442\u043e\u0434\u0430 \u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0420\u0443\u043d\u0433\u0435-\u041a\u0443\u0442\u0442\u0430 4\u0433\u043e \u043f\u043e\u0440\u044f\u0434\u043a\u0430.
+simedtdlg.lbl.GeodeticMethod = \u0413\u0435\u043e\u0434\u0435\u0437\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044b:
+simedtdlg.lbl.ttip.GeodeticMethodTip = \u041e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u0440\u0430\u0441\u0447\u0435\u0442\u0443 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u043d\u0430 \u0437\u0435\u043c\u043d\u043e\u0439 \u043f\u043e\u0432\u0435\u0440\u0445\u043d\u043e\u0441\u0442\u0438. \u0422\u0430\u043a\u0436\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u0442\u0441\u044f \u0432\u043b\u0438\u044f\u043d\u0438\u0435 \u044d\u0444\u0444\u0435\u043a\u0442\u0430 \u041a\u043e\u0440\u0438\u043e\u043b\u0438\u0441\u0430.
+simedtdlg.lbl.Timestep = \u0412\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0448\u0430\u0433:
+simedtdlg.lbl.ttip.Timestep1 = <html>\u0412\u0440\u0435\u043c\u044f \u043c\u0435\u0436\u0434\u0443 \u0448\u0430\u0433\u0430\u043c\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430.<br>\u041c\u0435\u043d\u044c\u0448\u0438\u0439 \u0448\u0430\u0433 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0431\u043e\u043b\u0435\u0435 \u0442\u043e\u0447\u043d\u043e\u043c\u0443, \u043d\u043e \u0431\u043e\u043b\u0435\u0435 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u043c\u0443 \u0440\u0430\u0441\u0447\u0435\u0442\u0443.<br>
+simedtdlg.lbl.ttip.Timestep2 = \u041c\u0435\u0442\u043e\u0434 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 4\u043e\u0439 \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0442\u043e\u0447\u0435\u043d \u043f\u0440\u0438 \u0448\u0430\u0433\u0435
+simedtdlg.but.ttip.resettodefault = \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0448\u0430\u0433 \u043d\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e (
+simedtdlg.border.Simlist = \u0421\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+simedtdlg.txt.longA1 = <html><i>\u0421\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430</i> - \u044d\u0442\u043e \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0430\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u043c \u043f\u0440\u043e\u0441\u043b\u0443\u0448\u0438\u0432\u0430\u0442\u044c \u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u043c.
+simedtdlg.txt.longA2 = \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f\u0445 \u0440\u0430\u0441\u0447\u0435\u0442\u0430, \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 OpenRocket.
+simedtdlg.lbl.Curlist = \u0422\u0435\u043a\u0443\u0449\u0438\u0435 \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0438:
+simedtdlg.lbl.Addsimlist = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+simedtdlg.lbl.Noflightdata = \u041d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0442\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.
+simedtdlg.lbl.runsimfirst = \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0440\u0430\u0441\u0447\u0435\u0442.
+simedtdlg.chart.Simflight = \u041c\u043e\u0434\u0435\u043b\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u043f\u043e\u043b\u0435\u0442
+simedtdlg.dlg.Simres = \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+simedtdlg.IntensityDesc.None = \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442
+simedtdlg.IntensityDesc.Verylow = \u041e\u0447\u0435\u043d\u044c \u043d\u0438\u0437\u043a\u0430\u044f
+simedtdlg.IntensityDesc.Low = \u041d\u0438\u0437\u043a\u0430\u044f
+simedtdlg.IntensityDesc.Medium = \u0421\u0440\u0435\u0434\u043d\u044f\u044f
+simedtdlg.IntensityDesc.High = \u0412\u044b\u0441\u043e\u043a\u0430\u044f
+simedtdlg.IntensityDesc.Veryhigh = \u041e\u0447\u0435\u043d\u044c \u0432\u044b\u0441\u043e\u043a\u0430\u044f
+simedtdlg.IntensityDesc.Extreme = \u042d\u043a\u0441\u0442\u0440\u0435\u043c\u0430\u043b\u044c\u043d\u0430\u044f
+
+GeodeticComputationStrategy.flat.name = \u041f\u043b\u043e\u0441\u043a\u0430\u044f \u0417\u0435\u043c\u043b\u044f
+GeodeticComputationStrategy.flat.desc = \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u044f \u043f\u043b\u043e\u0441\u043a\u043e\u0439 \u0417\u0435\u043c\u043b\u0438. \u0422\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430 \u0434\u043b\u044f \u043d\u0438\u0437\u043a\u0438\u0445 \u0432\u044b\u0441\u043e\u0442.
+GeodeticComputationStrategy.spherical.name = \u0421\u0444\u0435\u0440\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u0435
+GeodeticComputationStrategy.spherical.desc = <html>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0433\u0435\u043e\u0434\u0435\u0437\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044b \u0432 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0441\u0444\u0435\u0440\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0417\u0435\u043c\u043b\u0438.<br>\u0422\u043e\u0447\u043d\u043e\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0434\u043b\u044f \u043b\u044e\u0431\u044b\u0445 \u0446\u0435\u043b\u0435\u0439.
+GeodeticComputationStrategy.wgs84.name = WGS84 \u044d\u043b\u043b\u0438\u043f\u0441\u043e\u0438\u0434
+GeodeticComputationStrategy.wgs84.desc = <html>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0433\u0435\u043e\u0434\u0435\u0437\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0434\u043b\u044f WGS84 \u044d\u043b\u043b\u0438\u043f\u0441\u043e\u0438\u0434\u0430 \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0412\u0438\u043d\u0441\u0435\u043d\u0442\u0440\u0438<br>\u041c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u0439 \u0440\u0430\u0441\u0447\u0435\u0442, \u0438\u0437\u043b\u0438\u0448\u043d\u0438\u0439 \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432.
 
 
 
 
 ! Simulation Panel
-simpanel.but.newsimulation=\u041D\u043E\u0432\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.but.editsimulation=\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.but.runsimulations=\u0417\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.but.deletesimulations=\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.but.plotexport=\u041F\u0435\u0447\u0430\u0442\u044C / \u042D\u043A\u0441\u043F\u043E\u0440\u0442
-simpanel.but.ttip.newsimulation=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043D\u043E\u0432\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.but.ttip.editsim=\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.but.ttip.runsimu=\u0417\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0435\u0449\u0435 \u0440\u0430\u0437 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.but.ttip.deletesim=\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.checkbox.donotask= \u0411\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C
-simpanel.lbl.defpref= \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u044B\u0439 \u043F\u043E\u0440\u044F\u0434\u043E\u043A \u0440\u0430\u0431\u043E\u0442\u044B \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445.
-simpanel.dlg.lbl.DeleteSim1= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0439 \u0440\u0430\u0441\u0447\u0435\u0442?
-simpanel.dlg.lbl.DeleteSim2= <html><i> \u042D\u0442\u0430 \u043E\u043F\u0435\u0440\u0430\u0446\u0438\u044F \u043D\u0435 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430 </i>
-simpanel.dlg.lbl.DeleteSim3= \u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0440\u0430\u0441\u0447\u0435\u0442
-simpanel.col.Name=\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435
-simpanel.col.Motors= \u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0438
-simpanel.col.Velocityoffrod=\u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u0441\u0445\u043E\u0434\u0430 \u0441\u043E \u0441\u0442\u0435\u0440\u0436\u043D\u044F
-simpanel.col.Velocityatdeploy=\u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u043F\u0440\u0438 \u0440\u0430\u0441\u043A\u0440\u044B\u0442\u0438\u0438 \u043F\u0430\u0440\u0430\u0448\u044E\u0442\u0430
-simpanel.col.Apogee=\u0410\u043F\u043E\u0433\u0435\u0439
-simpanel.col.Maxvelocity= \u041C\u0430\u043A\u0441. \u0441\u043A\u043E\u0440\u043E\u0441\u0442\u044C
-simpanel.col.Maxacceleration= \u041C\u0430\u043A\u0441. \u0443\u0441\u043A\u043E\u0440\u0435\u043D\u0438\u0435
-simpanel.col.Timetoapogee=\u0412\u0440\u0435\u043C\u044F \u0434\u043E \u0430\u043F\u043E\u0433\u0435\u044F
-simpanel.col.Flighttime= \u0412\u0440\u0435\u043C\u044F \u043F\u043E\u043B\u0435\u0442\u0430
-simpanel.col.Groundhitvelocity=\u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u043F\u0440\u0438\u0437\u0435\u043C\u043B\u0435\u043D\u0438\u044F
+simpanel.but.newsimulation = \u041d\u043e\u0432\u044b\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
+simpanel.but.editsimulation = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0447\u0435\u0442
+simpanel.but.runsimulations = \u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0447\u0435\u0442\u044b
+simpanel.but.deletesimulations = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0440\u0430\u0441\u0447\u0435\u0442\u044b
+simpanel.but.plotexport = \u0413\u0440\u0430\u0444\u0438\u043a\u0438 / \u044d\u043a\u0441\u043f\u043e\u0440\u0442
+simpanel.but.ttip.newsimulation = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
+simpanel.but.ttip.editsim = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
+simpanel.but.ttip.runsimu = \u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
+simpanel.but.ttip.deletesim = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044b
+simpanel.checkbox.donotask = \u0411\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c
+simpanel.lbl.defpref = \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445.
+simpanel.dlg.lbl.DeleteSim1 = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044b?
+simpanel.dlg.lbl.DeleteSim2 = <html><i>\u042d\u0442\u0443 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u044c.</i>
+simpanel.dlg.lbl.DeleteSim3 = \u0423\u0434\u0430\u043b\u0435\u043d\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u0432
+simpanel.col.Name = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435
+simpanel.col.Motors = \u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0438
+simpanel.col.Velocityoffrod = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043e\u0442\u0440\u044b\u0432\u0430
+simpanel.col.Velocityatdeploy = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u0440\u0430\u0437\u0432\u0435\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u0438
+simpanel.col.Apogee = \u0410\u043f\u043e\u0433\u0435\u0439
+simpanel.col.Maxvelocity = \u041c\u0430\u043a\u0441. \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
+simpanel.col.Maxacceleration = \u041c\u0430\u043a\u0441. \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435
+simpanel.col.Timetoapogee = \u0412\u0440\u0435\u043c\u044f \u0434\u043e \u0430\u043f\u043e\u0433\u0435\u044f
+simpanel.col.Flighttime = \u0412\u0440\u0435\u043c\u044f \u043f\u043e\u043b\u0435\u0442\u0430
+simpanel.col.Groundhitvelocity = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u044f
+simpanel.ttip.uptodate = <i>\u0414\u0430\u043d\u043d\u044b\u0435 \u0432\u0430\u043b\u0438\u0434\u043d\u044b</i>
+simpanel.ttip.loaded = <i>\u0414\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043d\u044b \u0438\u0437 \u0444\u0430\u0439\u043b\u0430</i>
+simpanel.ttip.outdated = <i><font color=\"red\">\u0414\u0430\u043d\u043d\u044b\u0435 \u0443\u0441\u0442\u0430\u0440\u0435\u043b\u0438</font></i><br>\u041d\u0430\u0436\u043c\u0438\u0442\u0435 <i><b>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0447\u0435\u0442\u044b</b></i> \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430.
+simpanel.ttip.external = <i>\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435</i>
+simpanel.ttip.notSimulated = <i>\u0420\u0430\u0441\u0447\u0435\u0442 \u0435\u0449\u0435 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u0441\u044f</i><br>\u041d\u0430\u0436\u043c\u0438\u0442\u0435 <i><b>\u0412\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0447\u0435\u0442\u044b</b></i> \u0434\u043b\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430.
+simpanel.ttip.noData = \u041d\u0435\u0442 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.
+simpanel.ttip.noWarnings = <font color=\"gray\">\u041d\u0435\u0442 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0439.</font>
+simpanel.ttip.warnings = <font color=\"red\">\u041f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u044f:</font>
 
 ! SimulationRunDialog
-SimuRunDlg.title.RunSim=\u0412\u044B\u043F\u043E\u043B\u043D\u044F\u0435\u043C\u044B\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044B...
-SimuRunDlg.lbl.Running=\u0412 \u0440\u0430\u0431\u043E\u0442\u0435...
-SimuRunDlg.lbl.Simutime=\u0412\u0440\u0435\u043C\u044F \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
-SimuRunDlg.lbl.Altitude= \u0412\u044B\u0441\u043E\u0442\u0430:
-SimuRunDlg.lbl.Velocity= \u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C:
-SimuRunDlg.msg.Unabletosim=\u0420\u0430\u0441\u0447\u0435\u0442 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u0435\u043D:
-SimuRunDlg.msg.errorOccurred=\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0435:
-SimuRunDlg.msg.AnException1=\u0412\u043E\u0437\u043D\u0438\u043A\u043B\u043E \u0438\u0441\u043A\u043B\u044E\u0447\u0435\u043D\u0438\u0435 \u0432\u043E \u0432\u0440\u0435\u043C\u044F \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
-SimuRunDlg.msg.AnException2=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0441\u043E\u043E\u0431\u0449\u0438\u0442\u0435 \u043E\u0431 \u044D\u0442\u043E\u043C \u043A\u0430\u043A \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0435 \u0432\u043A\u043B\u044E\u0447\u0438\u0432 \u043D\u0438\u0436\u0435\u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435  \u0434\u0435\u0442\u0430\u043B\u0438.
-SimuRunDlg.msg.AssertionError1=\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430 \u0432\u044B\u0447\u0438\u0441\u043B\u0435\u043D\u0438\u044F \u043F\u0440\u0438 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430.
-SimuRunDlg.msg.AssertionError2=\u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430 \u0441\u043E\u043E\u0431\u0449\u0438\u0442\u0435 \u043E\u0431 \u044D\u0442\u043E\u043C \u043A\u0430\u043A \u043E \u0434\u0435\u0444\u0435\u043A\u0442\u0435 \u0432\u043A\u043B\u044E\u0447\u0438\u0432 \u043D\u0438\u0436\u0435\u0441\u043B\u0435\u0434\u0443\u044E\u0449\u0438\u0435  \u0434\u0435\u0442\u0430\u043B\u0438.
-SimuRunDlg.msg.unknownerror1=\u041F\u0440\u043E\u0438\u0437\u043E\u0448\u043B\u0430 \u043D\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043D\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u0430.
-SimuRunDlg.msg.unknownerror2=\u041F\u0440\u043E\u0433\u0440\u0430\u043C\u043C\u0430 \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C\u043D\u0435\u0441\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u0430. \u0412\u044B \u0434\u043E\u043B\u0436\u043D\u044B \u0441\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u0432\u0441\u0435 \u0441\u0432\u043E\u0438 \u043F\u0440\u043E\u0435\u043A\u0442\u044B \u0438 \u043F\u0435\u0440\u0435\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C OpenRocket!
+SimuRunDlg.title.RunSim = \u0420\u0430\u0441\u0447\u0435\u0442\u044b \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435...
+SimuRunDlg.lbl.Running = \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435...
+SimuRunDlg.lbl.Simutime = \u0412\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430:
+SimuRunDlg.lbl.Altitude = \u0412\u044b\u0441\u043e\u0442\u0430:
+SimuRunDlg.lbl.Velocity = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c:
+SimuRunDlg.msg.Unabletosim = \u0420\u0430\u0441\u0447\u0435\u0442 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d:
+SimuRunDlg.msg.errorOccurred = \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430:
+SimuRunDlg.msg.AnException1 = \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u044f:
+SimuRunDlg.msg.AnException2 = \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0442\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c, \u0432\u043a\u043b\u044e\u0447\u0438\u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.
+SimuRunDlg.msg.AssertionError1 = \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u043e\u0448\u0438\u0431\u043a\u0430:
+SimuRunDlg.msg.AssertionError2 = \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0442\u043f\u0440\u0430\u0432\u044c\u0442\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c, \u0432\u043a\u043b\u044e\u0447\u0438\u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435.
+SimuRunDlg.msg.unknownerror1 = \u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u0430 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430.
+SimuRunDlg.msg.unknownerror2 = \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u0430. \u0412\u0430\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0441\u0432\u043e\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u044b \u0438 \u0440\u0430\u0441\u0447\u0435\u0442\u044b \u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443.
 
 
-RK4SimulationStepper.error.valuesTooLarge=\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u044F \u0437\u0430 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u044B\u043C\u0438 \u043F\u0440\u0435\u0434\u0435\u043B\u0430\u043C\u0438 . \u041F\u043E\u043F\u0440\u043E\u0431\u0443\u0439\u0442\u0435 \u0432\u044B\u0431\u0440\u0430\u0442\u044C \u0431\u043E\u043B\u0435\u0435 \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0439 \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u043E\u0439 \u0448\u0430\u0433.
+RK4SimulationStepper.error.valuesTooLarge = \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0440\u0430\u0441\u0447\u0435\u0442\u0430\u0445 \u043f\u0440\u0435\u0432\u044b\u0441\u0438\u043b\u0438 \u0433\u0440\u0430\u043d\u0438\u0446\u044b. \u041f\u043e\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u0440\u043e\u0442\u043a\u0438\u0439 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0448\u0430\u0433.
 
 
 ! SimulationExportPanel
-SimExpPan.desc=\u0424\u0430\u0439\u043B \u0441 \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u0435\u043C \u0437\u0430\u043F\u044F\u0442\u044B\u043C\u0438 (*.csv)
-SimExpPan.border.Vartoexport=\u041F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u0434\u043B\u044F \u044D\u043A\u0441\u043F\u043E\u0440\u0442\u0430
-SimExpPan.but.Selectall= \u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0432\u0441\u0435
-SimExpPan.but.Selectnone=\u041D\u0435 \u0432\u044B\u0431\u0438\u0440\u0430\u0442\u044C \u043D\u0438\u0447\u0435\u0433\u043E
-SimExpPan.border.Fieldsep=\u0420\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044C \u043F\u043E\u043B\u0435\u0439
-SimExpPan.lbl.Fieldsepstr=\u0421\u0442\u0440\u043E\u043A\u0430 \u0440\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u0435\u043B\u044F \u043F\u043E\u043B\u0435\u0439
-SimExpPan.lbl.longA1= <html> \u0421\u0442\u0440\u043E\u043A\u0430 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0441\u044F \u0434\u043B\u044F \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u044F \u043F\u043E\u043B\u0435\u0439 \u0432 \u044D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u043C\u043E\u043C \u0444\u0430\u0439\u043B\u0435. <br>
-SimExpPan.lbl.longA2= \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 ',' \u0434\u043B\u044F \u0444\u0430\u0439\u043B\u0430 \u0441 \u0440\u0430\u0437\u0434\u0435\u043B\u0435\u043D\u0438\u0435\u043C \u0437\u0430\u043F\u044F\u0442\u044B\u043C\u0438 (CSV-\u0444\u0430\u0439\u043B).
-SimExpPan.checkbox.Includesimudesc=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
-SimExpPan.checkbox.ttip.Includesimudesc=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430 \u0432 \u043D\u0430\u0447\u0430\u043B\u043E \u0444\u0430\u0439\u043B\u0430.
-SimExpPan.border.Comments= \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438
-SimExpPan.checkbox.Includefielddesc= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u043F\u043E\u043B\u0435\u0439
-SimExpPan.checkbox.ttip.Includefielddesc=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0442\u0440\u043E\u043A\u0443 \u0441 \u043E\u043F\u0438\u0441\u0430\u043D\u0438\u0435\u043C \u044D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u043C\u044B\u0445 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445.
-SimExpPan.checkbox.Incflightevents=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u043E\u0431\u044B\u0442\u0438\u0435 \u043F\u043E\u043B\u0435\u0442\u0430.
-SimExpPan.checkbox.ttip.Incflightevents=\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0442\u0440\u043E\u0435\u0443 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F \u0434\u043B\u044F \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0441\u043E\u0431\u044B\u0442\u0438\u044F \u043F\u043E\u043B\u0435\u0442\u0430.
-SimExpPan.lbl.Commentchar=\u0421\u0438\u043C\u0432\u043E\u043B \u043A\u043E\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F:
-SimExpPan.lbl.ttip.Commentchar=\u0421\u0438\u043C\u0432\u043E\u043B(\u044B) \u043E\u0431\u043E\u0437\u043D\u0430\u0447\u0430\u044E\u0449\u0438\u0435 \u0441\u0442\u0440\u043E\u043A\u0443 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u044F.
-SimExpPan.but.Exporttofile= \u042D\u043A\u0441\u043F\u043E\u0440\u0442 \u0432 \u0444\u0430\u0439\u043B ...
-SimExpPan.Fileexists.desc1= \u0424\u0430\u0439\u043B \ "
-SimExpPan.Fileexists.desc2= \ " \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u041F\u0435\u0440\u0435\u0437\u0430\u043F\u0438\u0441\u0430\u0442\u044C?
-SimExpPan.Fileexists.title= \u0424\u0430\u0439\u043B \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
-SimExpPan.ExportingVar.desc1= \u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044F 1-\u044F \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F \u0438\u0437
-SimExpPan.ExportingVar.desc2=\u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u0443\u044E\u0442\u0441\u044F
-SimExpPan.ExportingVar.desc3=\u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0435 \u0438\u0437
-SimExpPan.Col.Variable=\u041F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F
-SimExpPan.Col.Unit=\u0415\u0434\u0438\u043D\u0438\u0446\u044B  \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F
-
-
-CsvOptionPanel.separator.space=\u041F\u0420\u041E\u0411\u0415\u041B
-CsvOptionPanel.separator.tab=\u0422\u0410\u0411
-
-
+SimExpPan.desc = \u0422\u0435\u043a\u0441\u0442, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0437\u0430\u043f\u044f\u0442\u044b\u043c\u0438 (*.csv)
+SimExpPan.border.Vartoexport = \u042d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435
+SimExpPan.but.Selectall = \u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0432\u0441\u0435
+SimExpPan.but.Selectnone = \u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u044b\u0431\u043e\u0440
+SimExpPan.border.Fieldsep = \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u043f\u043e\u043b\u0435\u0439
+SimExpPan.lbl.Fieldsepstr = \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u043f\u043e\u043b\u0435\u0439:
+SimExpPan.lbl.longA1 = <html>\u0421\u0442\u0440\u043e\u043a\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0430\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439 \u0432 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c\u043e\u043c \u0444\u0430\u0439\u043b\u0435.<br>
+SimExpPan.lbl.longA2 = \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u044f\u0442\u044b\u043c\u0438 (CSV) \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435\u0441\u044c \u0437\u043d\u0430\u043a\u043e\u043c ','
+SimExpPan.checkbox.Includesimudesc = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+SimExpPan.checkbox.ttip.Includesimudesc = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u0439 \u0432 \u043d\u0430\u0447\u0430\u043b\u043e \u0444\u0430\u0439\u043b\u0430 \u0441 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+SimExpPan.border.Comments = \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f
+SimExpPan.checkbox.Includefielddesc = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439
+SimExpPan.checkbox.ttip.Includefielddesc = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u0441 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0445 \u043f\u043e\u043b\u0435\u0439
+SimExpPan.checkbox.Incflightevents = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u0435\u0442\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f
+SimExpPan.checkbox.ttip.Incflightevents = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u043f\u043e\u043b\u0435\u0442\u0430
+SimExpPan.lbl.Commentchar = \u0421\u0438\u043c\u0432\u043e\u043b \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f:
+SimExpPan.lbl.ttip.Commentchar = \u0421\u0438\u043c\u0432\u043e\u043b(\u044b), \u043e\u0442\u043c\u0435\u0447\u0430\u044e\u0449\u0438\u0435 \u0441\u0442\u0440\u043e\u043a\u0443 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f
+SimExpPan.but.Exporttofile = \u042d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u0444\u0430\u0439\u043b...
+SimExpPan.Fileexists.desc1 = \u0424\u0430\u0439\u043b "
+SimExpPan.Fileexists.desc2 = " \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442. \u041f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u0430\u0442\u044c?
+SimExpPan.Fileexists.title = \u0424\u0430\u0439\u043b \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442
+SimExpPan.ExportingVar.desc1 = \u042d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0438\u0437
+SimExpPan.ExportingVar.desc2 = \u042d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f
+SimExpPan.ExportingVar.desc3 = \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u0438\u0437
+SimExpPan.Col.Variable = \u041f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f
+SimExpPan.Col.Unit = \u0415\u0434\u0438\u043d\u0438\u0446\u0430 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f
+
+
+CsvOptionPanel.separator.space = \u041f\u0440\u043e\u0431\u0435\u043b
+CsvOptionPanel.separator.tab = \u0422\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u044f
+
+
+! Custom expression general stuff
+customExpression.Name = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435
+customExpression.Symbol = \u041e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435
+customExpression.Expression = \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435
+customExpression.Units = \u0415\u0434\u0438\u043d\u0438\u0446\u0430 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f
+customExpression.Operator = \u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440
+customExpression.Description = \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435
+
+! Custom expression panel
+customExpressionPanel.but.NewExpression = \u041d\u043e\u0432\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435
+customExpressionPanel.but.ttip.NewExpression = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435
+customExpressionPanel.but.Import = \u0418\u043c\u043f\u043e\u0440\u0442
+customExpressionPanel.but.ttip.Import = \u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 .ork
+customExpressionPanel.lbl.UpdateNote = \u0412\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0447\u0435\u0442, \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u0432 \u0441\u0442\u0430\u043d\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e.
+customExpressionPanel.lbl.CalcNote = \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u044b \u0432 \u0442\u043e\u043c \u0436\u0435 \u043f\u043e\u0440\u044f\u0434\u043a\u0435, \u0432 \u043a\u0430\u043a\u043e\u043c \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b.
+customExpressionPanel.lbl.CustomExpressions = \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f
+customExpression.Units.but.ttip.Remove = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u044d\u0442\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435
+customExpression.Units.but.ttip.Edit = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u044d\u0442\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435
+customExpression.Units.but.ttip.MoveUp = \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432\u0432\u0435\u0440\u0445 \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f
+customExpression.Units.but.ttip.MoveDown = \u041f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0432\u043d\u0438\u0437 \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435 \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f
+
+
+! Custom expression builder window
+ExpressionBuilderDialog.title = \u041f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u0435\u043b\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439
+ExpressionBuilderDialog.InsertVariable = \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e
+ExpressionBuilderDialog.InsertOperator = \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440
+ExpressionBuilderDialog.led.ttip.Name = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c
+ExpressionBuilderDialog.led.ttip.Symbol = \u041e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c
+ExpressionBuilderDialog.led.ttip.Expression = \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437\u0432\u0435\u0447\u0442\u043d\u044b\u0435 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b
+ExpressionBuilderDialog.CopyToOtherSimulations = \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u0438\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u044b
+ExpressionBuilderDialog.CopyToOtherSimulations.ttip = <html>\u0421\u0434\u0435\u043b\u0430\u0442\u044c \u043a\u043e\u043f\u0438\u044e \u044d\u0442\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0440\u0430\u0441\u0447\u0435\u0442\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430<br>\u0423\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0440\u0430\u0441\u0447\u0435\u0442\u0430\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u0430\u043d\u044b.
+
+! Custom expression variable selector
+CustomVariableSelector.title = \u0412\u044b\u0431\u043e\u0440 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439
+
+! Custom operator selector
+CustomOperatorSelector.title = \u0412\u044b\u0431\u043e\u0440 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430
+
+! Operators
+Operator.plus = \u0421\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+Operator.minus = \u0412\u044b\u0447\u0438\u0442\u0430\u043d\u0438\u0435
+Operator.star = \u0423\u043c\u043d\u043e\u0436\u0435\u043d\u0438\u0435
+Operator.div = \u0414\u0435\u043b\u0435\u043d\u0438\u0435
+Operator.mod = \u041c\u043e\u0434\u0443\u043b\u044c
+Operator.pow = \u0412\u043e\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 \u0441\u0442\u0435\u043f\u0435\u043d\u044c
+Operator.abs = \u0410\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435
+Operator.ceil = \u0411\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0435 \u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0443 \u0431\u043e\u043b\u044c\u0448\u0435\u0435 \u0446\u0435\u043b\u043e\u0435
+Operator.floor = \u0411\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0435 \u043a \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u0443 \u043c\u0435\u043d\u044c\u0448\u0435\u0435 \u0446\u0435\u043b\u043e\u0435
+Operator.sqrt = \u041a\u0432\u0430\u0434\u0440\u0430\u0442\u043d\u044b\u0439 \u043a\u043e\u0440\u0435\u043d\u044c
+Operator.cbrt = \u041a\u0443\u0431\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043a\u043e\u0440\u0435\u043d\u044c
+Operator.exp = \u0427\u0438\u0441\u043b\u043e \u042d\u0439\u043b\u0435\u0440\u0430 \u0432 \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f (e^x)
+Operator.ln = \u041d\u0430\u0442\u0443\u0440\u0430\u043b\u044c\u043d\u044b\u0439 \u043b\u043e\u0433\u0430\u0440\u0438\u0444\u043c
+Operator.sin = \u0421\u0438\u043d\u0443\u0441
+Operator.cos = \u041a\u043e\u0441\u0438\u043d\u0443\u0441
+Operator.tan = \u0422\u0430\u043d\u0433\u0435\u043d\u0441
+Operator.asin = \u0410\u0440\u043a\u0441\u0438\u043d\u0443\u0441
+Operator.acos = \u0410\u0440\u043a\u043a\u043e\u0441\u0438\u043d\u0443\u0441
+Operator.atan = \u0410\u0440\u043a\u0442\u0430\u043d\u0433\u0435\u043d\u0441
+Operator.hsin = \u0413\u0438\u043f\u0435\u0440\u0431\u043e\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0438\u043d\u0443\u0441
+Operator.hcos = \u0413\u0438\u043f\u0435\u0440\u0431\u043e\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043a\u043e\u0441\u0438\u043d\u0443\u0441
+Operator.htan = \u0413\u0438\u043f\u0435\u0440\u0431\u043e\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0442\u0430\u043d\u0433\u0435\u043d\u0441
+Operator.log10 = \u0414\u0435\u0441\u044f\u0442\u0438\u0447\u043d\u044b\u0439 \u043b\u043e\u0433\u0430\u0440\u0438\u0444\u043c
+Operator.round = \u041e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u0435 \u0434\u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0433\u043e \u0446\u0435\u043b\u043e\u0433\u043e
+Operator.random = \u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430 \u0432 \u043f\u0435\u0440\u0435\u0434\u043b\u0430\u0445 \u043e\u0442 0 \u0434\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e
+Operator.expm1 = \u0422\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435, \u0447\u0442\u043e exp(x)-1, \u043d\u043e \u0431\u043b\u0434\u0435\u0435 \u0442\u043e\u0447\u043d\u043e\u0435 \u0434\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 x
+Operator.mean = \u0421\u0440\u0435\u0434\u043d\u0435\u0435 \u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u044f\u0434\u0430
+Operator.min = \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u044f\u0434\u0430
+Operator.max = \u041c\u0430\u043a\u0438\u0441\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u044f\u0434\u0430
+Operator.var = \u0412\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u043e\u0441\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u044f\u0434\u0430
+Operator.stdev = \u0414\u0435\u0432\u0438\u0430\u0442\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u044f\u0434\u0430
+Operator.rms = \u0421\u0440\u0435\u0434\u043d\u0435-\u043a\u0432\u0430\u0434\u0440\u0430\u0442\u0438\u0447\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0440\u044f\u0434\u0430
+Operator.lclip = Clips a value (1st parameter) to be no less than a given value (2nd parameter)
+Operator.uclip = Clips a value (1st parameter) to be no greater than a given value (2nd parameter)
+Operator.binf = Gives the fraction of values in a given range (1st parameter) inside a bin with given lower (2nd parameter) and upper (3rd parameter) bounds
+Operator.trapz = Integrates the given range using trapezoidal integration
+Operator.tnear = Find the time corresponding to the point in a range (1st parameter) nearest to a given value (2nd parameter)
 
 ! MotorPlot
-MotorPlot.title.Motorplot=\u0422\u044F\u0433\u043E\u0432\u0430\u044F \u043A\u0440\u0438\u0432\u0430\u044F \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F
-MotorPlot.but.Select=\u0412\u044B\u0431\u0440\u0430\u0442\u044C
-MotorPlot.Chart.Motorthrustcurve=\u041A\u0440\u0438\u0432\u0430\u044F \u0442\u044F\u0433\u0438 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F
-MotorPlot.Chart.Time=\u0412\u0440\u0435\u043C\u044F / \u0441\u0435\u043A
-MotorPlot.Chart.Thrust=\u0422\u044F\u0433\u0430 / \u041D
-MotorPlot.txt.Designation=\u041E\u0431\u043E\u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435:
-MotorPlot.txt.Manufacturer= \u041F\u0440\u043E\u0438\u0437\u0432\u043E\u0434\u0438\u0442\u0435\u043B\u044C:
-MotorPlot.txt.Type= \u0422\u0438\u043F:
-MotorPlot.txt.Delays=\u0417\u0430\u0434\u0435\u0440\u0436\u043A\u0430:
-MotorPlot.txt.Comment= \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0439:
-
-
+MotorPlot.title.Motorplot = \u0413\u0440\u0430\u0444\u0438\u043a \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+MotorPlot.but.Select = \u0412\u044b\u0431\u0440\u0430\u0442\u044c
+MotorPlot.Chart.Motorthrustcurve = \u041f\u0440\u043e\u0444\u0438\u043b\u044c \u0442\u044f\u0433\u0438 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+MotorPlot.Chart.Time = \u0412\u0440\u0435\u043c\u044f / \u0441\u0435\u043a
+MotorPlot.Chart.Thrust = \u0422\u044f\u0433\u0430 / \u041d
+MotorPlot.txt.Designation = \u041e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435:
+MotorPlot.txt.Manufacturer = \u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c:
+MotorPlot.txt.Type = \u0422\u0438\u043f:
+MotorPlot.txt.Delays = \u0417\u0430\u0434\u0435\u0440\u0436\u043a\u0430:
+MotorPlot.txt.Comment = \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435:\n
 
 ! Simulation plot panel
-simplotpanel.lbl.Presetplotconf=\u041F\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u043D\u044B\u0435 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0433\u0440\u0430\u0444\u0438\u043A\u043E\u0432:
-simplotpanel.lbl.Xaxistype=\u041E\u0441\u044C \u0425:
-simplotpanel.lbl.Unit=\u0415\u0434\u0438\u043D\u0438\u0446\u0430  \u0438\u0437\u043C\u0435\u0440\u0435\u043D\u0438\u044F
-simplotpanel.lbl.Yaxistypes=\u041E\u0441\u044C Y:
-simplotpanel.lbl.Flightevents=\u0421\u043E\u0431\u044B\u0442\u0438\u044F \u043F\u043E\u043B\u0435\u0442\u0430:
-simplotpanel.but.All=\u0412\u0441\u0435
-simplotpanel.but.None=\u041D\u0438\u0447\u0435\u0433\u043E
-simplotpanel.but.NewYaxisplottype=\u041D\u043E\u0432\u0430\u044F \u043E\u0441\u044C Y
-simplotpanel.but.Plotflight=\u041F\u043E\u0441\u0442\u0440\u043E\u0438\u0442\u044C \u0433\u0440\u0430\u0444\u0438\u043A \u043F\u043E\u043B\u0435\u0442\u0430
-simplotpanel.lbl.Axis=\u041A\u043E\u043E\u0440\u0434\u0438\u043D\u0430\u0442\u043D\u044B\u0435 \u043E\u0441\u0438:
-simplotpanel.but.ttip.Removethisplot=\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u044D\u0442\u043E\u0442 \u0433\u0440\u0430\u0444\u0438\u043A
-simplotpanel.Desc=\u0414\u0430\u043D\u043D\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044B\u0432\u043E\u0434\u0438\u0442\u0441\u044F \u0432 \u043F\u043E\u0440\u044F\u0434\u043A\u0435 \u0432\u0440\u0435\u043C\u0435\u043D\u0438 \u0434\u0430\u0436\u0435 \u0435\u0441\u043B\u0438 \u043E\u0441\u044C \u0425 \u043D\u0435 \u0432\u0440\u0435\u043C\u0435\u043D\u043D\u0430\u044F. 
-simplotpanel.OptionPane.lbl1=\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u043E\u0435 \u0447\u0438\u0441\u043B\u043E \u0433\u0440\u0430\u0444\u0438\u043A\u043E\u0432 - 15.
-simplotpanel.OptionPane.lbl2=\u0414\u043E\u0431\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043A\u0430 \u043D\u0435\u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E.
-simplotpanel.AUTO_NAME=\u0410\u0430\u0442\u043E
-simplotpanel.LEFT_NAME=\u041B\u0435\u0432\u044B\u0439
-simplotpanel.RIGHT_NAME=\u041F\u0440\u0430\u0432\u044B\u0439
-simplotpanel.CUSTOM=\u0417\u0430\u043A\u0430\u0437\u043D\u043E\u0439
-SimulationPlotPanel.error.noPlotSelected= \u041F\u043E\u0436\u0430\u043B\u0443\u0439\u0441\u0442\u0430, \u0434\u043E\u0431\u0430\u0432\u044C\u0442\u0435 \u043E\u0434\u043D\u0443 \u0438\u043B\u0438 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u043D\u044B\u0445 \u0434\u043B\u044F \u043F\u043E\u0441\u0442\u0440\u043E\u0435\u043D\u0438\u044F \u043F\u043E \u043E\u0441\u0438 Y.
-SimulationPlotPanel.error.noPlotSelected.title=\u041D\u0435\u0447\u0435\u0433\u043E \u0441\u0442\u0440\u043E\u0438\u0442\u044C
-
+simplotpanel.lbl.Presetplotconf = \u041f\u0440\u0435\u0434\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u0432:
+simplotpanel.lbl.Xaxistype = \u041e\u0441\u044c X:
+simplotpanel.lbl.Unit = \u0415\u0434\u0438\u043d\u0438\u0446\u0430 \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f:
+simplotpanel.lbl.Yaxistypes = \u041e\u0441\u044c Y:
+simplotpanel.lbl.Flightevents = \u041f\u043e\u043b\u0435\u0442\u043d\u044b\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f:
+simplotpanel.but.All = \u0412\u0441\u0435
+simplotpanel.but.None = \u041d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e
+simplotpanel.but.NewYaxisplottype = \u041d\u043e\u0432\u044b\u0439 \u0442\u0438\u043f \u043e\u0441\u0438 Y \u0433\u0440\u0430\u0444\u0438\u043a\u0430
+simplotpanel.but.Plotflight = \u0413\u0440\u0430\u0444\u0438\u043a \u043f\u043e\u043b\u0435\u0442\u0430
+simplotpanel.lbl.Axis = \u041e\u0441\u044c:
+simplotpanel.but.ttip.Removethisplot = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0433\u0440\u0430\u0444\u0438\u043a
+simplotpanel.Desc = \u0414\u0430\u043d\u043d\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u044b \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u0442\u0438\u043f \u043e\u0441\u0438 X \u043d\u0435 \u0432\u0440\u0435\u043c\u044f.
+simplotpanel.OptionPane.lbl1 = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u0433\u0440\u0430\u0444\u0438\u043a\u043e\u0432 - 15
+simplotpanel.OptionPane.lbl2 = \u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a
+simplotpanel.AUTO_NAME = \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438
+simplotpanel.LEFT_NAME = \u0421\u043b\u0435\u0432\u0430
+simplotpanel.RIGHT_NAME = \u0421\u043f\u0440\u0430\u0432\u0430
+simplotpanel.CUSTOM = \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0430\u044f
+SimulationPlotPanel.error.noPlotSelected = \u041f\u0435\u0440\u0435\u0434 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435\u043c \u0434\u043e\u0431\u0430\u0432\u044c\u0442\u0435, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043e\u0434\u043d\u0443 \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043f\u043e \u043e\u0441\u0438 Y.
+SimulationPlotPanel.error.noPlotSelected.title = \u041d\u0435\u0447\u0435\u0433\u043e \u0441\u0442\u0440\u043e\u0438\u0442\u044c
 
 ! Component add buttons
-compaddbuttons.Bodycompandfinsets=\u041A\u043E\u0440\u043F\u0443\u0441\u043D\u044B\u0435 \u0434\u0435\u0442\u0430\u043B\u0438 \u0438 \u0441\u0431\u043E\u0440\u043A\u0438 \u0445\u0432\u043E\u0441\u0442\u043E\u0432\u043E\u0433\u043E \u043E\u043F\u0435\u0440\u0435\u043D\u0438\u044F
-compaddbuttons.Nosecone=\u041D\u043E\u0441\u043E\u0432\u043E\u0439 \u043E\u0431\u0442\u0435\u043A\u0430\u0442\u0435\u043B\u044C 
-compaddbuttons.Bodytube=\u0426\u0435\u043B\u0438\u043D\u0434\u0440 \u043A\u043E\u0440\u043F\u0443\u0441\u0430
-compaddbuttons.Transition= \u041F\u0435\u0440\u0435\u0445\u043E\u0434
-compaddbuttons.Trapezoidal= \u0422\u0440\u0430\u043F\u0435\u0446\u0438\u0435\u0432\u0438\u0434\u043D\u044B\u0439
-compaddbuttons.Elliptical= \u042D\u043B\u043B\u0438\u043F\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0439
-compaddbuttons.Freeform=\u0421\u0432\u043E\u0431\u043E\u0434\u043D\u043E\u0439 \u0444\u043E\u0440\u043C\u044B
-compaddbuttons.Launchlug=\u041D\u0430\u043F\u0440\u0430\u0432\u043B\u044F\u044E\u0449\u0435\u0435 \n\u043A\u043E\u043B\u044C\u0446\u043E
-compaddbuttons.Innercomponent= \u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0438\u0439 \n\u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442
-compaddbuttons.Innertube= \u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044F\u044F \u0442\u0440\u0443\u0431\u0430
-compaddbuttons.Coupler= \u041C\u0443\u0444\u0442\u0430
-compaddbuttons.Centeringring=\u0426\u0435\u043D\u0442\u0440\u0438\u0440\u0443\u044E\u0449\u0435\u0435 \n\u043A\u043E\u043B\u044C\u0446\u043E
-compaddbuttons.Bulkhead=\u041F\u0435\u0440\u0435\u0431\u043E\u0440\u043A\u0430
-compaddbuttons.Engineblock=\u0423\u043F\u043E\u0440 \n\u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F
-compaddbuttons.Massobjects=\u0412\u0435\u0441\u043E\u0432\u044B\u0435 \u044D\u043B\u0435\u043C\u0435\u043D\u0442\u044B
-compaddbuttons.Parachute= \u041F\u0430\u0440\u0430\u0448\u044E\u0442
-compaddbuttons.Streamer=\u0422\u043E\u0440\u043C\u043E\u0437\u043D\u0430\u044F \u043B\u0435\u043D\u0442\u0430
-compaddbuttons.Shockcord=\u0421\u0442\u0440\u043E\u043F\u0430
-compaddbuttons.Masscomponent=\u0412\u0435\u0441\u043E\u0432\u043E\u0439 \n\u044D\u043B\u0435\u043C\u0435\u043D\u0442
-compaddbuttons.Donotaskmeagain= \u0411\u043E\u043B\u044C\u0448\u0435 \u043D\u0435 \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044C
-compaddbuttons.Selectcomppos= \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u043F\u043E\u0437\u0438\u0446\u0438\u044E \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430
-compaddbuttons.lbl.Youcanchange= \u0412\u044B \u043C\u043E\u0436\u0435\u0442\u0435 \u0438\u0437\u043C\u0435\u043D\u0438\u0442\u044C \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445.
-compaddbuttons.lbl.insertcomp= \u0412\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 \u043F\u043E\u0441\u043B\u0435 \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430 \u0438\u043B\u0438 \u0432 \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430?
-compaddbuttons.askPosition.Inserthere= \u0412\u0441\u0442\u0430\u0432\u044C\u0442\u0435 \u0437\u0434\u0435\u0441\u044C
-compaddbuttons.askPosition.Addtotheend= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043A \u043A\u043E\u043D\u0446\u0443
-compaddbuttons.askPosition.Cancel= \u041E\u0442\u043C\u0435\u043D\u0430
+compaddbuttons.Bodycompandfinsets = \u041a\u043e\u0440\u043f\u0443\u0441\u043d\u044b\u0435 \u0434\u0435\u0442\u0430\u043b\u0438 \u0438 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435
+compaddbuttons.Nosecone = \u0413\u043e\u043b\u043e\u0432\u043d\u043e\u0439\n\u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044c
+compaddbuttons.Bodytube = \u041a\u043e\u0440\u043f\u0443\u0441\u043d\u0430\u044f\n\u0442\u0440\u0443\u0431\u0430
+compaddbuttons.Transition = \u041f\u0435\u0440\u0435\u0445\u043e\u0434
+compaddbuttons.Trapezoidal = \u0422\u0440\u0430\u043f\u0435\u0446\u0438\u0435\u0432\u0438\u0434\u043d\u043e\u0435\n\u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435
+compaddbuttons.Elliptical = \u042d\u043b\u043b\u0438\u043f\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435\n\u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435
+compaddbuttons.Freeform = \u0421\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439\n\u0444\u043e\u0440\u043c\u044b
+compaddbuttons.Launchlug = \u041d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0435\n\u043a\u043e\u043b\u044c\u0446\u043e
+compaddbuttons.Innercomponent = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u0434\u0435\u0442\u0430\u043b\u0438
+compaddbuttons.Innertube = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f\n\u0442\u0440\u0443\u0431\u0430
+compaddbuttons.Coupler = \u041c\u0443\u0444\u0442\u0430
+compaddbuttons.Centeringring = \u0426\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u044e\u0449\u0435\u0435\n\u043a\u043e\u043b\u044c\u0446\u043e
+compaddbuttons.Bulkhead = \u041f\u0435\u0440\u0435\u0431\u043e\u0440\u043a\u0430
+compaddbuttons.Engineblock = \u0423\u043f\u043e\u0440\n\u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+compaddbuttons.Massobjects = \u0412\u0435\u0441\u043e\u0432\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b
+compaddbuttons.Parachute = \u041f\u0430\u0440\u0430\u0448\u044e\u0442
+compaddbuttons.Streamer = \u0422\u043e\u0440\u043c\u043e\u0437\u043d\u0430\u044f\n\u043b\u0435\u043d\u0442\u0430
+compaddbuttons.Shockcord = \u0421\u0442\u0440\u043e\u043f\u0430
+compaddbuttons.Masscomponent = \u0412\u0435\u0441\u043e\u0432\u043e\u0439\n\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+compaddbuttons.Donotaskmeagain = \u0411\u043e\u043b\u044c\u0448\u0435 \u043d\u0435 \u0441\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0442\u044c
+compaddbuttons.Selectcomppos = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430
+compaddbuttons.lbl.Youcanchange = \u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445
+compaddbuttons.lbl.insertcomp = \u0420\u0430\u0437\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u043e\u0441\u043b\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043a\u043e\u043d\u0435\u0446?
+compaddbuttons.askPosition.Inserthere = \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0437\u0434\u0435\u0441\u044c
+compaddbuttons.askPosition.Addtotheend = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043a\u043e\u043d\u0435\u0446
+compaddbuttons.askPosition.Cancel = \u041e\u0442\u043c\u0435\u043d\u0430
 
 ! Component Analysis Dialog
-componentanalysisdlg.componentanalysis=\u0410\u043D\u0430\u043B\u0438\u0437 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u043E\u0432
-componentanalysisdlg.lbl.winddir=\u041D\u0430\u043F-\u043D\u0438\u0435 \u0432\u0435\u0442\u0440\u0430:
-componentanalysisdlg.TitledBorder.warnings= \u041F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u044F:
-componentanalysisdlg.ToggleBut.worst=\u0425\u0443\u0434\u0448\u0438\u0439
-componentanalysisdlg.lbl.angleofattack= \u0423\u0433\u043E\u043B \u0430\u0442\u0430\u043A\u0438:
-componentanalysisdlg.lbl.machnumber=\u0427\u0438\u0441\u043B\u043E \u041C\u0430\u0445\u0430:
-componentanalysisdlg.lbl.rollrate=\u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u043A\u0440\u0435\u043D\u0430:
-componentanalysisdlg.lbl.activestages=\u0410\u043A\u0442\u0438\u0432\u043D\u044B\u0435 \u0441\u0442\u0443\u043F\u0435\u043D\u0438:
-componentanalysisdlg.lbl.motorconf=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F:
-componentanalysisdlg.TabStability.Col=\u041A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442
-componentanalysisdlg.TabStability=\u0421\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u043E\u0441\u0442\u044C
-componentanalysisdlg.TabStability.ttip=\u041F\u043E\u043A\u0430\u0437\u0430\u0442\u0438\u043B\u0438 \u0441\u0442\u0430\u0431\u0438\u043B\u044C\u043D\u043E\u0441\u0442\u0438
-componentanalysisdlg.dragTableModel.Col.Component=\u041A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442
-componentanalysisdlg.dragTableModel.Col.Pressure= <html>  C <sub> D </ SUB> \u0434\u0430\u0432\u043B\u0435\u043D\u0438\u044F
-componentanalysisdlg.dragTableModel.Col.Base= <html> C <sub> D </ SUB> \u0434\u043D\u0430
-componentanalysisdlg.dragTableModel.Col.friction= <html> C <sub> D </ SUB> \u0442\u0440\u0435\u043D\u0438\u044F
-componentanalysisdlg.dragTableModel.Col.total=<html>  \u0421\u0443\u043C\u043C\u0430\u0440\u043D\u044B\u0439 C <sub> D </ SUB>
-componentanalysisdlg.dragTabchar=\u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043A\u0438 \u0441\u043E\u043F\u0440\u043E\u0442\u0438\u0432\u043B\u0435\u043D\u0438\u044F
-componentanalysisdlg.dragTabchar.ttip=\u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043A\u0438 \u0441\u043E\u043F\u0440\u043E\u0442\u0438\u0432\u043B\u0435\u043D\u0438\u044F
-componentanalysisdlg.rollTableModel.Col.component=\u041A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442
-componentanalysisdlg.rollTableModel.Col.rollforc=\u041A\u043E\u044D\u0444\u0444\u0438\u0446\u0438\u0435\u043D\u0442 \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E\u0439 \u0441\u0438\u043B\u044B
-componentanalysisdlg.rollTableModel.Col.rolldamp=\u041A\u043E\u044D\u0444\u0444\u0438\u0446\u0438\u0435\u043D\u0442 \u0434\u0435\u043C\u043F\u0444\u0438\u0440\u0443\u044E\u0449\u0435\u0439 \u0441\u0438\u043B\u044B
-componentanalysisdlg.rollTableModel.Col.total= <html>\u0421\u0443\u043C\u043C\u0430\u0440\u043D\u044B\u0439 C<sub>l</sub>
-componentanalysisdlg.rollTableModel=\u0414\u0438\u043D\u0430\u043C\u0438\u043A\u0430 \u043A\u0440\u0435\u043D\u0430
-componentanalysisdlg.rollTableModel.ttip=\u0414\u0438\u043D\u0430\u043C\u0438\u043A\u0430 \u043A\u0440\u0435\u043D\u0430
-componentanalysisdlg.println.closingmethod= Closing method called:
-componentanalysisdlg.println.settingnam= SETTING NAN VALUES
-componentanalysisdlg.lbl.reflenght=\u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u043D\u0430\u044F \u0434\u043B\u0438\u043D\u0430:
-componentanalysisdlg.lbl.refarea=\u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u043D\u0430\u044F \u043F\u043B\u043E\u0449\u0430\u0434\u044C \u043C\u0438\u0434\u0435\u043B\u044F:
-!componentanalysisdlg.But.close = \u0417\u0430\u043A\u0440\u044B\u0442\u044C
-componentanalysisdlg.TabStability.Col.Component=\u041A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u044B:
+componentanalysisdlg.componentanalysis = \u0410\u043d\u0430\u043b\u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432
+componentanalysisdlg.lbl.winddir = \u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u0435\u0442\u0440\u0430:
+componentanalysisdlg.TitledBorder.warnings = \u041f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u044f:
+componentanalysisdlg.ToggleBut.worst = \u0425\u0443\u0434\u0448\u0435\u0435
+componentanalysisdlg.lbl.angleofattack = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438:
+componentanalysisdlg.lbl.machnumber = \u0427\u0438\u0441\u043b\u043e \u041c\u0430\u0445\u0430:
+componentanalysisdlg.lbl.rollrate = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043a\u0440\u0435\u043d\u0430:
+componentanalysisdlg.lbl.activestages = \u0410\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0441\u0442\u0443\u043f\u0435\u043d\u0438:
+componentanalysisdlg.lbl.motorconf = \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439:
+componentanalysisdlg.TabStability.Col = \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+componentanalysisdlg.TabStability = \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c
+componentanalysisdlg.TabStability.ttip = \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438
+componentanalysisdlg.dragTableModel.Col.Component = \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+componentanalysisdlg.dragTableModel.Col.Pressure = <html>\u0414\u0430\u0432\u043b\u0435\u043d\u0438\u044f C<sub>D</sub>
+componentanalysisdlg.dragTableModel.Col.Base = <html>\u0411\u0430\u0437\u043e\u0432\u044b\u0439 C<sub>D</sub>
+componentanalysisdlg.dragTableModel.Col.friction = <html>\u0422\u0440\u0435\u043d\u0438\u044f C<sub>D</sub>
+componentanalysisdlg.dragTableModel.Col.total = <html>\u041e\u0431\u0449\u0438\u0439 C<sub>D</sub>
+componentanalysisdlg.dragTabchar = \u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0438 \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+componentanalysisdlg.dragTabchar.ttip = \u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0438 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+componentanalysisdlg.rollTableModel.Col.component = \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+componentanalysisdlg.rollTableModel.Col.rollforc = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0443\u0441\u0438\u043b\u0435\u043d\u0438\u044f \u043a\u0440\u0435\u043d\u0430
+componentanalysisdlg.rollTableModel.Col.rolldamp = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0434\u0435\u043c\u043f\u0444\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u0440\u0435\u043d\u0430
+componentanalysisdlg.rollTableModel.Col.total = <html>\u041e\u0431\u0449\u0438\u0439 C<sub>l</sub>
+componentanalysisdlg.rollTableModel = \u0414\u0438\u043d\u0430\u043c\u0438\u043a\u0430 \u043a\u0440\u0435\u043d\u0430
+componentanalysisdlg.rollTableModel.ttip = \u0414\u0438\u043d\u0430\u043c\u0438\u043a\u0430 \u043a\u0440\u0435\u043d\u0430
+componentanalysisdlg.println.closingmethod = Closing method called:
+componentanalysisdlg.println.settingnam = SETTING NAN VALUES
+componentanalysisdlg.lbl.reflenght = \u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u043c\u0438\u0434\u0435\u043b\u044f:
+componentanalysisdlg.lbl.refarea = \u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u0430\u044f \u043f\u043b\u043e\u0449\u0430\u0434\u044c \u043c\u0438\u0434\u0435\u043b\u044f:
+!componentanalysisdlg.But.close = \u0417\u0430\u043a\u0440\u044b\u0442\u044c
+componentanalysisdlg.TabStability.Col.Component = \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+componentanalysisdlg.TabStability.Col.CG = \u0426\u0422
+componentanalysisdlg.TabStability.Col.Mass = \u041c\u0430\u0441\u0441\u0430
+componentanalysisdlg.TabStability.Col.CP = \u0426\u0414
+componentanalysisdlg.TOTAL = \u0412\u0441\u0435\u0433\u043e
+componentanalysisdlg.noWarnings = <html><i><font color=\"gray\">\u041f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0439 \u043d\u0435\u0442.</font></i>
+
 
 ! Custom Material dialog
-custmatdlg.title.Custommaterial=\u0417\u0430\u043A\u0430\u0437\u043D\u043E\u0439 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B
-custmatdlg.lbl.Materialname=\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u0430:
-custmatdlg.lbl.Materialtype=\u0422\u0438\u043F \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u0430:
-custmatdlg.lbl.Materialdensity=\u0423\u0434\u0435\u043B\u044C\u043D\u0430\u044F \u043F\u043B\u043E\u0442\u043D\u043E\u0441\u0442\u044C:
-custmatdlg.checkbox.Addmaterial= \u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043C\u0430\u0442\u0435\u0440\u0438\u0430\u043B \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043D\u043D\u044B\u0445
+custmatdlg.title.Custommaterial = \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b
+custmatdlg.lbl.Materialname = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430:
+custmatdlg.lbl.Materialtype = \u0422\u0438\u043f \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430:
+custmatdlg.lbl.Materialdensity = \u041f\u043b\u043e\u0442\u043d\u043e\u0441\u0442\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u0430:
+custmatdlg.checkbox.Addmaterial = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0432 \u0431\u0430\u0437\u0443
 
 
 ! Ring Component Config
-ringcompcfg.OuterRadius=\u0412\u043D\u0435\u0448\u043D\u0438\u0439 \u0440\u0430\u0434\u0438\u0443\u0441
-ringcompcfg.Automatic=\u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0439
-ringcompcfg.InnerRadius=\u0412\u043D\u0435\u0443\u0442\u0440\u0435\u043D\u043D\u0438\u0439 \u0440\u0430\u0434\u0438\u0443\u0441
-ringcompcfg.Thickness=\u0422\u043E\u043B\u0449\u0438\u043D\u0430
-ringcompcfg.Length=\u0414\u043B\u0438\u043D\u0430
-ringcompcfg.Positionrelativeto=\u041F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044E \u043A:
-ringcompcfg.plus=\u041F\u043B\u044E\u0441
-ringcompcfg.PositionValue=\u041F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0432\u0435\u043B\u0438\u0447\u0438\u043D\u0430
-ringcompcfg.Radialdistance=\u0420\u0430\u0434\u0438\u0430\u043B\u044C\u043D\u043E\u0435 \u0440\u0430\u0441\u0441\u0442\u043E\u044F\u043D\u0438\u0435:
-ringcompcfg.Distancefrom= \u0420\u0430\u0441\u0441\u0442\u043E\u044F\u043D\u0438\u0435 \u043E\u0442 \u043E\u0441\u0435\u0432\u043E\u0439 \u043B\u0438\u043D\u0438\u0438  \u0440\u0430\u043A\u0435\u0442\u044B
-ringcompcfg.Radialdirection=\u0420\u0430\u0434\u0438\u0430\u043B\u044C\u043D\u043E\u0435 \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435:
-ringcompcfg.radialdirectionfrom=\u0420\u0430\u0434\u0438\u0430\u043B\u044C\u043D\u043E\u0435 \u043D\u0430\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043E\u0442 \u043E\u0441\u0435\u0432\u043E\u0439 \u043B\u0438\u043D\u0438\u0438 \u0440\u0430\u043A\u0435\u0442\u044B
-ringcompcfg.but.Reset= \u0421\u0431\u0440\u043E\u0441
-ringcompcfg.but.Resetcomponant=\u0412\u0435\u0440\u043D\u0443\u0442\u044C \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 \u043D\u0430 \u043E\u0441\u0435\u0432\u0443\u044E \u043B\u0438\u043D\u0438\u044E
-ringcompcfg.EngineBlock.desc= <html> \u041A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442 <b> \u0423\u043F\u043E\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F </b> \u043F\u0440\u0435\u043F\u044F\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0438\u0436\u0435\u043D\u0438\u044E \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F \u0432\u043F\u0435\u0440\u0435\u0434 \u0432 \u0442\u0440\u0443\u0431\u0435 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438. <br> <br> \u0414\u043B\u044F \u0442\u043E\u0433\u043E, \u0447\u0442\u043E\u0431\u044B \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C, \u0441\u043E\u0437\u0434\u0430\u0439\u0442\u0435 <b> \u0426\u0435\u043B\u0438\u043D\u0434\u0440 \u043A\u043E\u0440\u043F\u0443\u0441\u0430 </b> \u0438\u043B\u0438 <b> \u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044E\u044E \u0442\u0440\u0443\u0431\u0443 </b> \u0438 \u043E\u0442\u043C\u0435\u0442\u044C\u0442\u0435 \u044D\u0442\u043E\u0442 \u044D\u043B\u0435\u043C\u0435\u043D\u0442 \u043A\u0430\u043A  \u0442\u0440\u0443\u0431\u0443 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u043D\u0430 \u0432\u043A\u043B\u0430\u0434\u043A\u0435 <em> \u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C </em> .
-ringcompcfg.note.desc= \u041F\u0440\u0438\u043C\u0435\u0447\u0430\u043D\u0438\u0435: \u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u044F\u044F \u0442\u0440\u0443\u0431\u0430 \u043D\u0435 \u0432\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u0430\u044D\u0440\u043E\u0434\u0438\u043D\u0430\u043C\u0438\u043A\u0443 \u0440\u0430\u043A\u0435\u0442\u044B, \u0434\u0430\u0436\u0435 \u0435\u0441\u043B\u0438 \u043E\u043D\u0430 \u043D\u0430\u0445\u043E\u0434\u0438\u0442\u0441\u044F \u0437\u0430 \u043F\u0440\u0435\u0434\u0435\u043B\u0430\u043C\u0438 \u0446\u0435\u043B\u0438\u043D\u0434\u0440\u0430 \u043A\u043E\u0440\u043F\u0443\u0441\u0430.
+ringcompcfg.OuterRadius = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0440\u0430\u0434\u0438\u0443\u0441
+ringcompcfg.Automatic = \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438
+ringcompcfg.InnerRadius = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0440\u0430\u0434\u0438\u0443\u0441
+ringcompcfg.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430
+ringcompcfg.Length = \u0414\u043b\u0438\u043d\u0430
+ringcompcfg.Positionrelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+ringcompcfg.plus = \u043f\u043b\u044e\u0441
+ringcompcfg.PositionValue = PositionValue
+ringcompcfg.Radialdistance = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435:
+ringcompcfg.Distancefrom = \u0420\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043e\u0442 \u043e\u0441\u0438 \u0440\u0430\u043a\u0435\u0442\u044b
+ringcompcfg.Radialdirection = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435
+ringcompcfg.radialdirectionfrom = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043e\u0442 \u043e\u0441\u0438 \u0440\u0430\u043a\u0435\u0442\u044b
+ringcompcfg.but.Reset = \u0421\u0431\u0440\u043e\u0441
+ringcompcfg.but.Resetcomponant = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043d\u0430 \u043e\u0441\u0438 \u0440\u0430\u043a\u0435\u0442\u044b
+ringcompcfg.EngineBlock.desc = <html><b>\u0423\u043f\u043e\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f</b> \u043f\u0440\u0435\u043f\u044f\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0434\u0432\u0438\u0436\u0435\u043d\u0438\u044e \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f \u0432\u043f\u0435\u0440\u0435\u0434 \u0432 \u0442\u0440\u0443\u0431\u0435.<br><br>\u0414\u043b\u044f \u0442\u043e\u0433\u043e \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c, \u0441\u043e\u0437\u0434\u0430\u0439\u0442\u0435 <b>\u041a\u043e\u0440\u043f\u0443\u0441\u043d\u0443\u044e \u0442\u0440\u0443\u0431\u0443</b> \u0438\u043b\u0438 <b>\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044e\u044e \u0442\u0440\u0443\u0431\u0443</b> \u0438 \u043e\u0442\u043c\u0435\u0442\u044c\u0442\u0435 \u044d\u0442\u043e\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043a\u0430\u043a \u043a\u0440\u0435\u043f\u0435\u0436 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 <em>\u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c</em> .
+ringcompcfg.note.desc = \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435: \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u0442\u0440\u0443\u0431\u0430 \u043d\u0435 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u043a\u0443, \u0434\u0430\u0436\u0435 \u0431\u0443\u0434\u0443\u0447\u0438 \u0440\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u043d\u043e\u0439 \u0437\u0430 \u043f\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u043a\u043e\u0440\u043f\u0443\u0441\u0430.
 
 
 ! Body Tube Config
-BodyTubecfg.lbl.Bodytubelength=\u0414\u043B\u0438\u043D\u0430 \u0446\u0435\u043B\u0438\u043D\u0434\u0440\u0430 \u043A\u043E\u0440\u043F\u0443\u0441\u0430:
-BodyTubecfg.lbl.Outerdiameter= \u041D\u0430\u0440\u0443\u0436\u043D\u044B\u0439 \u0434\u0438\u0430\u043C\u0435\u0442\u0440:
-BodyTubecfg.lbl.Innerdiameter= \u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0438\u0439 \u0434\u0438\u0430\u043C\u0435\u0442\u0440:
-BodyTubecfg.lbl.Wallthickness= \u0422\u043E\u043B\u0449\u0438\u043D\u0430 \u0441\u0442\u0435\u043D\u043A\u0438:
-BodyTubecfg.tab.General=\u041E\u0431\u0449\u0438\u0435
-BodyTubecfg.tab.Generalproperties=\u041E\u0431\u0449\u0438\u0435 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430
-BodyTubecfg.tab.Motor=\u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044C
-BodyTubecfg.tab.Motormountconf=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u044F \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F
-BodyTubecfg.checkbox.Automatic= \u0410\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0439
-BodyTubecfg.checkbox.Filled= \u0417\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043D\u044B\u0435
+BodyTubecfg.lbl.Bodytubelength = \u0414\u043b\u0438\u043d\u0430 \u0442\u0440\u0443\u0431\u044b:
+BodyTubecfg.lbl.Outerdiameter = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+BodyTubecfg.lbl.Innerdiameter = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+BodyTubecfg.lbl.Wallthickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430 \u0441\u0442\u0435\u043d\u043a\u0438:
+BodyTubecfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+BodyTubecfg.tab.Generalproperties = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+BodyTubecfg.tab.Motor = \u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c
+BodyTubecfg.tab.Motormountconf = \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+BodyTubecfg.checkbox.Automatic = \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438
+BodyTubecfg.checkbox.Filled = \u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u0430\u044f
 
 ! FinSetConfig
-FinSetConfig.tab.Fintabs=\u041F\u043B\u0430\u0441\u0442\u0438\u043D\u0430 \u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u044F \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0432\u0442\u043E\u0440\u0430
-FinSetConfig.tab.Through-the-wall=\u041F\u043B\u0430\u0441\u0442\u0438\u043D\u044B \u0441\u043A\u0432\u043E\u0437\u043D\u043E\u0433\u043E \u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u044F \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0432\u0442\u043E\u0440\u043E\u0432
-FinSetConfig.but.Converttofreeform=\u041F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u043E\u0432\u0430\u0442\u044C \u0432 \u0441\u0432\u043E\u0431\u043E\u0434\u043D\u0443\u044E \u0444\u043E\u0440\u043C\u0443
-FinSetConfig.but.Converttofreeform.ttip=\u041F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u043E\u0432\u0430\u0442\u044C \u0433\u0440\u0443\u043F\u043F\u0443 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0432\u0442\u043E\u0440\u043E\u0432 \u0432 \u0433\u0440\u0443\u043F\u043F\u0443 \u0441\u0432\u043E\u0431\u043E\u0434\u043D\u043E\u0439 \u0444\u043E\u0440\u043C\u044B 
-FinSetConfig.Convertfinset=\u041F\u0440\u0435\u043E\u0431\u0440\u0430\u0437\u043E\u0432\u0430\u0442\u044C \u0433\u0440\u0443\u043F\u043F\u0443
-FinSetConfig.but.Splitfins=\u0420\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u044C \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u044B
-FinSetConfig.but.Splitfins.ttip=\u0420\u0430\u0437\u0434\u0435\u043B\u0438\u0442\u044C \u043D\u0430\u0431\u043E\u0440 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u043E\u0432 \u043D\u0430 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0435 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u044B
-FinSetConfig.but.AutoCalc= \u0420\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044C \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438
-FinSetConfig.lbl.Through-the-wall=\u041F\u043B\u0430\u0441\u0442\u0438\u043D\u044B \u0441\u043A\u0432\u043E\u0437\u043D\u043E\u0433\u043E \u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u044F \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0432\u0442\u043E\u0440\u043E\u0432:
-FinSetConfig.lbl.Tablength=\u0414\u043B\u0438\u043D\u0430 \u043F\u043B\u0430\u0441\u0442\u0438\u043D\u044B:
-FinSetConfig.ttip.Tablength=\u0414\u043B\u0438\u043D\u0430 \u043F\u043B\u0430\u0441\u0442\u0438\u043D\u044B \u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u044F \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430:
-FinSetConfig.lbl.Tabheight=\u0412\u044B\u0441\u043E\u0442\u0430 \u043F\u043B\u0430\u0441\u0442\u0438\u043D\u044B:
-FinSetConfig.ttip.Tabheight=\u0432\u044B\u0441\u043E\u0442\u0430 \u043F\u043B\u0430\u0441\u0442\u0438\u043D\u044B \u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u044F \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430.
-FinSetConfig.lbl.Tabposition=\u041F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043B\u0430\u0441\u0442\u0438\u043D\u044B:
-FinSetConfig.ttip.Tabposition=\u041F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043B\u0430\u0441\u0442\u0438\u043D\u044B \u043A\u0440\u0435\u043F\u043B\u0435\u043D\u0438\u044F \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430:
-FinSetConfig.lbl.relativeto=\u043F\u043E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044E \u043A:
+FinSetConfig.tab.Fintabs = \u041a\u0440\u0435\u043f\u0435\u0436\u043d\u044b\u0435 \u0432\u044b\u0441\u0442\u0443\u043f\u044b
+FinSetConfig.tab.Through-the-wall = \u041a\u0440\u0435\u043f\u0435\u0436\u043d\u044b\u0435 \u0432\u044b\u0441\u0442\u0443\u043f\u044b \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432
+FinSetConfig.but.Converttofreeform = \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u0443\u044e \u0444\u043e\u0440\u043c\u0443
+FinSetConfig.but.Converttofreeform.ttip = \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435 \u0432 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b
+FinSetConfig.Convertfinset = \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435
+FinSetConfig.but.Splitfins = \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c
+FinSetConfig.but.Splitfins.ttip = \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u044b
+FinSetConfig.but.AutoCalc = \u0420\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438
+FinSetConfig.lbl.Through-the-wall = \u041a\u0440\u0435\u043f\u0435\u0436\u043d\u044b\u0435 \u0432\u044b\u0441\u0442\u0443\u043f\u044b \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432:
+FinSetConfig.lbl.Tablength = \u0414\u043b\u0438\u043d\u0430 \u0432\u044b\u0441\u0442\u0443\u043f\u0430:
+FinSetConfig.ttip.Tablength = \u0414\u043b\u0438\u043d\u0430 \u043a\u0440\u0435\u043f\u0435\u0436\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430.
+FinSetConfig.lbl.Tabheight = \u0412\u044b\u0441\u043e\u0442\u0430 \u0432\u044b\u0441\u0442\u0443\u043f\u0430:
+FinSetConfig.ttip.Tabheight = \u0412\u044b\u0441\u043e\u0442\u0430 (\u0433\u043b\u0443\u0431\u0438\u043d\u0430) \u043a\u0440\u0435\u043f\u0435\u0436\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430.
+FinSetConfig.lbl.Tabposition = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432\u044b\u0441\u0442\u0443\u043f\u0430:
+FinSetConfig.ttip.Tabposition = \u0420\u0430\u0437\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043a\u0440\u0435\u043f\u0435\u0436\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430.
+FinSetConfig.lbl.relativeto = \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e
 
 !FinMarkingGuide
-FinMarkingGuide.lbl.Front=\u043F\u0435\u0440\u0435\u0434\u043D\u044F\u044F \u043A\u0440\u043E\u043C\u043A\u0430
+FinMarkingGuide.lbl.Front = \u041f\u0435\u0440\u0435\u0434\u043d\u044f\u044f \u043a\u0440\u043e\u043c\u043a\u0430
 
 ! MotorDatabaseLoadingDialog
-MotorDbLoadDlg.title= \u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0435\u0439
-MotorDbLoadDlg.Loadingmotors= \u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0435\u0439 ...
+MotorDbLoadDlg.title = \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445
+MotorDbLoadDlg.Loadingmotors = \u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439...
 
 ! RocketConfig
-RocketCfg.lbl.Designname=\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043F\u0440\u043E\u0435\u043A\u0442\u0430:
-RocketCfg.lbl.Designer=\u041A\u043E\u043D\u0441\u0442\u0440\u0443\u043A\u0442\u043E\u0440:
-RocketCfg.lbl.Comments= \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438:
-RocketCfg.lbl.Revisionhistory= \u0418\u0441\u0442\u043E\u0440\u0438\u044F \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439:
-RocketCfg.lbl.Material= \u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B\u044B:
+RocketCfg.lbl.Designname = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435:
+RocketCfg.lbl.Designer = \u0410\u0432\u0442\u043e\u0440:
+RocketCfg.lbl.Comments = \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f:
+RocketCfg.lbl.Revisionhistory = \u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439:
+RocketCfg.lbl.Material = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b:
 
 ! ShockCordConfig
-ShockCordCfg.lbl.Shockcordlength=\u0414\u043B\u0435\u043D\u0430 \u0441\u0442\u0440\u043E\u043F\u044B:
+ShockCordCfg.lbl.Shockcordlength = \u0414\u043b\u0438\u043d\u0430 \u0441\u0442\u0440\u043e\u043f\u044b
 
 ! RocketComponentConfig
-RocketCompCfg.lbl.Componentname=\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
-RocketCompCfg.ttip.Thecomponentname=\u0418\u043C\u044F \u0434\u0430\u043D\u043D\u043E\u0433\u043E \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
-RocketCompCfg.tab.Override=\u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0438\u0442\u044C
-RocketCompCfg.tab.MassandCGoverride=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438 \u043F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u044F \u043C\u0430\u0441\u0441\u044B \u0438 \u0426\u0422
-RocketCompCfg.tab.Figure=\u0420\u0438\u0441\u0443\u043D\u043E\u043A
-RocketCompCfg.tab.Figstyleopt=\u0412\u0430\u0440\u0438\u0430\u043D\u0442\u044B \u0441\u0442\u0438\u043B\u044C \u0440\u0438\u0441\u0443\u043D\u043A\u0430
-RocketCompCfg.tab.Comment= \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438
-RocketCompCfg.tab.Specifyacomment= \u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438 \u0434\u043B\u044F \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430
-RocketCompCfg.lbl.Mass= \u041C\u0430\u0441\u0441\u0430:
-RocketCompCfg.lbl.Componentmass=\u041C\u0430\u0441\u0441\u0430 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
-RocketCompCfg.lbl.overriddento= (\u043F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u043E
-RocketCompCfg.lbl.overriddenby= (\u043E\u0442\u043C\u0435\u043D\u0435\u043D\u043E
-RocketCompCfg.lbl.Componentmaterial=\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
-RocketCompCfg.lbl.Componentfinish=\u0427\u0438\u0441\u0442\u043E\u0442\u0430 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u0438 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
-RocketCompCfg.lbl.ttip.componentmaterialaffects=\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430 \u0432\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u0435\u0433\u043E \u0432\u0435\u0441.
-RocketCompCfg.combo.ttip.componentmaterialaffects=\u041C\u0430\u0442\u0435\u0440\u0438\u0430\u043B \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430 \u0432\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u0435\u0433\u043E \u0432\u0435\u0441.
-RocketCompCfg.lbl.longA1= <html> \u0427\u0438\u0441\u0442\u043E\u0442\u0430 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u0438 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430 \u0432\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u0435\u0433\u043E \u0430\u044D\u0440\u043E\u0434\u0438\u043D\u0430\u043C\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0441\u0432\u043E\u0439\u0441\u0442\u0432\u0430. <br>
-RocketCompCfg.lbl.longA2=\u0421\u0440\u0435\u0434\u043D\u044F\u044F \u0432\u044B\u0441\u043E\u0442\u0430 \u043C\u0438\u043A\u0440\u043E\u0440\u0435\u043B\u044C\u0435\u0444\u0430 \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u0438.
-RocketCompCfg.but.Setforall=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0434\u043B\u044F \u0432\u0441\u0435\u0445
-RocketCompCfg.but.ttip.Setforall=\u0423\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0447\u0438\u0441\u0442\u043E\u0442\u0443 \u043E\u0431\u0440\u0430\u0431\u043E\u0442\u043A\u0438 \u043F\u043E\u0432\u0435\u0440\u0445\u043D\u043E\u0441\u0442\u0438 \u0434\u043B\u044F \u0432\u0441\u0435\u0445 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u043E\u0432 \u0440\u0430\u043A\u0435\u0442\u044B.
-RocketCompCfg.lbl.Overridemassorcenter= \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0441\u0441\u044B \u0438\u043B\u0438 \u0446\u0435\u043D\u0442\u0440\u0430 \u0442\u044F\u0436\u0435\u0441\u0442\u0438
-RocketCompCfg.checkbox.Overridemass= \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0441\u0441\u044B:
-RocketCompCfg.checkbox.Overridecenterofgrav= \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u0446\u0435\u043D\u0442\u0440\u0430 \u0442\u044F\u0436\u0435\u0441\u0442\u0438:
-RocketCompCfg.checkbox.OverridemassandCG= \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0441\u0441\u044B \u0438 \u0426\u0422 \u0432\u0441\u0435\u0445 \u043F\u043E\u0434-\u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u043E\u0432
-RocketCompCfg.lbl.longB1= <html> \u041F\u0435\u0440\u0435\u043E\u043F\u0440\u0435\u0434\u0435\u043B\u0435\u043D\u0438\u0435 \u043C\u0430\u0441\u0441\u044B \u043D\u0435 \u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u0438. <br>
-RocketCompCfg.lbl.longB2=\u0426\u0435\u043D\u0442\u0440 \u0442\u044F\u0436\u0435\u0441\u0442\u0438 \u0438\u0437\u043C\u0435\u0440\u044F\u0435\u0442\u0441\u044F \u043E\u0442 \u043F\u0435\u0440\u0435\u0434\u043D\u0435\u0439 \u043A\u0440\u043E\u043C\u043A\u0438
-RocketCompCfg.lbl.Commentsonthe= \u041A\u043E\u043C\u043C\u0435\u043D\u0442\u0430\u0440\u0438\u0438
-RocketCompCfg.lbl.Figurestyle=\u0421\u0442\u0438\u043B\u044C \u0440\u0438\u0441\u0443\u043D\u043A\u0430:
-RocketCompCfg.lbl.Componentcolor=\u0426\u0432\u0435\u0442 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0430:
-RocketCompCfg.lbl.Choosecolor= \u0412\u044B\u0431\u0435\u0440\u0438\u0442\u0435 \u0446\u0432\u0435\u0442
-RocketCompCfg.checkbox.Usedefaultcolor= \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0442\u044C \u0446\u0432\u0435\u0442\u0430 \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
-RocketCompCfg.lbl.Complinestyle=\u0421\u0442\u0438\u043B\u044C \u043B\u0438\u043D\u0438\u0438:
-RocketCompCfg.but.Saveasdefstyle= \u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C \u043A\u0430\u043A \u0441\u0442\u0438\u043B\u044C \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E
-RocketCompCfg.lbl.Diameter= \u0414\u0438\u0430\u043C\u0435\u0442\u0440:
-RocketCompCfg.lbl.Length= \u0414\u043B\u0438\u043D\u0430:
-RocketCompCfg.lbl.Thickness= \u0422\u043E\u043B\u0449\u0438\u043D\u0430:
-RocketCompCfg.checkbox.Endcapped=\u0421 \u0437\u0430\u0433\u043B\u0443\u0448\u043A\u043E\u0439 \u043D\u0430 \u0442\u043E\u0440\u0446\u0435
-RocketCompCfg.ttip.Endcapped=\u0422\u043E\u0440\u0435\u0446 \u0437\u0430\u043A\u0440\u044B\u0442 \u0437\u0430\u0433\u043B\u0443\u0448\u043A\u043E\u0439
-RocketCompCfg.title.Noseconeshoulder=\u041E\u0441\u043D\u043E\u0432\u0430\u043D\u0438\u0435 \u043D\u043E\u0441\u043E\u0432\u043E\u0433\u043E \u043E\u0431\u0442\u0435\u043A\u0430\u0442\u0435\u043B\u044F
-RocketCompCfg.title.Aftshoulder=\u041A\u043E\u0440\u043C\u043E\u0432\u043E\u0435 \u043E\u0441\u043D\u043E\u0432\u0430\u043D\u0438\u0435
-RocketCompCfg.border.Foreshoulder=\u041D\u043E\u0441\u043E\u0432\u043E\u0435 \u043E\u0441\u043D\u043E\u0432\u0430\u043D\u0438\u0435
-!RocketCompCfg.lbl.Length = \u0414\u043B\u0438\u043D\u0430:
+RocketCompCfg.lbl.Componentname = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430:
+RocketCompCfg.ttip.Thecomponentname = \u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430.
+RocketCompCfg.tab.Override = \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435
+RocketCompCfg.tab.MassandCGoverride = \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043c\u0430\u0441\u0441\u044b \u0438 \u0426\u0422
+RocketCompCfg.tab.Figure = \u0420\u0438\u0441\u0443\u043d\u043e\u043a
+RocketCompCfg.tab.Figstyleopt = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0442\u0438\u043b\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u0430
+RocketCompCfg.tab.Comment = \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435
+RocketCompCfg.tab.Specifyacomment = \u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u0435 \u043a \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0443
+RocketCompCfg.lbl.Mass = \u041c\u0430\u0441\u0441\u0430:
+RocketCompCfg.lbl.Componentmass = \u041c\u0430\u0441\u0441\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430:
+RocketCompCfg.lbl.overriddento = (\u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e \u043d\u0430
+RocketCompCfg.lbl.overriddenby = (\u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e \u043d\u0430
+RocketCompCfg.lbl.Componentmaterial = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430:
+RocketCompCfg.lbl.Componentfinish = \u041e\u0442\u0434\u0435\u043b\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430
+RocketCompCfg.lbl.ttip.componentmaterialaffects = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0435\u0433\u043e \u043c\u0430\u0441\u0441\u0443.
+RocketCompCfg.combo.ttip.componentmaterialaffects = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0435\u0433\u043e \u043c\u0430\u0441\u0441\u0443.
+RocketCompCfg.lbl.longA1 = <html>\u041e\u0442\u0434\u0435\u043b\u043a\u0430 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430<br>
+RocketCompCfg.lbl.longA2 = \u0423\u043a\u0430\u0437\u0430\u043d\u043e \u0441\u0440\u0435\u0434\u043d\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0448\u0435\u0440\u043e\u0445\u043e\u0432\u0430\u0442\u043e\u0441\u0442\u0438.
+RocketCompCfg.but.Setforall = \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u043b\u044f \u0432\u0441\u0435\u0445
+RocketCompCfg.but.ttip.Setforall = \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u044d\u0442\u0443 \u0448\u0435\u0440\u043e\u0445\u043e\u0432\u0430\u0442\u043e\u0441\u0442\u044c \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0440\u0430\u043a\u0435\u0442\u044b.
+RocketCompCfg.lbl.Overridemassorcenter = \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0430\u0441\u0441\u0443 \u0438\u043b\u0438 \u0446\u0435\u043d\u0442\u0440 \u0442\u044f\u0436\u0435\u0441\u0442\u0438 -
+RocketCompCfg.checkbox.Overridemass = \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0430\u0441\u0441\u0443:
+RocketCompCfg.checkbox.Overridecenterofgrav = \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0446\u0435\u043d\u0442\u0440 \u0442\u044f\u0436\u0435\u0441\u0442\u0438:
+RocketCompCfg.checkbox.OverridemassandCG = \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0430\u0441\u0441\u0443 \u0438 \u0426\u0422 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u0434\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432:
+RocketCompCfg.lbl.longB1 = <html>\u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0430\u044f \u043c\u0430\u0441\u0441\u0430 \u043d\u0435 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0438.<br>
+RocketCompCfg.lbl.longB2 = \u0426\u0435\u043d\u0442\u0440 \u0442\u044f\u0436\u0435\u0441\u0442\u0438 \u0438\u0437\u043c\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u043e\u0442 \u043d\u0430\u0447\u0430\u043b\u0430
+RocketCompCfg.lbl.Commentsonthe = \u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f -
+RocketCompCfg.lbl.Figurestyle = \u0421\u0442\u0438\u043b\u044c \u0440\u0438\u0441\u0443\u043d\u043a\u0430:
+RocketCompCfg.lbl.Componentcolor = \u0426\u0432\u0435\u0442 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430:
+RocketCompCfg.lbl.Choosecolor = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0446\u0432\u0435\u0442
+RocketCompCfg.checkbox.Usedefaultcolor = \u0426\u0432\u0435\u0442 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e
+RocketCompCfg.lbl.Complinestyle = \u0421\u0442\u0438\u043b\u044c \u043b\u0438\u043d\u0438\u0438 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430:
+RocketCompCfg.but.Saveasdefstyle = \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a \u0441\u0442\u0438\u043b\u044c \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e
+RocketCompCfg.lbl.Diameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440:
+RocketCompCfg.lbl.Length = \u0414\u043b\u0438\u043d\u0430:
+RocketCompCfg.lbl.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430:
+RocketCompCfg.checkbox.Endcapped = \u0422\u043e\u0440\u0435\u0446 \u0437\u0430\u0433\u043b\u0443\u0448\u0435\u043d
+RocketCompCfg.ttip.Endcapped = \u0417\u0430\u0433\u043b\u0443\u0448\u0435\u043d \u043b\u0438 \u0442\u043e\u0440\u0435\u0446.
+RocketCompCfg.title.Noseconeshoulder = \u0412\u044b\u0441\u0442\u0443\u043f \u0433\u043e\u043b\u043e\u0432\u043d\u043e\u0433\u043e \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044f
+RocketCompCfg.title.Aftshoulder = \u0417\u0430\u0434\u043d\u0438\u0439 \u0432\u044b\u0441\u0442\u0443\u043f
+RocketCompCfg.border.Foreshoulder = \u041f\u0435\u0440\u0435\u0434\u043d\u0438\u0439 \u0432\u044b\u0441\u0442\u0443\u043f
+!RocketCompCfg.lbl.Length = \u0414\u043b\u0438\u043d\u0430:
 
 ! BulkheadConfig
-BulkheadCfg.tab.Diameter= \u0414\u0438\u0430\u043C\u0435\u0442\u0440:
-BulkheadCfg.tab.Thickness= \u0422\u043E\u043B\u0449\u0438\u043D\u0430:
-BulkheadCfg.tab.General=\u041E\u0441\u043D\u043E\u0432\u043D\u044B\u0435
-BulkheadCfg.tab.Generalproperties=\u041E\u0441\u043D\u043E\u0432\u043D\u044B\u0435 \u0445\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043A\u0438
+BulkheadCfg.tab.Diameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440:
+BulkheadCfg.tab.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430:
+BulkheadCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+BulkheadCfg.tab.Generalproperties = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
 
 !CenteringRingConfig
-CenteringRingCfg.tab.Outerdiam= \u041D\u0430\u0440\u0443\u0436\u043D\u044B\u0439 \u0434\u0438\u0430\u043C\u0435\u0442\u0440:
-CenteringRingCfg.tab.Innerdiam= \u0412\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0438\u0439 \u0434\u0438\u0430\u043C\u0435\u0442\u0440:
-CenteringRingCfg.tab.Thickness= \u0422\u043E\u043B\u0449\u0438\u043D\u0430:
-CenteringRingCfg.tab.General=\u041E\u0441\u043D\u043E\u0432\u043D\u044B\u0435
-CenteringRingCfg.tab.Generalproperties=\u041E\u0441\u043D\u043E\u0432\u043D\u044B\u0435 \u0445\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043A\u0438
+CenteringRingCfg.tab.Outerdiam = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+CenteringRingCfg.tab.Innerdiam = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+CenteringRingCfg.tab.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430:
+CenteringRingCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+CenteringRingCfg.tab.Generalproperties = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
 
 !ComponentConfigDialog
-ComponentCfgDlg.configuration=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F
-ComponentCfgDlg.configuration1=
-ComponentCfgDlg.Modify=\u0418\u0437\u043C\u0435\u043D\u0438\u0442\u044C
+ComponentCfgDlg.configuration = \ - \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+ComponentCfgDlg.configuration1 = 
+ComponentCfgDlg.Modify = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c
+
+!StageConfig
+StageConfig.tab.Separation = \u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435
+StageConfig.tab.Separation.ttip = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0443\u043f\u0435\u043d\u0435\u0439
+StageConfig.separation.lbl.title = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435, \u043a\u043e\u0433\u0434\u0430 \u044d\u0442\u0430 \u0441\u0442\u0443\u043f\u0435\u043d\u044c \u043e\u0442\u0434\u0435\u043b\u044f\u0435\u0442\u0441\u044f:
+StageConfig.separation.lbl.plus = \u043f\u043b\u044e\u0441
+StageConfig.separation.lbl.seconds = \u0441\u0435\u043a\u0443\u043d\u0434
 
 !EllipticalFinSetConfig
-EllipticalFinSetCfg.Nbroffins= \u041A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u043E\u0432:
-EllipticalFinSetCfg.Rotation=\u0412\u0440\u0430\u0449\u0435\u043D\u0438\u0435:
-EllipticalFinSetCfg.Fincant=\u0423\u0433\u043E\u043B \u0430\u0442\u0430\u043A\u0438:
-EllipticalFinSetCfg.Rootchord=\u0425\u043E\u0440\u0434\u0430 \u043E\u0441\u043D\u043E\u0432\u0430\u043D\u0438\u044F:
-EllipticalFinSetCfg.Height=\u0412\u044B\u0441\u043E\u0442\u0430:
-EllipticalFinSetCfg.Positionrelativeto= \u041F\u043E\u043B\u043E\u0436\u0435\u043D\u0438\u0435 \u043F\u043E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044E \u043A:
-EllipticalFinSetCfg.plus=\u041F\u043B\u044E\u0441
-EllipticalFinSetCfg.FincrossSection=\u041F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430:
-EllipticalFinSetCfg.Thickness= \u0422\u043E\u043B\u0449\u0438\u043D\u0430:
-EllipticalFinSetCfg.General=\u041E\u0441\u043D\u043E\u0432\u043D\u044B\u0435
-EllipticalFinSetCfg.Generalproperties=\u041E\u0441\u043D\u043E\u0432\u043D\u044B\u0435 \u0445\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043A\u0438
-EllipticalFinSetCfg.ttip.Fincant=\u0423\u0433\u043E\u043B \u0430\u0442\u0430\u043A\u0438 \u0441\u0442\u0430\u0431\u0438\u043B\u0438\u0437\u0430\u0442\u043E\u0440\u0430 \u043F\u043E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044E \u043A \u043E\u0441\u0438 \u0440\u0430\u043A\u0435\u0442\u044B.
+EllipticalFinSetCfg.Nbroffins = \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432:
+EllipticalFinSetCfg.Rotation = \u0412\u0440\u0430\u0449\u0435\u043d\u0438\u0435:
+EllipticalFinSetCfg.Fincant = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438:
+EllipticalFinSetCfg.Rootchord = \u0414\u043b\u0438\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f:
+EllipticalFinSetCfg.Height = \u0412\u044b\u0441\u043e\u0442\u0430:
+EllipticalFinSetCfg.Positionrelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+EllipticalFinSetCfg.plus = \u043f\u043b\u044e\u0441
+EllipticalFinSetCfg.FincrossSection = \u041f\u0440\u043e\u0444\u0438\u043b\u044c \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430:
+EllipticalFinSetCfg.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430:
+EllipticalFinSetCfg.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+EllipticalFinSetCfg.Generalproperties = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+EllipticalFinSetCfg.ttip.Fincant = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u043f\u043e \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044e \u043a \u043e\u0441\u0438 \u0440\u0430\u043a\u0435\u0442\u044b.
 
 !FreeformFinSetConfig
-FreeformFinSetCfg.tab.General= General
-FreeformFinSetCfg.tab.ttip.General= General properties
-FreeformFinSetCfg.tab.Shape= Shape
-FreeformFinSetCfg.tab.ttip.Finshape= Fin shape
-FreeformFinSetCfg.lbl.Numberoffins= Number of fins:
-FreeformFinSetCfg.lbl.Finrotation= Fin rotation:
-FreeformFinSetCfg.lbl.Fincant= Fin cant:
-FreeformFinSetCfg.lbl.ttip.Fincant= The angle that the fins are canted with respect to the rocket body.
-FreeformFinSetCfg.lbl.Posrelativeto= Position relative to:
-FreeformFinSetCfg.lbl.plus= plus
-FreeformFinSetCfg.lbl.FincrossSection= Fin cross section:
-FreeformFinSetCfg.lbl.Thickness= Thickness:
+FreeformFinSetCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+FreeformFinSetCfg.tab.ttip.General = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+FreeformFinSetCfg.tab.Shape = \u0424\u043e\u0440\u043c\u0430
+FreeformFinSetCfg.tab.ttip.Finshape = \u0424\u043e\u0440\u043c\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430
+FreeformFinSetCfg.lbl.Numberoffins = \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432:
+FreeformFinSetCfg.lbl.Finrotation = \u0412\u0440\u0430\u0449\u0435\u043d\u0438\u0435:
+FreeformFinSetCfg.lbl.Fincant = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438:
+FreeformFinSetCfg.lbl.ttip.Fincant = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u043f\u043e \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044e \u043a \u043e\u0441\u0438 \u0440\u0430\u043a\u0435\u0442\u044b.
+FreeformFinSetCfg.lbl.Posrelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+FreeformFinSetCfg.lbl.plus = \u043f\u043b\u044e\u0441
+FreeformFinSetCfg.lbl.FincrossSection = \u041f\u0440\u043e\u0444\u0438\u043b\u044c \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430:
+FreeformFinSetCfg.lbl.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430:
 ! doubleClick1 + 2 form the message "Double-click to edit", split approximately at the middle
-FreeformFinSetConfig.lbl.doubleClick1= Double-click
-FreeformFinSetConfig.lbl.doubleClick2= to edit
-FreeformFinSetConfig.lbl.clickDrag= Click+drag: Add and move points
-FreeformFinSetConfig.lbl.ctrlClick= Ctrl+click: Remove point
+FreeformFinSetConfig.lbl.doubleClick1 = \u0414\u0432\u043e\u0439\u043d\u043e\u0439 \u043a\u043b\u0438\u043a
+FreeformFinSetConfig.lbl.doubleClick2 = \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f
+FreeformFinSetConfig.lbl.clickDrag = \u041a\u043b\u0438\u043a+\u0442\u0430\u0449\u0438\u0442\u044c: \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438 \u0434\u0432\u0438\u0433\u0430\u0442\u044c \u0442\u043e\u0447\u043a\u0438
+FreeformFinSetConfig.lbl.ctrlClick = Ctrl+\u043a\u043b\u0438\u043a: \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0442\u043e\u0447\u043a\u0443
+FreeformFinSetConfig.lbl.scaleFin = \u041c\u0430\u0441\u0448\u0442\u0430\u0431 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430
 
 
 !InnerTubeConfig
-InnerTubeCfg.tab.Motor= Motor
-InnerTubeCfg.tab.ttip.Motor= Motor mount configuration
-InnerTubeCfg.tab.Cluster= Cluster
-InnerTubeCfg.tab.ttip.Cluster= Cluster configuration
-InnerTubeCfg.tab.Radialpos= Radial position
-InnerTubeCfg.tab.ttip.Radialpos= Radial position
-InnerTubeCfg.lbl.Selectclustercfg= Select cluster configuration:
-InnerTubeCfg.lbl.TubeSep= Tube separation:
-InnerTubeCfg.lbl.ttip.TubeSep= The separation of the tubes, 1.0 = touching each other
-InnerTubeCfg.lbl.Rotation= Rotation:
-InnerTubeCfg.lbl.ttip.Rotation= Rotation angle of the cluster configuration
-InnerTubeCfg.lbl.Rotangle= Rotation angle of the cluster configuration
-InnerTubeCfg.but.Splitcluster= Split cluster
-InnerTubeCfg.lbl.longA1= <html>Split the cluster into separate components.<br>
-InnerTubeCfg.lbl.longA2= This also duplicates all components attached to this inner tube.
-InnerTubeCfg.but.Resetsettings= Reset settings
-InnerTubeCfg.but.ttip.Resetsettings= Reset the separation and rotation to the default values
+InnerTubeCfg.tab.Motor = \u0414\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c
+InnerTubeCfg.tab.ttip.Motor = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+InnerTubeCfg.tab.Cluster = \u041a\u043b\u0430\u0441\u0442\u0435\u0440
+InnerTubeCfg.tab.ttip.Cluster = \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430
+InnerTubeCfg.tab.Radialpos = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+InnerTubeCfg.tab.ttip.Radialpos = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+InnerTubeCfg.lbl.Selectclustercfg = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430:
+InnerTubeCfg.lbl.TubeSep = \u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u043a:
+InnerTubeCfg.lbl.ttip.TubeSep = \u041f\u0440\u043e\u043c\u0435\u0436\u0443\u0442\u043e\u043a \u043c\u0435\u0436\u0434\u0443 \u0442\u0440\u0443\u0431\u0430\u043c\u0438, 1.0
+InnerTubeCfg.lbl.Rotation = \u041f\u043e\u0432\u043e\u0440\u043e\u0442:
+InnerTubeCfg.lbl.ttip.Rotation = \u0423\u0433\u043e\u043b \u043f\u043e\u0432\u043e\u0440\u043e\u0442\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430
+InnerTubeCfg.lbl.Rotangle = \u0423\u0433\u043e\u043b \u043f\u043e\u0432\u043e\u0440\u043e\u0442\u0430 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430
+InnerTubeCfg.but.Splitcluster = \u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0442\u0435\u0440
+InnerTubeCfg.lbl.longA1 = <html>\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043b\u0430\u0441\u0442\u0435\u0440 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b.<br>
+InnerTubeCfg.lbl.longA2 = \u042d\u0442\u043e \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u043e\u0434\u0443\u0431\u043b\u0438\u0440\u0443\u0435\u0442 \u0432\u0441\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b, \u043f\u0440\u0438\u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u043d\u044b\u0435 \u043a \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0442\u0440\u0443\u0431\u0435.
+InnerTubeCfg.but.Resetsettings = \u0421\u0431\u0440\u043e\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a
+InnerTubeCfg.but.ttip.Resetsettings = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0438 \u043f\u043e\u0432\u043e\u0440\u043e\u0442\u0430 \u043d\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e
 
 ! LaunchLugConfig
-LaunchLugCfg.lbl.Length= Length:
-LaunchLugCfg.lbl.Outerdiam= Outer diameter:
-LaunchLugCfg.lbl.Innerdiam= Inner diameter:
-LaunchLugCfg.lbl.Thickness= Thickness:
-LaunchLugCfg.lbl.Radialpos= Radial position:
-LaunchLugCfg.lbl.Posrelativeto= Position relative to:
-LaunchLugCfg.lbl.plus= plus
-LaunchLugCfg.tab.General= General
-LaunchLugCfg.tab.Generalprop= General properties
+LaunchLugCfg.lbl.Length = \u0414\u043b\u0438\u043d\u0430:
+LaunchLugCfg.lbl.Outerdiam = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+LaunchLugCfg.lbl.Innerdiam = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+LaunchLugCfg.lbl.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430:
+LaunchLugCfg.lbl.Radialpos = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435:
+LaunchLugCfg.lbl.Posrelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+LaunchLugCfg.lbl.plus = \u043f\u043b\u044e\u0441
+LaunchLugCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+LaunchLugCfg.tab.Generalprop = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
 
 ! MassComponentConfig
-MassComponentCfg.lbl.Mass= Mass:
-MassComponentCfg.lbl.Length= Length:
-MassComponentCfg.lbl.Diameter= Diameter:
-MassComponentCfg.lbl.PosRelativeto= Position relative to:
-MassComponentCfg.lbl.plus= plus
-MassComponentCfg.tab.General= General
-MassComponentCfg.tab.ttip.General= General properties
-MassComponentCfg.tab.Radialpos= Radial position
-MassComponentCfg.tab.ttip.Radialpos= Radial position configuration
-MassComponentCfg.lbl.Radialdistance= Radial distance:
-MassComponentCfg.lbl.Radialdirection= Radial direction:
-MassComponentCfg.but.Reset= Reset
+MassComponentCfg.lbl.Mass = \u041c\u0430\u0441\u0441\u0430
+MassComponentCfg.lbl.Density = \u041f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043f\u043b\u043e\u0442\u043d\u043e\u0441\u0442\u044c:
+MassComponentCfg.lbl.Length = \u0414\u043b\u0438\u043d\u0430
+MassComponentCfg.lbl.Diameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440
+MassComponentCfg.lbl.PosRelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+MassComponentCfg.lbl.plus = \u043f\u043b\u044e\u0441
+MassComponentCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+MassComponentCfg.tab.ttip.General = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+MassComponentCfg.tab.Radialpos = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+MassComponentCfg.tab.ttip.Radialpos = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0440\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f
+MassComponentCfg.lbl.Radialdistance = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u044f:
+MassComponentCfg.lbl.Radialdirection = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435:
+MassComponentCfg.but.Reset = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c
 
 ! MotorConfig
-MotorCfg.checkbox.compmotormount= This component is a motor mount
-MotorCfg.lbl.Motorcfg= Motor configuration:
-MotorCfg.but.New= New
-MotorCfg.lbl.Currentmotor= Current motor:
-MotorCfg.lbl.Motoroverhang= Motor overhang:
-MotorCfg.lbl.Ignitionat= Ignition at:
-MotorCfg.lbl.plus= plus
-MotorCfg.lbl.seconds= seconds
-MotorCfg.lbl.longA1= The current design has only one stage.
-MotorCfg.lbl.longA2= Stages can be added by clicking \"New stage\".
-MotorCfg.lbl.longB1= The current design has
-MotorCfg.lbl.longB2= stages.
-MotorCfg.but.Selectmotor= Select motor
-MotorCfg.but.Removemotor= Remove motor
-MotorCfg.lbl.motorLabel= None
+MotorCfg.checkbox.compmotormount = \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u0435\u043c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+MotorCfg.lbl.Motorcfg = \u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f:
+MotorCfg.but.New = \u0421\u043e\u0437\u0434\u0430\u0442\u044c
+MotorCfg.lbl.Currentmotor = \u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c:
+MotorCfg.lbl.Motoroverhang = \u0421\u0432\u0435\u0441 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f:
+MotorCfg.lbl.Ignitionat = \u0412\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d\u0435\u043d\u0438\u0435:
+MotorCfg.lbl.plus = \u043f\u043b\u044e\u0441
+MotorCfg.lbl.seconds = \u0441\u0435\u043a\u0443\u043d\u0434
+MotorCfg.lbl.longA1 = \u0412 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0445\u0435\u043c\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 \u0441\u0442\u0443\u043f\u0435\u043d\u044c.
+MotorCfg.lbl.longA2 = \u0421\u0442\u0443\u043f\u0435\u043d\u0438 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c, \u043d\u0430\u0436\u0430\u0432 "\u041d\u043e\u0432\u0430\u044f \u0441\u0442\u0443\u043f\u0435\u043d\u044c".
+MotorCfg.lbl.longB1 = \u0412 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0445\u0435\u043c\u0435
+MotorCfg.lbl.longB2 = \u0441\u0442\u0443\u043f\u0435\u043d\u0435\u0439.
+MotorCfg.but.Selectmotor = \u0412\u044b\u0431\u0440\u0430\u0442\u044c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c
+MotorCfg.but.Removemotor = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c
+MotorCfg.lbl.motorLabel = \u041d\u0435\u0442
 
 ! NoseConeConfig
-NoseConeCfg.lbl.Noseconeshape= Nose cone shape:
-NoseConeCfg.lbl.Shapeparam= Shape parameter:
-NoseConeCfg.lbl.Noseconelength= Nose cone length:
-NoseConeCfg.lbl.Basediam= Base diameter:
-NoseConeCfg.checkbox.Automatic= Automatic
-NoseConeCfg.lbl.Wallthickness= Wall thickness:
-NoseConeCfg.checkbox.Filled= Filled
-NoseConeCfg.tab.General= General
-NoseConeCfg.tab.ttip.General= General properties
-NoseConeCfg.tab.Shoulder= Shoulder
-NoseConeCfg.tab.ttip.Shoulder= Shoulder properties
+NoseConeCfg.lbl.Noseconeshape = \u0424\u043e\u0440\u043c\u0430 \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044f:
+NoseConeCfg.lbl.Shapeparam = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0444\u043e\u0440\u043c\u044b:
+NoseConeCfg.lbl.Noseconelength = \u0414\u043b\u0438\u043d\u0430 \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044f:
+NoseConeCfg.lbl.Basediam = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f:
+NoseConeCfg.checkbox.Automatic = \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438
+NoseConeCfg.lbl.Wallthickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430 \u0441\u0442\u0435\u043d\u043a\u0438:
+NoseConeCfg.checkbox.Filled = \u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0439
+NoseConeCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+NoseConeCfg.tab.ttip.General = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+NoseConeCfg.tab.Shoulder = \u0412\u044b\u0441\u0442\u0443\u043f \u043c\u0443\u0444\u0442\u044b
+NoseConeCfg.tab.ttip.Shoulder = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u044b\u0441\u0442\u0443\u043f\u0430 \u043c\u0443\u0444\u0442\u044b
 
 ! ParachuteConfig
-ParachuteCfg.lbl.Canopy= Canopy:
-ParachuteCfg.lbl.Diameter= Diameter:
-ParachuteCfg.lbl.Material= Material:
-ParachuteCfg.combo.MaterialModel= The component material affects the weight of the component.
-ParachuteCfg.lbl.longA1= <html>Drag coefficient C<sub>D</sub>:
-ParachuteCfg.lbl.longB1= <html>The drag coefficient relative to the total area of the parachute.<br>
-ParachuteCfg.lbl.longB2= A larger drag coefficient yields a slowed descent rate.  
-ParachuteCfg.lbl.longB3= A typical value for parachutes is 0.8.
-ParachuteCfg.but.Reset= Reset
-ParachuteCfg.lbl.Shroudlines= Shroud lines:
-ParachuteCfg.lbl.Numberoflines= Number of lines:
-ParachuteCfg.lbl.Linelength= Line length:
-ParachuteCfg.lbl.Material= Material:
-ParachuteCfg.lbl.Posrelativeto= Position relative to:
-ParachuteCfg.lbl.plus= plus
-ParachuteCfg.lbl.Packedlength= Packed length:
-ParachuteCfg.lbl.Packeddiam= Packed diameter:
-ParachuteCfg.lbl.Deploysat= Deploys at:
-ParachuteCfg.lbl.seconds= seconds
-ParachuteCfg.lbl.Altitude= Altitude:
-ParachuteCfg.tab.General= General
-ParachuteCfg.tab.ttip.General= General properties
-ParachuteCfg.tab.Radialpos= Radial position
-ParachuteCfg.tab.ttip.Radialpos= Radial position configuration
-ParachuteCfg.lbl.Radialdistance= Radial distance:
-ParachuteCfg.lbl.Radialdirection= Radial direction:
-ParachuteCfg.but.Reset= Reset
-ParachuteCfg.lbl.plusdelay= plus
-
-! ShockCordConfig 
-ShockCordCfg.lbl.Shockcordlength= Shock cord length:
-ShockCordCfg.lbl.Shockcordmaterial= Shock cord material:
-ShockCordCfg.lbl.Posrelativeto= Position relative to:
-ShockCordCfg.lbl.plus= plus
-ShockCordCfg.lbl.Packedlength= Packed length:
-ShockCordCfg.lbl.Packeddiam= Packed diameter:
-ShockCordCfg.tab.General= General
-ShockCordCfg.tab.ttip.General= General properties
+ParachuteCfg.lbl.Canopy = \u041a\u0443\u043f\u043e\u043b:
+ParachuteCfg.lbl.Diameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440:
+ParachuteCfg.lbl.Material = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b:
+ParachuteCfg.combo.MaterialModel = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0435\u0433\u043e \u043c\u0430\u0441\u0441\u0443.
+ParachuteCfg.lbl.longA1 = <html>\u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f C<sub>D</sub>:
+ParachuteCfg.lbl.longB1 = <html>\u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u0449\u0435\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u0438 \u043f\u0430\u0440\u0430\u0448\u044e\u0442\u0430.<br>
+ParachuteCfg.lbl.longB2 = \u0411\u043e\u043b\u044c\u0448\u0438\u0439 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u043e\u0435 \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u0435.
+ParachuteCfg.lbl.longB3 = \u0422\u0438\u043f\u0438\u0447\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u0430\u0440\u0430\u0448\u044e\u0442\u043e\u0432 0.8.
+ParachuteCfg.but.Reset = \u0421\u0431\u0440\u043e\u0441
+ParachuteCfg.lbl.Shroudlines = \u0421\u0442\u0440\u043e\u043f\u044b:
+ParachuteCfg.lbl.Numberoflines = \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043f:
+ParachuteCfg.lbl.Linelength = \u0414\u043b\u0438\u043d\u0430 \u0441\u0442\u0440\u043e\u043f:
+ParachuteCfg.lbl.Material = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b:
+ParachuteCfg.lbl.Posrelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+ParachuteCfg.lbl.plus = \u043f\u043b\u044e\u0441
+ParachuteCfg.lbl.Packedlength = \u0414\u043b\u0438\u043d\u0430 \u0443\u043a\u043b\u0430\u0434\u043a\u0438:
+ParachuteCfg.lbl.Packeddiam = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u0443\u043a\u043b\u0430\u0434\u043a\u0438:
+ParachuteCfg.lbl.Deploysat = \u0420\u0430\u0441\u043a\u0440\u044b\u0442\u0438\u0435 \u043f\u0440\u0438:
+ParachuteCfg.lbl.seconds = \u0441\u0435\u043a\u0443\u043d\u0434
+ParachuteCfg.lbl.Altitude = \u0412\u044b\u0441\u043e\u0442\u0430:
+ParachuteCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+ParachuteCfg.tab.ttip.General = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+ParachuteCfg.tab.Radialpos = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+ParachuteCfg.tab.ttip.Radialpos = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0440\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f
+ParachuteCfg.lbl.Radialdistance = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435:
+ParachuteCfg.lbl.Radialdirection = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435:
+ParachuteCfg.but.Reset = \u0421\u0431\u0440\u043e\u0441
+ParachuteCfg.lbl.plusdelay = \u043f\u043b\u044e\u0441
+
+! ShockCordConfig
+ShockCordCfg.lbl.Shockcordlength = \u0414\u043b\u0438\u043d\u0430 \u0441\u0442\u0440\u043e\u043f\u044b
+ShockCordCfg.lbl.Shockcordmaterial = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0440\u043e\u043f\u044b:
+ShockCordCfg.lbl.Posrelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+ShockCordCfg.lbl.plus = \u043f\u043b\u044e\u0441
+ShockCordCfg.lbl.Packedlength = \u0414\u043b\u0438\u043d\u0430 \u0443\u043a\u043b\u0430\u0434\u043a\u0438:
+ShockCordCfg.lbl.Packeddiam = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u0443\u043a\u043b\u0430\u0434\u043a\u0438:
+ShockCordCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+ShockCordCfg.tab.ttip.General = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
 
 !SleeveConfig
-SleeveCfg.tab.Outerdiam= Outer diameter:
-SleeveCfg.tab.Innerdiam= Inner diameter:
-SleeveCfg.tab.Wallthickness= Wall thickness:
-SleeveCfg.tab.Length= Length:
-SleeveCfg.tab.General= General
-SleeveCfg.tab.Generalproperties= General properties
+SleeveCfg.tab.Outerdiam = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+SleeveCfg.tab.Innerdiam = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+SleeveCfg.tab.Wallthickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430 \u0441\u0442\u0435\u043d\u043a\u0438:
+SleeveCfg.tab.Length = \u0414\u043b\u0438\u043d\u0430:
+SleeveCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+SleeveCfg.tab.Generalproperties = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
 
 ! StreamerConfig
-StreamerCfg.lbl.Striplength= Strip length:
-StreamerCfg.lbl.Stripwidth= Strip width:
-StreamerCfg.lbl.Striparea= Strip area:
-StreamerCfg.lbl.Aspectratio= Aspect ratio:
-StreamerCfg.lbl.Material= Material:
-StreamerCfg.combo.ttip.MaterialModel= The component material affects the weight of the component.
-StreamerCfg.lbl.longA1= <html>Drag coefficient C<sub>D</sub>:
-StreamerCfg.lbl.longB1= <html>The drag coefficient relative to the total area of the streamer.<br>
-StreamerCfg.lbl.longB2= A larger drag coefficient yields a slowed descent rate.
-StreamerCfg.lbl.Automatic= Automatic
-StreamerCfg.lbl.longC1= The drag coefficient is relative to the area of the streamer.
-StreamerCfg.lbl.Posrelativeto= Position relative to:
-StreamerCfg.lbl.plus= plus
-StreamerCfg.lbl.Packedlength= Packed length:
-StreamerCfg.lbl.Packeddiam= Packed diameter:
-StreamerCfg.lbl.Deploysat= Deploys at:
-StreamerCfg.lbl.seconds= seconds
-StreamerCfg.lbl.Altitude= Altitude:
-StreamerCfg.tab.General= General
-StreamerCfg.tab.ttip.General= General properties
-StreamerCfg.tab.Radialpos= Radial position
-StreamerCfg.tab.ttip.Radialpos= Radial position configuration
-StreamerCfg.lbl.Radialdistance= Radial distance:
-StreamerCfg.lbl.Radialdirection= Radial direction:
-StreamerCfg.but.Reset= Reset
-StreamerCfg.lbl.plusdelay= plus
+StreamerCfg.lbl.Striplength = \u0414\u043b\u0438\u043d\u0430 \u043b\u0435\u043d\u0442\u044b:
+StreamerCfg.lbl.Stripwidth = \u0428\u0438\u0440\u0438\u043d\u0430 \u043b\u0435\u043d\u0442\u044b:
+StreamerCfg.lbl.Striparea = \u041f\u043b\u043e\u0449\u0430\u0434\u044c \u043b\u0435\u043d\u0442\u044b:
+StreamerCfg.lbl.Aspectratio = \u041e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d:
+StreamerCfg.lbl.Material = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b:
+StreamerCfg.combo.ttip.MaterialModel = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0432\u043b\u0438\u044f\u0435\u0442 \u043d\u0430 \u0435\u0433\u043e \u043c\u0430\u0441\u0441\u0443.
+StreamerCfg.lbl.longA1 = <html>\u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f C<sub>D</sub>:
+StreamerCfg.lbl.longB1 = <html>\u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043e\u0431\u0449\u0435\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u0438 \u043b\u0435\u043d\u0442\u044b.<br>
+StreamerCfg.lbl.longB2 = \u0411\u043e\u043b\u044c\u0448\u0438\u0439 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043b\u043e\u0431\u043e\u0432\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u0435\u0442 \u043c\u0435\u043d\u044c\u0448\u0443\u044e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0441\u043d\u0438\u0436\u0435\u043d\u0438\u044f.
+StreamerCfg.lbl.Automatic = \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438
+StreamerCfg.lbl.longC1 = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0441\u043e\u043f\u0440\u043e\u0442\u043e\u0438\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043f\u043b\u043e\u0449\u0430\u0434\u0438 \u043b\u0435\u043d\u0442\u044b.
+StreamerCfg.lbl.Posrelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+StreamerCfg.lbl.plus = \u043f\u043b\u044e\u0441
+StreamerCfg.lbl.Packedlength = \u0414\u043b\u0438\u043d\u0430 \u0443\u043a\u043b\u0430\u0434\u043a\u0438:
+StreamerCfg.lbl.Packeddiam = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u0443\u043a\u043b\u0430\u0434\u043a\u0438:
+StreamerCfg.lbl.Deploysat = \u0421\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0438:
+StreamerCfg.lbl.seconds = \u0441\u0435\u043a\u0443\u043d\u0434
+StreamerCfg.lbl.Altitude = \u0412\u044b\u0441\u043e\u0442\u0430:
+StreamerCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+StreamerCfg.tab.ttip.General = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+StreamerCfg.tab.Radialpos = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+StreamerCfg.tab.ttip.Radialpos = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0440\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f
+StreamerCfg.lbl.Radialdistance = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435:
+StreamerCfg.lbl.Radialdirection = \u0420\u0430\u0434\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435:
+StreamerCfg.but.Reset = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c
+StreamerCfg.lbl.plusdelay = \u043f\u043b\u044e\u0441
 
 ! ThicknessRingComponentConfig
-ThicknessRingCompCfg.tab.Outerdiam= Outer diameter:
-ThicknessRingCompCfg.tab.Innerdiam= Inner diameter:
-ThicknessRingCompCfg.tab.Wallthickness= Wall thickness:
-ThicknessRingCompCfg.tab.Length= Length:
-ThicknessRingCompCfg.tab.General= General
-ThicknessRingCompCfg.tab.Generalprop= General properties
+ThicknessRingCompCfg.tab.Outerdiam = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+ThicknessRingCompCfg.tab.Innerdiam = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440:
+ThicknessRingCompCfg.tab.Wallthickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430 \u0441\u0442\u0435\u043d\u043a\u0438:
+ThicknessRingCompCfg.tab.Length = \u0414\u043b\u0438\u043d\u0430:
+ThicknessRingCompCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+ThicknessRingCompCfg.tab.Generalprop = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
 
 ! TransitionConfig
-TransitionCfg.lbl.Transitionshape= Transition shape:
-TransitionCfg.checkbox.Clipped= Clipped
-TransitionCfg.lbl.Shapeparam= Shape parameter:
-TransitionCfg.lbl.Transitionlength= Transition length:
-TransitionCfg.lbl.Forediam= Fore diameter:
-TransitionCfg.checkbox.Automatic= Automatic
-TransitionCfg.lbl.Aftdiam= Aft diameter:
-TransitionCfg.lbl.Wallthickness= Wall thickness:
-TransitionCfg.checkbox.Filled= Filled
-TransitionCfg.tab.General= General
-TransitionCfg.tab.Generalproperties= General properties
-TransitionCfg.tab.Shoulder= Shoulder
-TransitionCfg.tab.Shoulderproperties= Shoulder properties
+TransitionCfg.lbl.Transitionshape = \u0424\u043e\u0440\u043c\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430:
+TransitionCfg.checkbox.Clipped = \u041e\u0431\u0440\u0435\u0437\u0430\u043d
+TransitionCfg.lbl.Shapeparam = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0444\u043e\u0440\u043c\u044b:
+TransitionCfg.lbl.Transitionlength = \u0414\u043b\u0438\u043d\u0430 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430:
+TransitionCfg.lbl.Forediam = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u0432\u044b\u0445\u043e\u0434\u0430:
+TransitionCfg.checkbox.Automatic = \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438
+TransitionCfg.lbl.Aftdiam = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u0432\u0445\u043e\u0434\u0430:
+TransitionCfg.lbl.Wallthickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430 \u0441\u0442\u0435\u043d\u043a\u0438:
+TransitionCfg.checkbox.Filled = \u0417\u0430\u043b\u0438\u0442
+TransitionCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+TransitionCfg.tab.Generalproperties = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
+TransitionCfg.tab.Shoulder = \u0412\u044b\u0441\u0442\u0443\u043f
+TransitionCfg.tab.Shoulderproperties = \u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u0432\u044b\u0441\u0442\u0443\u043f\u0430
 
 ! TrapezoidFinSetConfig
-TrapezoidFinSetCfg.lbl.Nbroffins= Number of fins:
-TrapezoidFinSetCfg.lbl.ttip.Nbroffins= The number of fins in the fin set.
-TrapezoidFinSetCfg.lbl.Finrotation= Fin rotation:
-TrapezoidFinSetCfg.lbl.ttip.Finrotation= The angle of the first fin in the fin set.
-TrapezoidFinSetCfg.lbl.Fincant= Fin cant:
-TrapezoidFinSetCfg.lbl.ttip.Fincant=The angle that the fins are canted with respect to the rocket body.
-TrapezoidFinSetCfg.lbl.Rootchord= Root chord:
-TrapezoidFinSetCfg.lbl.Tipchord= Tip chord:
-TrapezoidFinSetCfg.lbl.Height= Height:
-TrapezoidFinSetCfg.lbl.Sweeplength= Sweep length:
-TrapezoidFinSetCfg.lbl.Sweepangle= Sweep angle:
-TrapezoidFinSetCfg.lbl.FincrossSection= Fin cross section:
-TrapezoidFinSetCfg.lbl.Thickness= Thickness:
-TrapezoidFinSetCfg.lbl.Posrelativeto= Position relative to:
-TrapezoidFinSetCfg.lbl.plus= plus
-TrapezoidFinSetCfg.tab.General= General
-TrapezoidFinSetCfg.tab.Generalproperties= General properties
+TrapezoidFinSetCfg.lbl.Nbroffins = \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432:
+TrapezoidFinSetCfg.lbl.ttip.Nbroffins = \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432 \u0432 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0438.
+TrapezoidFinSetCfg.lbl.Finrotation = \u0412\u0440\u0430\u0449\u0435\u043d\u0438\u0435:
+TrapezoidFinSetCfg.lbl.ttip.Finrotation = \u041f\u043e\u0432\u043e\u0440\u043e\u0442 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u0432 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0438.
+TrapezoidFinSetCfg.lbl.Fincant = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438:
+TrapezoidFinSetCfg.lbl.ttip.Fincant = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u043f\u043e \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044e \u043a \u043e\u0441\u0438 \u0440\u0430\u043a\u0435\u0442\u044b.
+TrapezoidFinSetCfg.lbl.Rootchord = \u0414\u043b\u0438\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f:
+TrapezoidFinSetCfg.lbl.Tipchord = \u0414\u043b\u0438\u043d\u0430 \u043d\u0430\u043a\u043e\u043d\u0435\u0447\u043d\u0438\u043a\u0430:
+TrapezoidFinSetCfg.lbl.Height = \u0412\u044b\u0441\u043e\u0442\u0430:
+TrapezoidFinSetCfg.lbl.Sweeplength = \u0414\u043b\u0438\u043d\u0430 \u0441\u0442\u0440\u0435\u043b\u043e\u0432\u0438\u0434\u043d\u043e\u0441\u0442\u0438:
+TrapezoidFinSetCfg.lbl.Sweepangle = \u0423\u0433\u043e\u043b \u0441\u0442\u0440\u0435\u043b\u043e\u0432\u0438\u0434\u043d\u043e\u0441\u0442\u0438:
+TrapezoidFinSetCfg.lbl.FincrossSection = \u041f\u0440\u043e\u0444\u0438\u043b\u044c \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430:
+TrapezoidFinSetCfg.lbl.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430:
+TrapezoidFinSetCfg.lbl.Posrelativeto = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e:
+TrapezoidFinSetCfg.lbl.plus = \u043f\u043b\u044e\u0441
+TrapezoidFinSetCfg.tab.General = \u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0435
+TrapezoidFinSetCfg.tab.Generalproperties = \u041e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
 
 !MotorConfigurationModel
-MotorCfgModel.Editcfg= Edit configurations
+MotorCfgModel.Editcfg = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438
 
 ! StorageOptionChooser
-StorageOptChooser.lbl.Simdatatostore= Simulated data to store:
-StorageOptChooser.rdbut.Allsimdata= All simulated data
-StorageOptChooser.lbl.longA1= <html>Store all simulated data.<br>
-StorageOptChooser.lbl.longA2= This can result in very large files!
-StorageOptChooser.rdbut.Every= Every
-StorageOptChooser.lbl.longB1= <html>Store plottable values approximately this far apart.<br>
-StorageOptChooser.lbl.longB2= Larger values result in smaller files.
-StorageOptChooser.lbl.seconds= seconds
-StorageOptChooser.rdbut.Onlyprimfig= Only primary figures
-StorageOptChooser.lbl.longC1= <html>Store only the values shown in the summary table.<br>
-StorageOptChooser.lbl.longC2= This results in the smallest files.
-StorageOptChooser.checkbox.Compfile= Compress file
-StorageOptChooser.lbl.UsingComp= Using compression reduces the file size significantly.
-StorageOptChooser.lbl.longD1= An estimate on how large the resulting file would be with the present options.
-StorageOptChooser.ttip.Saveopt= Save options
-StorageOptChooser.lbl.Estfilesize= Estimated file size:
-StorageOptChooser.lbl.Saveopt= Save options
+StorageOptChooser.lbl.Simdatatostore = \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0441\u0447\u0442\u043e\u0432:
+StorageOptChooser.rdbut.Allsimdata = \u0412\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+StorageOptChooser.lbl.longA1 = <html>\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u0432.<br>
+StorageOptChooser.lbl.longA2 = \u0420\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430 \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u0431\u043e\u043b\u044c\u0448\u0438\u043c!
+StorageOptChooser.rdbut.Every = \u041a\u0430\u0436\u0434\u044b\u0435
+StorageOptChooser.lbl.longB1 = <html>\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0440\u0430\u0441\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0441 \u0442\u0430\u043a\u043e\u0439 \u0447\u0430\u0441\u0442\u043e\u0442\u043e\u0439.<br>
+StorageOptChooser.lbl.longB2 = \u0411\u043e\u043b\u044c\u0448\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u044e\u0442 \u043c\u0435\u043d\u044c\u0448\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430.
+StorageOptChooser.lbl.seconds = \u0441\u0435\u043a\u0443\u043d\u0434
+StorageOptChooser.rdbut.Onlyprimfig = \u0422\u043e\u043b\u044c\u043a\u043e \u0441\u0445\u0435\u043c\u0443
+StorageOptChooser.lbl.longC1 = <html>\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0441\u0432\u043e\u0434\u043d\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u0435<br>
+StorageOptChooser.lbl.longC2 = \u042d\u0442\u043e \u0434\u0430\u0435\u0442 \u043d\u0430\u0438\u043c\u0435\u043d\u044c\u0448\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430.
+StorageOptChooser.checkbox.Compfile = \u0421\u0436\u0430\u0442\u044c \u0444\u0430\u0439\u043b
+StorageOptChooser.lbl.UsingComp = \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0436\u0430\u0442\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430.
+StorageOptChooser.lbl.longD1 = \u041f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u043e\u0446\u0435\u043d\u043a\u0430 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0440\u0438\u0443\u044e\u0449\u0435\u0433\u043e \u0444\u0430\u0439\u043b\u0430 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438.
+StorageOptChooser.ttip.Saveopt = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430
+StorageOptChooser.lbl.Estfilesize = \u041e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430:
+StorageOptChooser.lbl.Saveopt = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f
 
 ! ThrustCurveMotorSelectionPanel
-TCMotorSelPan.lbl.Selrocketmotor= Select rocket motor:
-TCMotorSelPan.checkbox.hideSimilar= Hide very similar thrust curves
-TCMotorSelPan.SHOW_DESCRIPTIONS.desc1= Show all motors
-TCMotorSelPan.SHOW_DESCRIPTIONS.desc2= Show motors with diameter less than that of the motor mount
-TCMotorSelPan.SHOW_DESCRIPTIONS.desc3= Show motors with diameter equal to that of the motor mount
-TCMotorSelPan.lbl.Motormountdia= Motor mount diameter:
-TCMotorSelPan.lbl.Search= Search:
-TCMotorSelPan.lbl.Selectthrustcurve= Select thrust curve:
-TCMotorSelPan.lbl.Ejectionchargedelay= Ejection charge delay:
-TCMotorSelPan.equalsIgnoreCase.None= None
-TCMotorSelPan.lbl.NumberofsecondsorNone= (Number of seconds or \"None\")
-TCMotorSelPan.lbl.Totalimpulse= Total impulse:
-TCMotorSelPan.lbl.Avgthrust= Avg. thrust:
-TCMotorSelPan.lbl.Maxthrust= Max. thrust:
-TCMotorSelPan.lbl.Burntime= Burn time:
-TCMotorSelPan.lbl.Launchmass= Launch mass:
-TCMotorSelPan.lbl.Emptymass= Empty mass:
-TCMotorSelPan.lbl.Datapoints= Data points:
-TCMotorSelPan.lbl.Digest= Digest:
-TCMotorSelPan.title.Thrustcurve= Thrust curve:
-TCMotorSelPan.title.Thrust= Thrust
-TCMotorSelPan.delayBox.None= None
+TCMotorSelPan.lbl.Selrocketmotor = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u0430\u043a\u0435\u0442\u043d\u044b\u0439 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044c:
+TCMotorSelPan.checkbox.hideSimilar = \u0421\u043a\u0440\u044b\u0442\u044c \u043f\u043e\u0445\u043e\u0436\u0438\u0435 \u043f\u0440\u043e\u0444\u0438\u043b\u0438 \u0442\u044f\u0433\u0438
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc1 = \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0441\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0438
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc2 = \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0438 \u0441 \u0434\u0438\u0430\u043c\u0435\u0442\u0440\u043e\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u044f
+TCMotorSelPan.SHOW_DESCRIPTIONS.desc3 = \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0438 \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u0434\u0438\u0430\u043c\u0435\u0442\u0440\u043e\u043c, \u043a\u0430\u043a \u0443 \u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u044f
+TCMotorSelPan.lbl.Motormountdia = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u043a\u0440\u0435\u043f\u043b\u0435\u043d\u0438\u044f:
+TCMotorSelPan.lbl.Search = \u041f\u043e\u0438\u0441\u043a:
+TCMotorSelPan.lbl.Selectthrustcurve = \u0412\u044b\u0431\u043e\u0440 \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u0442\u044f\u0433\u0438:
+TCMotorSelPan.lbl.Ejectionchargedelay = \u0417\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u0432\u044b\u0431\u0440\u043e\u0441\u0430 \u0437\u0430\u0440\u044f\u0434\u0430:
+TCMotorSelPan.equalsIgnoreCase.None = \u041d\u0435\u0442
+TCMotorSelPan.lbl.NumberofsecondsorNone = (\u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u043a\u0443\u043d\u0434 \u0438\u043b\u0438 "\u041d\u0435\u0442")
+TCMotorSelPan.lbl.Totalimpulse = \u041e\u0431\u0449\u0438\u0439 \u0438\u043c\u043f\u0443\u043b\u044c\u0441:
+TCMotorSelPan.lbl.Avgthrust = \u0421\u0440\u0435\u0434\u043d\u044f\u044f \u0442\u044f\u0433\u0430:
+TCMotorSelPan.lbl.Maxthrust = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u044f\u0430 \u0442\u044f\u0433\u0430:
+TCMotorSelPan.lbl.Burntime = \u0412\u0440\u0435\u043c\u044f \u0433\u043e\u0440\u0435\u043d\u0438\u044f:
+TCMotorSelPan.lbl.Launchmass = \u0421\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u044f \u043c\u0430\u0441\u0441\u0430:
+TCMotorSelPan.lbl.Emptymass = \u041e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u0430\u044f \u043c\u0430\u0441\u0441\u0430:
+TCMotorSelPan.lbl.Datapoints = \u0422\u043e\u0447\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445:
+TCMotorSelPan.lbl.Digest = \u0420\u0435\u0437\u044e\u043c\u0435:
+TCMotorSelPan.title.Thrustcurve = \u041f\u0440\u043e\u0444\u0438\u043b\u044c \u0442\u044f\u0433\u0438:
+TCMotorSelPan.title.Thrust = \u0422\u044f\u0433\u0430
+TCMotorSelPan.delayBox.None = \u041d\u0435\u0442
+TCMotorSelPan.noDescription = \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442.
 
 
 ! PlotDialog
-PlotDialog.title.Flightdataplot= Flight data plot
-PlotDialog.Chart.Simulatedflight= Simulated flight
-PlotDialog.CheckBox.Showdatapoints= Show data points
-PlotDialog.lbl.Chart= Click and drag down+right to zoom in, up+left to zoom out
+PlotDialog.title.Flightdataplot = \u0413\u0440\u0430\u0444\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0442\u0430
+PlotDialog.Chart.Simulatedflight = \u0420\u0430\u0441\u0447\u0435\u0442 \u043f\u043e\u043b\u0435\u0442\u0430
+PlotDialog.CheckBox.Showdatapoints = \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u043e\u0447\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445
+PlotDialog.lbl.Chart = \u041a\u043b\u0438\u043a+\u0442\u0430\u0449\u0438\u0442\u044c \u0432\u043d\u0438\u0437-\u0432\u043f\u0440\u0430\u0432\u043e \u0434\u043b\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u044f, \u0442\u0430\u0449\u0438\u0442\u044c \u0432\u043b\u0435\u0432\u043e-\u0432\u0432\u0435\u0440\u0445 \u0434\u043b\u044f \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u044f
 
 
 ! "main" prefix is used for the main application dialog
 
-# FIXME: Rename the description keys 
-
-main.menu.file= File
-main.menu.file.desc= File-handling related tasks
-main.menu.file.new= New
-main.menu.file.new.desc= Create a new rocket design
-main.menu.file.open= Open...
-BasicFrame.item.Openrocketdesign= Open a rocket design
-main.menu.file.openExample= Open example...
-BasicFrame.item.Openexamplerocketdesign= Open an example rocket design
-main.menu.file.save= Save
-BasicFrame.item.SavecurRocketdesign= Save the current rocket design
-main.menu.file.saveAs= Save as...
-BasicFrame.item.SavecurRocketdesnewfile= Save the current rocket design to a new file
-main.menu.file.print= Print / Export PDF...
-main.menu.file.print.desc= Print or save as PDF the parts list and fin templates
-main.menu.file.close= Close
-BasicFrame.item.Closedesign= Close the current rocket design
-main.menu.file.quit= Quit
-BasicFrame.item.Quitprogram= Quit the program
-
-main.menu.edit= Edit
-BasicFrame.menu.Rocketedt= Rocket editing
-main.menu.edit.undo= Undo
-main.menu.edit.undo.desc= Undo the previous operation
-main.menu.edit.redo= Redo
-main.menu.edit.redo.desc= Redo the previously undone operation
-main.menu.edit.cut= Cut
-main.menu.edit.copy= Copy
-main.menu.edit.paste= Paste
-main.menu.edit.delete= Delete
-main.menu.edit.resize= Scale...
-main.menu.edit.resize.desc= Scale parts of the rocket design
-main.menu.edit.preferences= Preferences
-main.menu.edit.preferences.desc= Setup the application preferences
-
-main.menu.analyze= Analyze
-main.menu.analyze.desc= Rocket analysis
-main.menu.analyze.componentAnalysis= Component analysis
-main.menu.analyze.componentAnalysis.desc= Analyze the rocket components separately
-main.menu.analyze.optimization= Rocket optimization
-main.menu.analyze.optimization.desc= General rocket design optimization
-
-main.menu.help= Help
-main.menu.help.desc= Information about OpenRocket
-main.menu.help.tours= Guided tours
-main.menu.help.tours.desc= Take guided tours on OpenRocket
-main.menu.help.license= License
-main.menu.help.license.desc= OpenRocket license information
-main.menu.help.bugReport= Bug report
-main.menu.help.bugReport.desc= Information about reporting bugs in OpenRocket
-main.menu.help.debugLog= Debug log
-main.menu.help.debugLog.desc= View the OpenRocket debug log
-main.menu.help.about= About
-main.menu.help.about.desc= Copyright details about OpenRocket
-
-main.menu.debug= Debug
-main.menu.debug.whatisthismenu= What is this menu?
-main.menu.debug.createtestrocket= Create test rocket
+# FIXME: Rename the description keys
+
+main.menu.file = \u0424\u0430\u0439\u043b
+main.menu.file.desc = \u0417\u0430\u0434\u0430\u0447\u0438, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u0444\u0430\u0439\u043b\u0430\u043c\u0438
+main.menu.file.new = \u041d\u043e\u0432\u044b\u0439
+main.menu.file.new.desc = \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0441\u0445\u0435\u043c\u0443 \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.file.open = \u041e\u0442\u043a\u0440\u044b\u0442\u044c...
+BasicFrame.item.Openrocketdesign = \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0441\u0445\u0435\u043c\u0443 \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.file.openRecent = \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u044b...
+BasicFrame.item.Openrecentrocketdesign = \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0437\u0430\u043d\u043e\u0432\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u044b
+main.menu.file.openExample = \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440...
+BasicFrame.item.Openexamplerocketdesign = \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u0445\u0435\u043c\u044b \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.file.save = \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c
+BasicFrame.item.SavecurRocketdesign = \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0441\u0445\u0435\u043c\u0443 \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.file.saveAs = \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a...
+BasicFrame.item.SavecurRocketdesnewfile = \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0441\u0445\u0435\u043c\u0443 \u0440\u0430\u043a\u0435\u0442\u044b \u0432 \u043d\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b
+main.menu.file.print = \u041f\u0435\u0447\u0430\u0442\u044c / \u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 PDF...
+main.menu.file.print.desc = \u041d\u0430\u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c \u0438\u043b\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 PDF \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u0435\u0442\u0430\u043b\u0435\u0439 \u0438 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432
+main.menu.file.close = \u0417\u0430\u043a\u0440\u044b\u0442\u044c
+BasicFrame.item.Closedesign = \u0417\u0430\u043a\u0440\u044b\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0441\u0445\u0435\u043c\u0443 \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.file.quit = \u0412\u044b\u0445\u043e\u0434
+BasicFrame.item.Quitprogram = \u0412\u044b\u0439\u0442\u0438 \u0438\u0437 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b
+
+main.menu.edit = \u041f\u0440\u0430\u0432\u043a\u0430
+BasicFrame.menu.Rocketedt = \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.edit.undo = \u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c
+main.menu.edit.undo.desc = \u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435
+main.menu.edit.redo = \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c
+main.menu.edit.redo.desc = \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u043e\u0442\u043c\u0435\u043d\u0435\u043d\u043d\u043e\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435
+main.menu.edit.cut = \u0412\u044b\u0440\u0435\u0437\u0430\u0442\u044c
+main.menu.edit.copy = \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c
+main.menu.edit.paste = \u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c
+main.menu.edit.delete = \u0423\u0434\u0430\u043b\u0438\u0442\u044c
+main.menu.edit.resize = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c...
+main.menu.edit.resize.desc = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0435\u0442\u0430\u043b\u0438 \u0441\u0445\u0435\u043c\u044b
+main.menu.edit.preferences = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438
+main.menu.edit.preferences.desc = \u0418\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f
+
+main.menu.analyze = \u0410\u043d\u0430\u043b\u0438\u0437
+main.menu.analyze.desc = \u0410\u043d\u0430\u043b\u0438\u0437 \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.analyze.componentAnalysis = \u0410\u043d\u0430\u043b\u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432
+main.menu.analyze.componentAnalysis.desc = \u0410\u043d\u0430\u043b\u0438\u0437 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432 \u0440\u0430\u043a\u0435\u0442\u044b \u043f\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438
+main.menu.analyze.optimization = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.analyze.optimization.desc = \u041e\u0431\u0449\u0430\u044f\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0440\u0430\u043a\u0435\u0442\u044b
+main.menu.analyze.customExpressions = \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f
+main.menu.analyze.customExpressions.desc = \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u043e\u0432\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0442\u0430 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439
+
+main.menu.help = \u0421\u043f\u0440\u0430\u0432\u043a\u0430
+main.menu.help.desc = \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0431 OpenRocket
+main.menu.help.tours = \u041f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0430
+main.menu.help.tours.desc = \u041f\u043e\u0441\u0435\u0442\u0438\u0442\u044c \u044d\u043a\u0441\u043a\u0443\u0440\u0441\u0438\u044e \u043f\u043e OpenRocket
+main.menu.help.license = \u041b\u0438\u0446\u0435\u043d\u0437\u0438\u044f
+main.menu.help.license.desc = \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043b\u0438\u0446\u0435\u043d\u0437\u0438\u0438 OpenRocket
+main.menu.help.bugReport = \u041e\u0442\u0447\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0435
+main.menu.help.bugReport.desc = \u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c OpenRocket
+main.menu.help.debugLog = \u0416\u0443\u0440\u043d\u0430\u043b \u043e\u0442\u043b\u0430\u0434\u043a\u0438
+main.menu.help.debugLog.desc = \u041f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0436\u0443\u0440\u043d\u0430\u043b \u043e\u0442\u043b\u0430\u0434\u043a\u0438 Openiocket
+main.menu.help.about = \u041e \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435
+main.menu.help.about.desc = \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e \u043f\u0440\u0430\u0432\u0430\u0445
+
+main.menu.debug = \u041e\u0442\u043b\u0430\u0434\u043a\u0430
+main.menu.debug.whatisthismenu = \u0427\u0442\u043e \u044d\u0442\u043e \u0437\u0430 \u043c\u0435\u043d\u044e?
+main.menu.debug.createtestrocket = \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0440\u0430\u043a\u0435\u0442\u0443
 
 ! database
 ! Translate here all material database
 !
 
+Material.CUSTOM = \u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439
+
 ! Material database
+Databases.materials.types.Bulk = \u041e\u0431\u044a\u0435\u043c\u043d\u044b\u0439
+Databases.materials.types.Line = \u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439
+Databases.materials.types.Surface = \u041f\u043e\u0432\u0435\u0440\u0445\u043d\u043e\u0441\u0442\u043d\u044b\u0439
 ! BULK_MATERIAL
-Databases.materials.Acrylic= Acrylic
-Databases.materials.Aluminum= Aluminum
-Databases.materials.Balsa= Balsa
-Databases.materials.Basswood= Basswood
-Databases.materials.Birch= Birch
-Databases.materials.Brass= Brass
-Databases.materials.Cardboard= Cardboard
-Databases.materials.Carbonfiber= Carbon fiber
-Databases.materials.Cork= Cork
-Databases.materials.DepronXPS= Depron (XPS)
-Databases.materials.Fiberglass= Fiberglass
-Databases.materials.Kraftphenolic= Kraft phenolic
-Databases.materials.Maple= Maple
-Databases.materials.Paperoffice= Paper (office)
-Databases.materials.Pine= Pine
-Databases.materials.Plywoodbirch= Plywood (birch)
-Databases.materials.PolycarbonateLexan= Polycarbonate (Lexan)
-Databases.materials.Polystyrene= Polystyrene
-Databases.materials.PVC= PVC
-Databases.materials.Spruce= Spruce
-Databases.materials.Steel= Steel
-Databases.materials.StyrofoamgenericEPS= Styrofoam (generic EPS)
-Databases.materials.StyrofoamBluefoamXPS= Styrofoam \"Blue foam\" (XPS)
-Databases.materials.Titanium= Titanium
-Databases.materials.Quantumtubing= Quantum tubing
-Databases.materials.BlueTube= Blue tube
+material.acrylic = \u0410\u043a\u0440\u0438\u043b
+material.aluminum = \u0410\u043b\u044e\u043c\u0438\u043d\u0438\u0439
+material.balsa = \u0411\u0430\u043b\u044c\u0441\u0430
+material.basswood = \u0410\u043c\u0435\u0440\u0438\u043a\u0430\u043d\u0441\u043a\u0430\u044f \u043b\u0438\u043f\u0430
+material.birch = \u0411\u0435\u0440\u0435\u0437\u0430
+material.brass = \u041b\u0430\u0442\u0443\u043d\u044c
+material.cardboard = \u041a\u0430\u0440\u0442\u043e\u043d
+material.carbon_fiber = \u0423\u0433\u043b\u0435\u0432\u043e\u043b\u043e\u043a\u043d\u043e
+material.cork = \u041f\u0440\u043e\u0431\u043a\u0430
+material.depron_xps = \u0414\u0435\u043f\u0440\u043e\u043d (XPS)
+material.fiberglass = \u0421\u0442\u0435\u043a\u043b\u043e\u0432\u043e\u043b\u043e\u043a\u043d\u043e
+material.kraft_phenolic = \u041f\u0440\u043e\u043f\u0438\u0442\u0430\u043d\u043d\u0430\u044f \u043a\u0440\u0430\u0444\u0442-\u0431\u0443\u043c\u0430\u0433\u0430
+material.maple = \u041a\u043b\u0451\u043d
+material.paper_office = \u0411\u0443\u043c\u0430\u0433\u0430 (\u043e\u0444\u0438\u0441\u043d\u0430\u044f)
+material.pine = \u0421\u043e\u0441\u043d\u0430
+material.plywood_birch = \u0424\u0430\u043d\u0435\u0440\u0430 (\u0431\u0435\u0440\u0435\u0437\u043e\u0432\u0430\u044f)
+material.polycarbonate_lexan = \u041f\u043e\u043b\u0438\u043a\u0430\u0440\u0431\u043e\u043d\u0430\u0442 (\u041b\u0435\u043a\u0441\u0430\u043d)
+material.polystyrene = \u041f\u043e\u043b\u0438\u0441\u0442\u0438\u0440\u043e\u043b
+material.pvc = \u041f\u0412\u0425
+material.spruce = \u0415\u043b\u044c
+material.steel = \u0421\u0442\u0430\u043b\u044c
+material.styrofoam_generic_eps = \u041f\u0435\u043d\u043e\u043f\u043b\u0430\u0441\u0442 (\u043e\u0431\u044b\u0447\u043d\u044b\u0439 EPS)
+material.styrofoam_blue_foam_xps = \u041f\u0435\u043d\u043e\u043f\u043b\u0430\u0441\u0442 "Blue foam" (XPS)
+material.titanium = \u0422\u0438\u0442\u0430\u043d
+material.quantum_tubing = Quantum tubing
+material.blue_tube = Blue tube
 !SURFACE_MATERIAL
-Databases.materials.Ripstopnylon= Ripstop nylon
-Databases.materials.Mylar= Mylar
-Databases.materials.Polyethylenethin= Polyethylene (thin)
-Databases.materials.Polyethyleneheavy= Polyethylene (heavy)
-Databases.materials.Silk= Silk
-Databases.materials.Paperoffice= Paper (office)
-Databases.materials.Cellophane= Cellophane
-Databases.materials.Crepepaper= Cr\u00eape paper
+material.ripstop_nylon = \u041d\u0435\u0439\u043b\u043e\u043d\u043e\u0432\u044b\u0439 \u0440\u0438\u043f\u0441\u0442\u043e\u043f
+material.mylar = \u041c\u0430\u0439\u043b\u0430\u0440
+material.polyethylene_thin = \u041f\u043e\u043b\u0438\u044d\u0442\u0438\u043b\u0435\u043d (\u0442\u043e\u043d\u043a\u0438\u0439)
+material.polyethylene_heavy = \u041f\u043e\u043b\u0438\u044d\u0442\u0438\u043b\u0435\u043d (\u043f\u043b\u043e\u0442\u043d\u044b\u0439)
+material.silk = \u0428\u0435\u043b\u043a
+material.paper_office = \u0411\u0443\u043c\u0430\u0433\u0430 (\u043e\u0444\u0438\u0441\u043d\u0430\u044f)
+material.cellophane = \u0426\u0435\u043b\u043b\u043e\u0444\u0430\u043d
+material.crepe_paper = Cr\u00eape paper
 ! LINE_MATERIAL
-Databases.materials.Threadheavy-duty= Thread (heavy-duty)
-Databases.materials.Elasticcordround2mm= Elastic cord (round 2mm, 1/16 in)
-Databases.materials.Elasticcordflat6mm= Elastic cord (flat  6mm, 1/4 in)
-Databases.materials.Elasticcordflat12mm= Elastic cord (flat 12mm, 1/2 in)
-Databases.materials.Elasticcordflat19mm= Elastic cord (flat 19mm, 3/4 in)
-Databases.materials.Elasticcordflat25mm= Elastic cord (flat 25mm, 1 in)
-Databases.materials.Braidednylon2mm= Braided nylon (2 mm, 1/16 in)
-Databases.materials.Braidednylon3mm= Braided nylon (3 mm, 1/8 in)
-Databases.materials.Tubularnylon11mm= Tubular nylon (11 mm, 7/16 in)
-Databases.materials.Tubularnylon14mm= Tubular nylon (14 mm, 9/16 in)
-Databases.materials.Tubularnylon25mm= Tubular nylon (25 mm, 1 in)
+material.thread_heavy_duty = \u0421\u0443\u0440\u043e\u0432\u0430\u044f \u043d\u0438\u0442\u044c
+material.elastic_cord_round_2_mm_1_16_in = \u042d\u043b\u0430\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0448\u043d\u0443\u0440 (\u043a\u0440\u0443\u0433\u043b\u044b\u0439 2mm, 1/16 in)
+material.elastic_cord_flat_6_mm_1_4_in = \u042d\u043b\u0430\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0448\u043d\u0443\u0440 (\u043f\u043b\u043e\u0441\u043a\u0438\u0439  6mm, 1/4 in)
+material.elastic_cord_flat_12_mm_1_2_in = \u042d\u043b\u0430\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0448\u043d\u0443\u0440 (\u043f\u043b\u043e\u0441\u043a\u0438\u0439 12mm, 1/2 in)
+material.elastic_cord_flat_19_mm_3_4_in = \u042d\u043b\u0430\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0448\u043d\u0443\u0440 (\u043f\u043b\u043e\u0441\u043a\u0438\u0439 19mm, 3/4 in)
+material.elastic_cord_flat_25_mm_1_in = \u042d\u043b\u0430\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0448\u043d\u0443\u0440 (\u043f\u043b\u043e\u0441\u043a\u0438\u0439 25mm, 1 in)
+material.braided_nylon_2_mm_1_16_in = \u041f\u043b\u0435\u0442\u0435\u043d\u044b\u0439 \u043d\u0435\u0439\u043b\u043e\u043d (2 mm, 1/16 in)
+material.braided_nylon_3_mm_1_8_in = \u041f\u043b\u0435\u0442\u0435\u043d\u044b\u0439 \u043d\u0435\u0439\u043b\u043e\u043d (3 mm, 1/8 in)
+material.tubular_nylon_11_mm_7_16_in = \u0422\u0440\u0443\u0431\u0447\u0430\u0442\u044b\u0439 \u043d\u0435\u0439\u043b\u043e\u043d (11 mm, 7/16 in)
+material.tubular_nylon_14_mm_9_16_in = \u0422\u0440\u0443\u0431\u0447\u0430\u0442\u044b\u0439 \u043d\u0435\u0439\u043b\u043e\u043d (14 mm, 9/16 in)
+material.tubular_nylon_25_mm_1_in = \u0422\u0440\u0443\u0431\u0447\u0430\u0442\u044b\u0439 \u043d\u0435\u0439\u043b\u043e\u043d (25 mm, 1 in)
 
 ! ExternalComponent
-ExternalComponent.Rough= Rough
-ExternalComponent.Unfinished= Unfinished
-ExternalComponent.Regularpaint= Regular paint
-ExternalComponent.Smoothpaint= Smooth paint
-ExternalComponent.Polished= Polished
+ExternalComponent.Rough = \u0427\u0435\u0440\u043d\u043e\u0432\u0430\u044f
+ExternalComponent.Unfinished = \u041d\u0435\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u0430\u044f
+ExternalComponent.Regularpaint = \u041e\u0431\u044b\u0447\u043d\u0430\u044f \u043e\u043a\u0440\u0430\u0441\u043a\u0430
+ExternalComponent.Smoothpaint = \u0413\u043b\u0430\u0434\u043a\u0430\u044f \u043e\u043a\u0440\u0430\u0441\u043a\u0430
+ExternalComponent.Polished = \u041f\u043e\u043b\u0438\u0440\u043e\u0432\u043a\u0430
 
 ! LineStyle
-LineStyle.Solid= Solid
-LineStyle.Dashed= Dashed
-LineStyle.Dotted= Dotted
-LineStyle.Dash-dotted= Dash-dotted
-LineStyle.Defaultstyle= Default style
+LineStyle.Solid = \u0421\u043f\u043b\u043e\u0448\u043d\u0430\u044f
+LineStyle.Dashed = \u0428\u0442\u0440\u0438\u0445\u043e\u0432\u0430\u044f
+LineStyle.Dotted = \u041f\u0443\u043d\u043a\u0442\u0438\u0440\u043d\u0430\u044f
+LineStyle.Dash-dotted = \u0428\u0442\u0440\u0438\u0445-\u043f\u0443\u043d\u043a\u0442\u0438\u0440\u043d\u0430\u044f
+LineStyle.Defaultstyle = \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e
 
 ! Shape
-Shape.Conical= Conical
-Shape.Conical.desc1= A conical nose cone has a profile of a triangle.
-Shape.Conical.desc2= A conical transition has straight sides.
-Shape.Ogive= Ogive
-Shape.Ogive.desc1= An ogive nose cone has a profile that is a segment of a circle.  The shape parameter value 1 produces a <b>tangent ogive</b>, which has a smooth transition to the body tube, values less than 1 produce <b>secant ogives</b>.
-"Shape.Ogive.desc2= An ogive transition has a profile that is a segment of a circle.      The shape parameter value 1 produces a <b>tangent ogive</b>, which has a smooth transition to the body tube at the aft end, values less than 1 produce <b>secant ogives</b>."
-Shape.Ellipsoid= Ellipsoid
-Shape.Ellipsoid.desc1= An ellipsoidal nose cone has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.
-"Shape.Ellipsoid.desc2= An ellipsoidal transition has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the transition is not clipped, then the profile is extended at the center by the corresponding radius.        "
-Shape.Powerseries= Power series
-Shape.Powerseries.desc1= A power series nose cone has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i> = 0.5 this is a <b>\u00BD-power</b> or <b>parabolic</b> nose cone, for <i>k</i> = 0.5 this is a <b>\u00BD-power</b> or <b>parabolic</b> nose cone, for <i>k</i> = 0.75 a <b>\u00BE-power</b>, and for <i>k</i> = 1 a <b>conical</b> nose cone.
-Shape.Powerseries.desc2= A power series transition has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i> = 0.75 a <b>\u00BE-power</b>, and for <i>k</i> = 1 <b>conical</b>.
-Shape.Parabolicseries= Parabolic series
-Shape.Parabolicseries.desc1= A parabolic series nose cone has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.
-Shape.Parabolicseries.desc2= A parabolic series transition has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.
-Shape.Haackseries= Haack series
-Shape.Haackseries.desc1= The Haack series nose cones are designed to minimize drag.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> nose cone, which minimizes drag for fixed length and diameter, while a value of 0.333 produces an <b>LV-Haack</b> nose cone, which minimizes drag for fixed length and volume.
-"Shape.Haackseries.desc2= The Haack series <i>nose cones</i> are designed to minimize drag.  These transition shapes are their equivalents, but do not necessarily produce optimal drag for transitions.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, while a value of 0.333 produces an <b>LV-Haack</b> shape.        "
+Shape.Conical = \u041a\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439
+Shape.Conical.desc1 = \u041a\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0433\u043e\u043b\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044c \u043e\u0431\u043b\u0430\u0434\u0430\u0435\u0442 \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u044b\u043c \u043f\u0440\u043e\u0444\u0438\u043b\u0435\u043c.
+Shape.Conical.desc2 = \u0423 \u043a\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043f\u0440\u044f\u043c\u044b\u0435 \u0441\u0442\u043e\u0440\u043e\u043d\u044b.
+Shape.Ogive = \u0421\u0442\u0440\u0435\u043b\u043e\u0432\u0438\u0434\u043d\u044b\u0439
+Shape.Ogive.desc1 = \u0421\u0442\u0440\u0435\u043b\u043e\u0432\u0438\u0434\u043d\u044b\u0439 \u0433\u043e\u043b\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0434\u0443\u0433\u0438 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438. \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0444\u043e\u0440\u043c\u044b, \u0440\u0430\u0432\u043d\u044b\u0439 1, \u0434\u0430\u0435\u0442 <b>\u0432\u044b\u043f\u0443\u043a\u043b\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c</b>, \u043f\u043b\u0430\u0432\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u0432 \u043a\u043e\u0440\u043f\u0443\u0441\u043d\u0443\u044e \u0442\u0440\u0443\u0431\u0443, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440, \u043c\u0435\u043d\u044c\u0448\u0438\u0439 1, \u0434\u0430\u0435\u0442 <b>\u0443\u043f\u043b\u043e\u0449\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c</b>.
+Shape.Ogive.desc2 = \u0421\u0442\u0440\u0435\u043b\u043e\u0432\u0438\u0434\u043d\u044b\u0439 \u0433\u043e\u043b\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u0432\u0440\u0430\u0449\u0435\u043d\u0438\u044f \u0434\u0443\u0433\u0438 \u043e\u043a\u0440\u0443\u0436\u043d\u043e\u0441\u0442\u0438. \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0444\u043e\u0440\u043c\u044b, \u0440\u0430\u0432\u043d\u044b\u0439 1, \u0434\u0430\u0435\u0442 <b>\u0432\u044b\u043f\u0443\u043a\u043b\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c</b>, \u043f\u043b\u0430\u0432\u043d\u043e \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u0432 \u043a\u043e\u0440\u043f\u0443\u0441\u043d\u0443\u044e \u0442\u0440\u0443\u0431\u0443, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440, \u043c\u0435\u043d\u044c\u0448\u0438\u0439 1, \u0434\u0430\u0435\u0442 <b>\u0443\u043f\u043b\u043e\u0449\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u043e\u0444\u0438\u043b\u044c</b>.
+Shape.Ellipsoid = \u042d\u043b\u043b\u0438\u043f\u0441\u043e\u0438\u0434
+Shape.Ellipsoid.desc1 = An ellipsoidal nose cone has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.
+Shape.Ellipsoid.desc2 = An ellipsoidal transition has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the transition is not clipped, then the profile is extended at the center by the corresponding radius.
+Shape.Powerseries = \u0421\u0442\u0435\u043f\u0435\u043d\u043d\u043e\u0439
+Shape.Powerseries.desc1 = A power series nose cone has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i>
+Shape.Powerseries.desc2 = A power series transition has a profile of <i>Radius</i>&nbsp;&times;&nbsp;(<i>x</i>&nbsp;/&nbsp;<i>Length</i>)<sup><i>k</i></sup> where <i>k</i> is the shape parameter.  For <i>k</i>
+Shape.Parabolicseries = \u041f\u0430\u0440\u0430\u0431\u043e\u043b\u0438\u0447\u0435\u0441\u043a\u0438\u0439
+Shape.Parabolicseries.desc1 = A parabolic series nose cone has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.
+Shape.Parabolicseries.desc2 = A parabolic series transition has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.
+Shape.Haackseries = \u0425\u0430\u0430\u043a\u0430
+Shape.Haackseries.desc1 = The Haack series nose cones are designed to minimize drag.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> nose cone, which minimizes drag for fixed length and diameter, while a value of 0.333 produces an <b>LV-Haack</b> nose cone, which minimizes drag for fixed length and volume.
+Shape.Haackseries.desc2 = The Haack series <i>nose cones</i> are designed to minimize drag.  These transition shapes are their equivalents, but do not necessarily produce optimal drag for transitions.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, while a value of 0.333 produces an <b>LV-Haack</b> shape.
 
 
 ! RocketComponent
-RocketComponent.Position.TOP= Top of the parent component
-RocketComponent.Position.MIDDLE= Middle of the parent component
-RocketComponent.Position.BOTTOM= Bottom of the parent component
-RocketComponent.Position.AFTER= After the parent component
-RocketComponent.Position.ABSOLUTE= Tip of the nose cone
+RocketComponent.Position.TOP = \u0412\u0435\u0440\u0445\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430
+RocketComponent.Position.MIDDLE = \u0421\u0435\u0440\u0435\u0434\u0438\u043d\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430
+RocketComponent.Position.BOTTOM = \u041d\u0438\u0437\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430
+RocketComponent.Position.AFTER = \u041a\u043e\u043d\u0446\u0430 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430
+RocketComponent.Position.ABSOLUTE = \u041a\u043e\u043d\u0447\u0438\u043a\u0430 \u0433\u043e\u043b\u043e\u0432\u043d\u043e\u0433\u043e \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044f
 
 ! LaunchLug
-LaunchLug.Launchlug= Launch lug
+LaunchLug.Launchlug = \u041d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0435 \u043a\u043e\u043b\u044c\u0446\u043e
 ! NoseCone
-NoseCone.NoseCone= Nose cone
+NoseCone.NoseCone = \u0413\u043e\u043b\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044c
 ! Transition
-Transition.Transition= Transition
+Transition.Transition = \u041f\u0435\u0440\u0435\u0445\u043e\u0434
 !Stage
-Stage.Stage= Stage
+Stage.Stage = \u0421\u0442\u0443\u043f\u0435\u043d\u044c
+
+Stage.SeparationEvent.UPPER_IGNITION = \u0412\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+Stage.SeparationEvent.IGNITION = \u0412\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+Stage.SeparationEvent.BURNOUT = \u0412\u044b\u0433\u043e\u0440\u0430\u043d\u0438\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+Stage.SeparationEvent.EJECTION = \u0412\u044b\u0448\u0438\u0431\u043d\u043e\u0439 \u0437\u0430\u0440\u044f\u0434 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+Stage.SeparationEvent.LAUNCH = \u041f\u0443\u0441\u043a
+Stage.SeparationEvent.NEVER = \u041d\u0438\u043a\u043e\u0433\u0434\u0430
+
 ! BodyTube
-BodyTube.BodyTube= Body tube
+BodyTube.BodyTube = \u041a\u043e\u0440\u043f\u0443\u0441\u043d\u0430\u044f \u0442\u0440\u0443\u0431\u0430
 ! TubeCoupler
-TubeCoupler.TubeCoupler= Tube coupler
+TubeCoupler.TubeCoupler = \u041c\u0443\u0444\u0442\u0430
 !InnerTube
-InnerTube.InnerTube= Inner Tube
+InnerTube.InnerTube = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u0442\u0440\u0443\u0431\u0430
 ! TrapezoidFinSet
-TrapezoidFinSet.TrapezoidFinSet= Trapezoidal fin set
+TrapezoidFinSet.TrapezoidFinSet = \u0422\u0440\u0430\u043f\u0435\u0446\u0438\u0435\u0434\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435
 ! FreeformFinSet
-FreeformFinSet.FreeformFinSet= Freeform fin set
+FreeformFinSet.FreeformFinSet = \u041e\u043f\u0435\u0440\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b
 !MassComponent
-MassComponent.MassComponent= Mass component
+MassComponent.MassComponent = \u0412\u0435\u0441\u043e\u0432\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
 ! Parachute
-Parachute.Parachute= Parachute
+Parachute.Parachute = \u041f\u0430\u0440\u0430\u0448\u044e\u0442
 ! ShockCord
-ShockCord.ShockCord= Shock cord
+ShockCord.ShockCord = \u0421\u0442\u0440\u043e\u043f\u0430
 ! Bulkhead
-Bulkhead.Bulkhead= Bulkhead
+Bulkhead.Bulkhead = \u041f\u0435\u0440\u0435\u0431\u043e\u0440\u043a\u0430
+! CenteringRing
+CenteringRing.CenteringRing = \u0426\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u044e\u0449\u0435\u0435 \u043a\u043e\u043b\u044c\u0446\u043e
+! EngineBlock
+EngineBlock.EngineBlock = \u0423\u043f\u043e\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+! Streamer
+Streamer.Streamer = \u0422\u043e\u0440\u043c\u043e\u0437\u043d\u0430\u044f \u043b\u0435\u043d\u0442\u0430
+! Sleeve
+Sleeve.Sleeve = \u0412\u0442\u0443\u043b\u043a\u0430
+
 
 !Rocket
-Rocket.motorCount.Nomotor= [No motors]
-Rocket.compname.Rocket= Rocket
+Rocket.motorCount.Nomotor = [\u0411\u0435\u0437 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439]
+Rocket.compname.Rocket = \u0420\u0430\u043a\u0435\u0442\u0430
 
 !MotorMount
-MotorMount.IgnitionEvent.AUTOMATIC= Automatic (launch or ejection charge)
-MotorMount.IgnitionEvent.LAUNCH= Launch
-MotorMount.IgnitionEvent.EJECTION_CHARGE= First ejection charge of previous stage
-MotorMount.IgnitionEvent.BURNOUT= First burnout of previous stage
-MotorMount.IgnitionEvent.NEVER= Never
-
-!ComponentIcons 
-ComponentIcons.Nosecone= Nose cone
-ComponentIcons.Bodytube= Body tube
-ComponentIcons.Transition= Transition
-ComponentIcons.Trapezoidalfinset= Trapezoidal fin set
-ComponentIcons.Ellipticalfinset= Elliptical fin set
-ComponentIcons.Freeformfinset= Freeform fin set
-ComponentIcons.Launchlug= Launch lug
-ComponentIcons.Innertube= Inner tube
-ComponentIcons.Tubecoupler= Tube coupler
-ComponentIcons.Centeringring= Centering ring
-ComponentIcons.Bulkhead= Bulk head
-ComponentIcons.Engineblock=\u0423\u043F\u043E\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043B\u044F
-ComponentIcons.Parachute= Parachute
-ComponentIcons.Streamer= Streamer
-ComponentIcons.Shockcord= Shock cord
-ComponentIcons.Masscomponent= Mass component
-ComponentIcons.disabled= (disabled)
+MotorMount.IgnitionEvent.AUTOMATIC = \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 (\u0437\u0430\u043f\u0443\u0441\u043a \u0438\u043b\u0438 \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0443\u043f\u0435\u043d\u0438)
+MotorMount.IgnitionEvent.LAUNCH = \u0417\u0430\u043f\u0443\u0441\u043a
+MotorMount.IgnitionEvent.EJECTION_CHARGE = \u041f\u0435\u0440\u0432\u044b\u0439 \u0432\u044b\u0448\u0438\u0431\u043d\u043e\u0439 \u0437\u0430\u0440\u044f\u0434 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+MotorMount.IgnitionEvent.BURNOUT = \u0412\u044b\u0433\u043e\u0440\u0430\u043d\u0438\u0435 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+MotorMount.IgnitionEvent.NEVER = \u041d\u0438\u043a\u043e\u0433\u0434\u0430
+
+!ComponentIcons
+ComponentIcons.Nosecone = \u0413\u043e\u043b\u043e\u0432\u043d\u043e\u0439 \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044c
+ComponentIcons.Bodytube = \u041a\u043e\u0440\u043f\u0443\u0441\u043d\u0430\u044f \u0442\u0440\u0443\u0431\u0430
+ComponentIcons.Transition = \u041f\u0435\u0440\u0435\u0445\u043e\u0434
+ComponentIcons.Trapezoidalfinset = \u0422\u0440\u0430\u043f\u0435\u0446\u0438\u0435\u0434\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435
+ComponentIcons.Ellipticalfinset = \u042d\u043b\u043b\u0438\u043f\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435
+ComponentIcons.Freeformfinset = \u041e\u043f\u0435\u0440\u0435\u043d\u0438\u0435 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b
+ComponentIcons.Launchlug = \u041d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0435 \u043a\u043e\u043b\u044c\u0446\u043e
+ComponentIcons.Innertube = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u0442\u0440\u0443\u0431\u0430
+ComponentIcons.Tubecoupler = \u041c\u0443\u0444\u0442\u0430
+ComponentIcons.Centeringring = \u0426\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u044e\u0449\u0435\u0435 \u043a\u043e\u043b\u044c\u0443\u043e
+ComponentIcons.Bulkhead = \u041f\u0435\u0440\u0435\u0431\u043e\u0440\u043a\u0430
+ComponentIcons.Engineblock = \u0423\u043f\u043e\u0440 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+ComponentIcons.Parachute = \u041f\u0430\u0440\u0430\u0448\u044e\u0442
+ComponentIcons.Streamer = \u0422\u043e\u0440\u043c\u043e\u0437\u043d\u0430\u044f \u043b\u0435\u043d\u0442\u0430
+ComponentIcons.Shockcord = \u0421\u0442\u0440\u043e\u043f\u0430
+ComponentIcons.Masscomponent = \u0412\u0435\u0441\u043e\u0432\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+ComponentIcons.disabled = (disabled)
 
 ! StageAction
-StageAction.Stage= Stage
+StageAction.Stage = \u0421\u0442\u0443\u043f\u0435\u043d\u044c
 
 ! RecoveryDevice
-RecoveryDevice.DeployEvent.LAUNCH= Launch (plus NN seconds)
-RecoveryDevice.DeployEvent.EJECTION= First ejection charge of this stage
-RecoveryDevice.DeployEvent.APOGEE= Apogee
-RecoveryDevice.DeployEvent.ALTITUDE= Specific altitude during descent
-RecoveryDevice.DeployEvent.NEVER= Never
+RecoveryDevice.DeployEvent.LAUNCH = \u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 + NN \u0441\u0435\u043a\u0443\u043d\u0434
+RecoveryDevice.DeployEvent.EJECTION = \u041f\u0435\u0440\u0432\u044b\u0439 \u0432\u044b\u0448\u0438\u0431\u043d\u043e\u0439 \u0437\u0430\u0440\u044f\u0434 \u044d\u0442\u043e\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+RecoveryDevice.DeployEvent.APOGEE = \u0412 \u0430\u043f\u043e\u0433\u0435\u0435
+RecoveryDevice.DeployEvent.ALTITUDE = \u041d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0439 \u0432\u044b\u0441\u043e\u0442\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043f\u0443\u0441\u043a\u0430
+RecoveryDevice.DeployEvent.CURRENT_STAGE_SEPARATION = \u041e\u0442\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION = \u041e\u0442\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043d\u0438\u0436\u043d\u0435\u0439 \u0441\u0442\u0443\u043f\u0435\u043d\u0438
+RecoveryDevice.DeployEvent.NEVER = \u041d\u0438\u043a\u043e\u0433\u0434\u0430
 
 ! FlightEvent
-FlightEvent.Type.LAUNCH= Launch
-FlightEvent.Type.IGNITION= Motor ignition
-FlightEvent.Type.LIFTOFF= Lift-off
-FlightEvent.Type.LAUNCHROD= Launch rod clearance
-FlightEvent.Type.BURNOUT= Motor burnout
-FlightEvent.Type.EJECTION_CHARGE= Ejection charge
-FlightEvent.Type.STAGE_SEPARATION= Stage separation
-FlightEvent.Type.APOGEE= Apogee
-FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT= Recovery device deployment
-FlightEvent.Type.GROUND_HIT= Ground hit
-FlightEvent.Type.SIMULATION_END= Simulation end
-FlightEvent.Type.ALTITUDE= Altitude change
+FlightEvent.Type.LAUNCH = \u041f\u0443\u0441\u043a
+FlightEvent.Type.IGNITION = \u0412\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+FlightEvent.Type.LIFTOFF = \u041e\u0442\u0440\u044b\u0432
+FlightEvent.Type.LAUNCHROD = \u0421\u0445\u043e\u0434 \u0441 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0439
+FlightEvent.Type.BURNOUT = \u0412\u044b\u0433\u043e\u0440\u0430\u043d\u0438\u0435 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+FlightEvent.Type.EJECTION_CHARGE = \u0412\u044b\u0448\u0438\u0431\u043d\u043e\u0439 \u0437\u0430\u0440\u044f\u0434
+FlightEvent.Type.STAGE_SEPARATION = \u0420\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0441\u0442\u0443\u043f\u0435\u043d\u0435\u0439
+FlightEvent.Type.APOGEE = \u0410\u043f\u043e\u0433\u0435\u0439
+FlightEvent.Type.RECOVERY_DEVICE_DEPLOYMENT = \u0421\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u043f\u0430\u0441\u0435\u043d\u0438\u044f
+FlightEvent.Type.GROUND_HIT = \u041f\u0440\u0438\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u0435
+FlightEvent.Type.SIMULATION_END = \u041a\u043e\u043d\u0435\u0446 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+FlightEvent.Type.ALTITUDE = \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432\u044b\u0441\u043e\u0442\u044b
 
 ! ThrustCurveMotorColumns
-TCurveMotorCol.MANUFACTURER= Manufacturer
-TCurveMotorCol.DESIGNATION= Designation
-TCurveMotorCol.TYPE= Type
-TCurveMotorCol.DIAMETER= Diameter
-TCurveMotorCol.LENGTH= Length
+TCurveMotorCol.MANUFACTURER = \u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c
+TCurveMotorCol.DESIGNATION = \u041e\u0431\u043e\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435
+TCurveMotorCol.TYPE = \u0422\u0438\u043f
+TCurveMotorCol.DIAMETER = \u0414\u0438\u0430\u043c\u0435\u0442\u0440
+TCurveMotorCol.LENGTH = \u0414\u043b\u0438\u043d\u0430
+
+TCurveMotor.ttip.diameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440:
+TCurveMotor.ttip.length = \u0414\u043b\u0438\u043d\u0430:
+TCurveMotor.ttip.maxThrust = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u044f\u0433\u0430:
+TCurveMotor.ttip.avgThrust = \u0421\u0440\u0435\u0434\u043d\u044f\u044f \u0442\u044f\u0433\u0430:
+TCurveMotor.ttip.burnTime = \u0412\u0440\u0435\u043c\u044f \u0433\u043e\u0440\u0435\u043d\u0438\u044f:
+TCurveMotor.ttip.totalImpulse = \u041e\u0431\u0449\u0438\u0439 \u0438\u043c\u043f\u0443\u043b\u044c\u0441:
+TCurveMotor.ttip.launchMass = \u0421\u0442\u0430\u0440\u0442\u043e\u0432\u0430\u044f \u043c\u0430\u0441\u0441\u0430:
+TCurveMotor.ttip.emptyMass = \u041c\u0430\u0441\u0441\u0430 \u0431\u0435\u0437 \u0442\u043e\u043f\u043b\u0438\u0432\u0430:
 
 ! RocketInfo
-RocketInfo.lengthLine.Length= Length
-RocketInfo.lengthLine.maxdiameter= , max. diameter
-RocketInfo.massText1= Mass with motors 
-RocketInfo.massText2= Mass with no motors
-RocketInfo.at= at M
-RocketInfo.cgText= CG:
-RocketInfo.cpText= CP:
-RocketInfo.stabText= Stability:
-RocketInfo.Warning= Warning:
-RocketInfo.Calculating= Calculating...
-RocketInfo.Apogee= Apogee:
-RocketInfo.Maxvelocity= Max. velocity:
-RocketInfo.Maxacceleration= Max. acceleration:
-RocketInfo.apogeeValue= N/A
-RocketInfo.Mach= (Mach
-RocketInfo.velocityValue= N/A
-RocketInfo.accelerationValue= N/A
+RocketInfo.lengthLine.Length = \u0414\u043b\u0438\u043d\u0430
+RocketInfo.lengthLine.maxdiameter = , \u043c\u0430\u043a\u0441. \u0434\u0438\u0430\u043c\u0435\u0442\u0440
+RocketInfo.massText1 = \u041c\u0430\u0441\u0441\u0430 \u0441 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f\u043c\u0438
+RocketInfo.massText2 = \u041c\u0430\u0441\u0441\u0430 \u0431\u0435\u0437 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435\u0439
+RocketInfo.at = \u041f\u0440\u0438 M
+RocketInfo.cgText = \u0426\u0422:
+RocketInfo.cpText = \u0426\u0414:
+RocketInfo.stabText = \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c:
+RocketInfo.Warning = \u041f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0435:
+RocketInfo.Calculating = \u0420\u0430\u0441\u0447\u0435\u0442...
+RocketInfo.Apogee = \u0410\u043f\u043e\u0433\u0435\u0439:
+RocketInfo.Maxvelocity = \u041c\u0430\u043a\u0441. \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c:
+RocketInfo.Maxacceleration = \u041c\u0430\u043a\u0441. \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435:
+RocketInfo.apogeeValue = \u041d/\u0414
+RocketInfo.Mach = (\u0427\u0438\u0441\u043b\u043e \u041c\u0430\u0445\u0430
+RocketInfo.velocityValue = \u041d/\u0414
+RocketInfo.accelerationValue = \u041d/\u0414
 
 ! FinSet
-FinSet.CrossSection.SQUARE= Square
-FinSet.CrossSection.ROUNDED= Rounded
-FinSet.CrossSection.AIRFOIL= Airfoil
-FinSet.TabRelativePosition.FRONT= Root chord leading edge
-FinSet.TabRelativePosition.CENTER= Root chord midpoint
-FinSet.TabRelativePosition.END= Root chord trailing edge
+FinSet.CrossSection.SQUARE = \u041f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u044b\u0439
+FinSet.CrossSection.ROUNDED = \u0421\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u043d\u044b\u0439
+FinSet.CrossSection.AIRFOIL = \u0410\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u0439
+FinSet.TabRelativePosition.FRONT = \u041d\u0430\u0447\u0430\u043b\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f
+FinSet.TabRelativePosition.CENTER = \u0421\u0435\u0440\u0435\u0434\u0438\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f
+FinSet.TabRelativePosition.END = \u041a\u043e\u043d\u0435\u0446 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f
 
 ! FlightDataType
-FlightDataType.TYPE_TIME= Time
-= Altitude
-FlightDataType.TYPE_VELOCITY_Z= Vertical velocity
-FlightDataType.TYPE_ACCELERATION_Z= Vertical acceleration
-FlightDataType.TYPE_VELOCITY_TOTAL= Total velocity
-FlightDataType.TYPE_ACCELERATION_TOTAL= Total acceleration
-FlightDataType.TYPE_POSITION_X= Position upwind
-FlightDataType.TYPE_POSITION_Y= Position parallel to wind
-FlightDataType.TYPE_POSITION_XY= Lateral distance
-FlightDataType.TYPE_POSITION_DIRECTION= Lateral direction
-FlightDataType.TYPE_VELOCITY_XY= Lateral velocity
-FlightDataType.TYPE_ACCELERATION_XY= Lateral acceleration
-FlightDataType.TYPE_AOA= \u0423\u0433\u043E\u043B \u0430\u0442\u0430\u043A\u0438
-FlightDataType.TYPE_ROLL_RATE= Roll rate
-FlightDataType.TYPE_PITCH_RATE=\u0421\u043A\u043E\u0440\u043E\u0441\u0442\u044C \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F \u0443\u0433\u043B\u0430 \u0434\u0438\u0444\u0444\u0435\u0440\u0435\u043D\u0442\u0430
-FlightDataType.TYPE_YAW_RATE= Yaw rate
-FlightDataType.TYPE_MASS= \u041C\u0430\u0441\u0441\u0430
-FlightDataType.TYPE_LONGITUDINAL_INERTIA=\u041F\u0440\u043E\u0434\u043E\u043B\u044C\u043D\u044B\u0439 \u043C\u043E\u043C\u0435\u043D\u0442 \u0438\u043D\u0435\u0440\u0446\u0438\u0438
-FlightDataType.TYPE_ROTATIONAL_INERTIA= \u041A\u0440\u0443\u0442\u044F\u0449\u0438\u0439 \u043C\u043E\u043C\u0435\u043D\u0442 \u0438\u043D\u0435\u0440\u0446\u0438\u0438
-FlightDataType.TYPE_CP_LOCATION= CP location
-FlightDataType.TYPE_CG_LOCATION= CG location
-FlightDataType.TYPE_STABILITY= Stability margin calibers
-FlightDataType.TYPE_MACH_NUMBER= Mach number
-FlightDataType.TYPE_REYNOLDS_NUMBER= Reynolds number
-FlightDataType.TYPE_THRUST_FORCE= Thrust
-FlightDataType.TYPE_DRAG_FORCE= Drag force
-FlightDataType.TYPE_DRAG_COEFF= Drag coefficient
-FlightDataType.TYPE_AXIAL_DRAG_COEFF= Axial drag coefficient
-FlightDataType.TYPE_FRICTION_DRAG_COEFF= Friction drag coefficient
-FlightDataType.TYPE_PRESSURE_DRAG_COEFF= Pressure drag coefficient
-FlightDataType.TYPE_BASE_DRAG_COEFF= Base drag coefficient
-FlightDataType.TYPE_NORMAL_FORCE_COEFF= Normal force coefficient
-FlightDataType.TYPE_PITCH_MOMENT_COEFF= Pitch moment coefficient
-FlightDataType.TYPE_YAW_MOMENT_COEFF= Yaw moment coefficient
-FlightDataType.TYPE_SIDE_FORCE_COEFF= Side force coefficient
-FlightDataType.TYPE_ROLL_MOMENT_COEFF= Roll moment coefficient
-FlightDataType.TYPE_ROLL_FORCING_COEFF= Roll forcing coefficient
-FlightDataType.TYPE_ROLL_DAMPING_COEFF= Roll damping coefficient
-FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF= Pitch damping coefficient
-FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF= Yaw damping coefficient
-FlightDataType.TYPE_REFERENCE_LENGTH= Reference lenght
-FlightDataType.TYPE_REFERENCE_AREA= Reference area
-FlightDataType.TYPE_ORIENTATION_THETA= Vertical orientation (zenith)
-FlightDataType.TYPE_ORIENTATION_PHI= Lateral orientation (azimuth)
-FlightDataType.TYPE_WIND_VELOCITY= Wind velocity
-FlightDataType.TYPE_AIR_TEMPERATURE= Air temperature
-FlightDataType.TYPE_AIR_PRESSURE= Air pressure
-FlightDataType.TYPE_SPEED_OF_SOUND= Speed of sound
-FlightDataType.TYPE_TIME_STEP= Simulation time step
-FlightDataType.TYPE_COMPUTATION_TIME= Computation time
-FlightDataType.TYPE_LATITUDE= Latitude
-FlightDataType.TYPE_LONGITUDE= Longitude
-FlightDataType.TYPE_CORIOLIS_ACCELERATION= Coriolis acceleration
+FlightDataType.TYPE_TIME = \u0412\u0440\u0435\u043c\u044f
+FlightDataType.TYPE_ALTITUDE = \u0412\u044b\u0441\u043e\u0442\u0430
+FlightDataType.TYPE_VELOCITY_Z = \u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
+FlightDataType.TYPE_ACCELERATION_Z = \u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435
+FlightDataType.TYPE_VELOCITY_TOTAL = \u041e\u0431\u0449\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
+FlightDataType.TYPE_ACCELERATION_TOTAL = \u041e\u0431\u0449\u0435\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435
+FlightDataType.TYPE_POSITION_X = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0442\u0438\u0432 \u0432\u0435\u0442\u0440\u0430
+FlightDataType.TYPE_POSITION_Y = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e \u0432\u0435\u0442\u0440\u0443
+FlightDataType.TYPE_POSITION_XY = \u0411\u043e\u043a\u043e\u0432\u0430\u044f \u0434\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u044f
+FlightDataType.TYPE_POSITION_DIRECTION = \u0411\u043e\u043a\u043e\u0432\u043e\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435
+FlightDataType.TYPE_VELOCITY_XY = \u0411\u043e\u043a\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
+FlightDataType.TYPE_ACCELERATION_XY = \u0411\u043e\u043a\u043e\u0432\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435
+FlightDataType.TYPE_AOA = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438
+FlightDataType.TYPE_ROLL_RATE = \u0423\u0433\u043b\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043a\u0440\u0435\u043d\u0430
+FlightDataType.TYPE_PITCH_RATE = \u0423\u0433\u043b\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0442\u0430\u043d\u0433\u0430\u0436\u0430
+FlightDataType.TYPE_YAW_RATE = \u0423\u0433\u043b\u043e\u0432\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0440\u044b\u0441\u043a\u0430\u043d\u044c\u044f
+FlightDataType.TYPE_MASS = \u041c\u0430\u0441\u0441\u0430
+FlightDataType.TYPE_LONGITUDINAL_INERTIA = \u041f\u0440\u043e\u0434\u043e\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u043d\u0435\u0440\u0446\u0438\u0438
+FlightDataType.TYPE_ROTATIONAL_INERTIA = \u041a\u0440\u0443\u0442\u044f\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0438\u043d\u0435\u0440\u0446\u0438\u0438
+FlightDataType.TYPE_CP_LOCATION = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0426\u0414
+FlightDataType.TYPE_CG_LOCATION = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0426\u0422
+FlightDataType.TYPE_STABILITY = \u0417\u0430\u043f\u0430\u0441 \u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 \u0432 \u043a\u0430\u043b\u0438\u0431\u0440\u0430\u0445
+FlightDataType.TYPE_MACH_NUMBER = \u0427\u0438\u0441\u043b\u043e \u041c\u0430\u0445\u0430
+FlightDataType.TYPE_REYNOLDS_NUMBER = \u0427\u0438\u0441\u043b\u043e \u0420\u0435\u0439\u043d\u043e\u043b\u044c\u0434\u0441\u0430
+FlightDataType.TYPE_THRUST_FORCE = \u0422\u044f\u0433\u0430
+FlightDataType.TYPE_DRAG_FORCE = \u0421\u0438\u043b\u0430 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+FlightDataType.TYPE_DRAG_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+FlightDataType.TYPE_AXIAL_DRAG_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043e\u0441\u0435\u0432\u043e\u0433\u043e \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+FlightDataType.TYPE_FRICTION_DRAG_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+FlightDataType.TYPE_PRESSURE_DRAG_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0434\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+FlightDataType.TYPE_BASE_DRAG_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+FlightDataType.TYPE_NORMAL_FORCE_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043d\u043e\u0440\u043c\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u044f\u0433\u0438
+FlightDataType.TYPE_PITCH_MOMENT_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0442\u0430\u043d\u0433\u0430\u0436\u0430
+FlightDataType.TYPE_YAW_MOMENT_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u0440\u044b\u0441\u043a\u0430\u043d\u044c\u044f
+FlightDataType.TYPE_SIDE_FORCE_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0431\u043e\u043a\u043e\u0432\u043e\u0439 \u0442\u044f\u0433\u0438
+FlightDataType.TYPE_ROLL_MOMENT_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 \u043a\u0440\u0435\u043d\u0430
+FlightDataType.TYPE_ROLL_FORCING_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0443\u0441\u0438\u043b\u0435\u043d\u0438\u044f \u043a\u0440\u0435\u043d\u0430
+FlightDataType.TYPE_ROLL_DAMPING_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0437\u0430\u0442\u0443\u0445\u0430\u043d\u0438\u044f \u043a\u0440\u0435\u043d\u0430
+FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0437\u0430\u0442\u0443\u0445\u0430\u043d\u0438\u044f \u0442\u0430\u043d\u0433\u0430\u0436\u0430
+FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0437\u0430\u0442\u0443\u0445\u0430\u043d\u0438\u044f \u0440\u044b\u0441\u043a\u0430\u043d\u044c\u044f
+FlightDataType.TYPE_REFERENCE_LENGTH = \u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u043c\u0438\u0434\u0435\u043b\u044f
+FlightDataType.TYPE_REFERENCE_AREA = \u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u043d\u0430\u044f \u043f\u043b\u043e\u0449\u0430\u0434\u044c
+FlightDataType.TYPE_ORIENTATION_THETA = \u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u0430\u044f \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u044f (\u0437\u0435\u043d\u0438\u0442)
+FlightDataType.TYPE_ORIENTATION_PHI = \u041f\u0440\u043e\u0434\u043e\u043b\u044c\u043d\u0430\u044f \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u044f (\u0430\u0437\u0438\u043c\u0443\u0442)
+FlightDataType.TYPE_WIND_VELOCITY = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0432\u0435\u0442\u0440\u0430
+FlightDataType.TYPE_AIR_TEMPERATURE = \u0422\u0435\u043c\u043f\u0435\u0440\u0430\u0442\u0443\u0440\u0430 \u0432\u043e\u0437\u0434\u0443\u0445\u0430
+FlightDataType.TYPE_AIR_PRESSURE = \u0414\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432\u043e\u0437\u0434\u0443\u0445\u0430
+FlightDataType.TYPE_SPEED_OF_SOUND = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0437\u0432\u0443\u043a\u0430
+FlightDataType.TYPE_TIME_STEP = \u0412\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0448\u0430\u0433 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+FlightDataType.TYPE_COMPUTATION_TIME = \u0412\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+FlightDataType.TYPE_LATITUDE = \u0428\u0438\u0440\u043e\u0442\u0430
+FlightDataType.TYPE_LONGITUDE = \u0414\u043e\u043b\u0433\u043e\u0442\u0430
+FlightDataType.TYPE_CORIOLIS_ACCELERATION = \u041a\u043e\u0440\u0438\u043e\u043b\u0438\u0441\u043e\u0432\u043e \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435
+FlightDataType.TYPE_GRAVITY = \u0413\u0440\u0430\u0432\u0438\u0442\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435
 
 ! PlotConfiguration
-PlotConfiguration.Verticalmotion= Vertical motion vs. time
-PlotConfiguration.Totalmotion= Total motion vs. time
-PlotConfiguration.Flightside= Flight side profile
-PlotConfiguration.Stability= Stability vs. time
-PlotConfiguration.Dragcoef= Drag coefficients vs. Mach number
-PlotConfiguration.Rollcharacteristics= Roll characteristics
-PlotConfiguration.Angleofattack= Angle of attack and orientation vs. time
-PlotConfiguration.Simulationtime= Simulation time step and computation time
+PlotConfiguration.Verticalmotion = \u0412\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 / \u0412\u0440\u0435\u043c\u044f
+PlotConfiguration.Totalmotion = \u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 / \u0412\u0440\u0435\u043c\u044f
+PlotConfiguration.Flightside = \u041f\u0440\u043e\u0444\u0438\u043b\u044c \u043f\u043e\u043b\u0435\u0442\u0430
+PlotConfiguration.Stability = \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c / \u0412\u0440\u0435\u043c\u044f
+PlotConfiguration.Dragcoef = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u044b \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f / \u0427\u0438\u0441\u043b\u043e \u041c\u0430\u0445\u0430
+PlotConfiguration.Rollcharacteristics = \u0425\u0430\u0440\u0430\u043a\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043a\u0438 \u043a\u0440\u0435\u043d\u0430
+PlotConfiguration.Angleofattack = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438 \u0438 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 / \u0412\u0440\u0435\u043c\u044f
+PlotConfiguration.Simulationtime = \u0412\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0448\u0430\u0433 \u0438 \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u0447\u0435\u0442\u0430
 
 ! Warning
-Warning.LargeAOA.str1= Large angle of attack encountered.
-Warning.LargeAOA.str2= Large angle of attack encountered (
-Warning.DISCONTINUITY= Discontinuity in rocket body diameter.
-Warning.THICK_FIN= Thick fins may not be modeled accurately.
-Warning.JAGGED_EDGED_FIN= Jagged-edged fin predictions may be inaccurate.
-Warning.LISTENERS_AFFECTED= Listeners modified the flight simulation
-Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING= Recovery device opened while motor still burning.
-Warning.FILE_INVALID_PARAMETER= Invalid parameter encountered, ignoring.
+Warning.LargeAOA.str1 = \u0411\u043e\u043b\u044c\u0448\u043e\u0439 \u0443\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438.
+Warning.LargeAOA.str2 = \u0411\u043e\u043b\u044c\u0448\u043e\u0439 \u0443\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438 (
+Warning.DISCONTINUITY = \u0420\u0430\u0441\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0432 \u0434\u0438\u0430\u043c\u0435\u0442\u0440\u0435 \u043a\u043e\u0440\u043f\u0443\u0441\u0430 \u0440\u0430\u043a\u0435\u0442\u044b.
+Warning.THICK_FIN = \u0422\u043e\u043b\u0441\u0442\u044b\u0435 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438.
+Warning.JAGGED_EDGED_FIN = \u0421\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u044b \u0441 \u0437\u0430\u043e\u0441\u0442\u0440\u0435\u043d\u043d\u044b\u043c\u0438 \u043a\u0440\u0430\u044f\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043c\u043e\u0434\u0435\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438.
+Warning.LISTENERS_AFFECTED = \u0421\u043b\u0443\u0448\u0430\u0442\u0435\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u0438\u043b\u0438 \u0440\u0430\u0441\u0447\u0435\u0442 \u043f\u043e\u043b\u0435\u0442\u0430
+Warning.RECOVERY_DEPLOYMENT_WHILE_BURNING = \u0421\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u043f\u0430\u0441\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0449\u0435\u043c \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u0435.
+Warning.FILE_INVALID_PARAMETER = \u0412\u0441\u0442\u0440\u0435\u0442\u0438\u043b\u0441\u044f \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440, \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u044e.
+Warning.PARALLEL_FINS = \u0421\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u043d\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432.
+Warning.SUPERSONIC = \u0420\u0430\u0441\u0447\u0435\u0442\u044b \u043a\u043e\u0440\u043f\u0443\u0441\u0430 \u043f\u0440\u0438 \u0441\u0432\u0435\u0440\u0445\u0437\u0432\u0443\u043a\u043e\u0432\u044b\u0445 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044f\u0445 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043d\u0435\u0442\u043e\u0447\u043d\u044b.
+Warning.RECOVERY_LAUNCH_ROD = \u0421\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u043f\u0430\u0441\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0439 \u043f\u043b\u043e\u0449\u0430\u0434\u043a\u0435.
+Warning.RECOVERY_HIGH_SPEED = \u0421\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u0435 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u043f\u0430\u0441\u0435\u043d\u0438\u044f \u043d\u0430 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438
 
 
 ! Scale dialog
-ScaleDialog.lbl.scaleRocket= Entire rocket
-ScaleDialog.lbl.scaleSubselection= Selection and all subcomponents
-ScaleDialog.lbl.scaleSelection= Only selected component
-ScaleDialog.title= Scale design
-ScaleDialog.lbl.scale= Scale:
-ScaleDialog.lbl.scale.ttip= Select whether to scale the entire design or only the selected component
-ScaleDialog.lbl.scaling= Scaling to apply:
-ScaleDialog.lbl.scaling.ttip= Resulting size, values above 100% grow and values below 100% shrink the design.
+ScaleDialog.lbl.scaleRocket = \u0420\u0430\u043a\u0435\u0442\u0443 \u0446\u0435\u043b\u0438\u043a\u043e\u043c
+ScaleDialog.lbl.scaleSubselection = \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u0438 \u0432\u0441\u0435 \u043f\u043e\u0434\u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b
+ScaleDialog.lbl.scaleSelection = \u0422\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+ScaleDialog.title = \u041c\u0430\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0445\u0435\u043c\u044b
+ScaleDialog.lbl.scale = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c:
+ScaleDialog.lbl.scale.ttip = \u0423\u043a\u0430\u0436\u0438\u0442\u0435, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043b\u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0438\u043b\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442
+ScaleDialog.lbl.scaling = \u041c\u0430\u0441\u0448\u0442\u0430\u0431:
+ScaleDialog.lbl.scaling.ttip = \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0431\u043e\u043b\u044c\u0448\u0438\u0435 100% - \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0435, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043c\u0435\u043d\u044c\u0448\u0438\u0435 100% - \u0443\u043c\u0435\u043d\u044c\u0448\u0435\u043d\u0438\u0435.
 ! The scaleFrom/scaleTo pair creates a phrase "Scale from [...] to [...]"
-ScaleDialog.lbl.scaleFrom= Scale from
-ScaleDialog.lbl.scaleTo= to
-ScaleDialog.lbl.scaleFromTo.ttip= Define the scaling based on an original and resulting length.
-ScaleDialog.checkbox.scaleMass= Update explicit mass values
-ScaleDialog.checkbox.scaleMass.ttip= Scale mass component and override mass values by the cube of the scaling factor
-ScaleDialog.button.scale= Scale
-ScaleDialog.undo.scaleRocket= Scale rocket
-ScaleDialog.undo.scaleComponent= Scale component
-ScaleDialog.undo.scaleComponents= Scale components
+ScaleDialog.lbl.scaleFrom = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442
+ScaleDialog.lbl.scaleTo = \u0434\u043e
+ScaleDialog.lbl.scaleFromTo.ttip = \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0430\u0441\u0448\u0442\u0430\u0431, \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u044f\u0441\u044c \u043d\u0430 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0439 \u0438 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0439 \u0434\u043b\u0438\u043d\u0435.
+ScaleDialog.checkbox.scaleMass = \u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u044f\u0432\u043d\u043e \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043c\u0430\u0441\u0441\u044b
+ScaleDialog.checkbox.scaleMass.ttip = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u043e\u0432\u043e\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043c\u0430\u0441\u0441\u044b \u043a\u0443\u0431\u043e\u043c \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442\u043e\u043c \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f
+ScaleDialog.button.scale = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u0442\u044c
+ScaleDialog.undo.scaleRocket = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u043a\u0435\u0442\u044b
+ScaleDialog.undo.scaleComponent = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430
+ScaleDialog.undo.scaleComponents = \u041c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u043e\u0432
 
 !icons
-Icons.Undo= Undo
-Icons.Redo= Redo
+Icons.Undo = \u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c
+Icons.Redo = \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c
 
-OpenRocketPrintable.Partsdetail= Parts detail
-OpenRocketPrintable.Fintemplates= Fin templates
-OpenRocketPrintable.Transitiontemplates= Transition templates
-OpenRocketPrintable.Noseconetemplates= Nose Cone templates
-OpenRocketPrintable.Finmarkingguide= Fin marking guide
-OpenRocketPrintable.DesignReport= Design Report
+OpenRocketPrintable.Partsdetail = \u0414\u0435\u0442\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0447\u0430\u0441\u0442\u0435\u0439
+OpenRocketPrintable.Fintemplates = \u0428\u0430\u0431\u043b\u043e\u043d\u044b \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432
+OpenRocketPrintable.Transitiontemplates = \u0428\u0430\u0431\u043b\u043e\u043d\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u043e\u0432
+OpenRocketPrintable.Noseconetemplates = \u0428\u0430\u0431\u043b\u043e\u043d\u044b \u0433\u043e\u043b\u043e\u0432\u043d\u044b\u0445 \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u0435\u0439
+OpenRocketPrintable.Finmarkingguide = \u0420\u0430\u0437\u043c\u0435\u0442\u043a\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432
+OpenRocketPrintable.DesignReport = \u0421\u0445\u0435\u043c\u0430
+OpenRocketPrintable.Centeringringtemplates = \u0428\u0430\u0431\u043b\u043e\u043d\u044b \u0446\u0435\u043d\u0442\u0440\u0438\u0440\u0443\u044e\u0449\u0438\u0445 \u043a\u043e\u043b\u0435\u0446
 
-OpenRocketDocument.Redo= Redo
-OpenRocketDocument.Undo= Undo
+OpenRocketDocument.Redo = \u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c
+OpenRocketDocument.Undo = \u041e\u0442\u043c\u0435\u043d\u0438\u0442\u044c
 
 !EllipticalFinSet
-EllipticalFinSet.Ellipticalfinset= Elliptical fin set
+EllipticalFinSet.Ellipticalfinset = \u042d\u043b\u043b\u0438\u043f\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u0435
 
 ! Optimization
 
 ! Modifiers
 
-optimization.modifier.nosecone.length= Length
-optimization.modifier.nosecone.length.desc= Optimize the nose cone length.
-optimization.modifier.nosecone.diameter= Diameter
-optimization.modifier.nosecone.diameter.desc= Optimize the nose cone base diameter.
-optimization.modifier.nosecone.thickness= Thickness
-optimization.modifier.nosecone.thickness.desc= Optimize the nose cone wall thickness.
-optimization.modifier.nosecone.shapeparameter= Shape parameter
-optimization.modifier.nosecone.shapeparameter.desc= Optimize the nose cone shape parameter.
-
-optimization.modifier.transition.length= Length
-optimization.modifier.transition.length.desc= Optimize the transition length.
-optimization.modifier.transition.forediameter= Fore diameter
-optimization.modifier.transition.forediameter.desc= Optimize the transition fore diameter.
-optimization.modifier.transition.aftdiameter= Aft diameter
-optimization.modifier.transition.aftdiameter.desc= Optimize the transition aft diameter.
-optimization.modifier.transition.thickness= Thickness
-optimization.modifier.transition.thickness.desc= Optimize the transition wall thickness.
-optimization.modifier.transition.shapeparameter= Shape parameter
-optimization.modifier.transition.shapeparameter.desc= Optimize the transition shape parameter.
-
-optimization.modifier.bodytube.length= Length
-optimization.modifier.bodytube.length.desc= Optimize the body tube length.
-optimization.modifier.bodytube.outerDiameter= Outer diameter
-optimization.modifier.bodytube.outerDiameter.desc= Optimize the body tube outer diameter while maintaining the wall thickness.
-optimization.modifier.bodytube.thickness= Thickness
-optimization.modifier.bodytube.thickness.desc= Optimize the body tube wall thickness.
-
-optimization.modifier.trapezoidfinset.rootChord= Root chord
-optimization.modifier.trapezoidfinset.rootChord.desc= Optimize the root chord length of the fin set (length of fin at the rocket body).
-optimization.modifier.trapezoidfinset.tipChord= Tip chord
-optimization.modifier.trapezoidfinset.tipChord.desc= Optimize the tip chord length of the fin set (length of fin at outer edge).
-optimization.modifier.trapezoidfinset.sweep= Sweep
-optimization.modifier.trapezoidfinset.sweep.desc= Optimize the sweep of the fin set (distance that the leading edge sweeps backwards).
-optimization.modifier.trapezoidfinset.height= Height
-optimization.modifier.trapezoidfinset.height.desc= Optimize the height (semi-span) of the fin set.
-
-optimization.modifier.ellipticalfinset.length= Root chord
-optimization.modifier.ellipticalfinset.length.desc= Optimize the root chord length of the fin set.
-optimization.modifier.ellipticalfinset.height= Height
-optimization.modifier.ellipticalfinset.height.desc= Optimize the height (semi-span) of the fin set.
-
-optimization.modifier.finset.cant= Cant angle
-optimization.modifier.finset.cant.desc= Optimize the cant angle of the fin set.
-optimization.modifier.finset.position= Position
-optimization.modifier.finset.position.desc= Optimize the fin set position along the rocket body.
-
-optimization.modifier.launchlug.length= Length
-optimization.modifier.launchlug.length.desc= Optimize the launch lug length.
-optimization.modifier.launchlug.outerDiameter= Outer diameter
-optimization.modifier.launchlug.outerDiameter.desc= Optimize the outer diameter of the launch lug.
-optimization.modifier.launchlug.thickness= Thickness
-optimization.modifier.launchlug.thickness.desc= Optimize the launch lug thickness while keeping the outer diameter constant.
-optimization.modifier.launchlug.position= Position
-optimization.modifier.launchlug.position.desc= Optimize the launch lug position along the rocket body.
-
-
-optimization.modifier.internalcomponent.position= Position
-optimization.modifier.internalcomponent.position.desc= Optimize the position of the component relative to the parent component.
-
-optimization.modifier.masscomponent.mass= Mass
-optimization.modifier.masscomponent.mass.desc= Optimize the mass of the mass component.
-
-optimization.modifier.parachute.diameter= Diameter
-optimization.modifier.parachute.diameter.desc= Optimize the parachute canopy diameter.
-optimization.modifier.parachute.coefficient= Drag coefficient
-optimization.modifier.parachute.coefficient.desc= Optimize the drag coefficient of the parachute.  Typical parachutes have a drag coefficient of about 0.8.
-
-optimization.modifier.streamer.length= Length
-optimization.modifier.streamer.length.desc= Optimize the length of the streamer.
-optimization.modifier.streamer.width= Width
-optimization.modifier.streamer.width.desc= Optimize the width of the streamer.
-optimization.modifier.streamer.aspectRatio= Aspect ratio
-optimization.modifier.streamer.aspectRatio.desc= Optimize the aspect ratio of the streamer (length/width).  You should NOT select streamer length or width at the same time with the aspect ratio.
-optimization.modifier.streamer.coefficient= Drag coefficient
-optimization.modifier.streamer.coefficient.desc= Optimize the drag coefficient of the streamer.
-
-optimization.modifier.recoverydevice.deployDelay= Deployment delay
-optimization.modifier.recoverydevice.deployDelay.desc= Optimize the deployment delay of the recovery device.
-optimization.modifier.recoverydevice.deployAltitude= Deployment altitude
-optimization.modifier.recoverydevice.deployAltitude.desc= Optimize the deployment altitude of the recovery device.
-
-optimization.modifier.rocketcomponent.overrideMass= Override mass
-optimization.modifier.rocketcomponent.overrideMass.desc= Optimize the overridden mass of the component.
-optimization.modifier.rocketcomponent.overrideCG= Override CG
-optimization.modifier.rocketcomponent.overrideCG.desc= Optimize the overridden center of gravity of the component.
-
-optimization.modifier.motormount.overhang= Motor overhang
-optimization.modifier.motormount.overhang.desc= Optimize the motor overhang.
-optimization.modifier.motormount.delay= Motor ignition delay
-optimization.modifier.motormount.delay.desc= Optimize the motor ignition delay.
+optimization.modifier.nosecone.length = \u0414\u043b\u0438\u043d\u0430
+optimization.modifier.nosecone.length.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u0433\u043e\u043b\u043e\u0432\u043d\u043e\u0433\u043e \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044f.
+optimization.modifier.nosecone.diameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440
+optimization.modifier.nosecone.diameter.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u043e\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044f.
+optimization.modifier.nosecone.thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430
+optimization.modifier.nosecone.thickness.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u0449\u0438\u043d\u0443 \u0441\u0442\u0435\u043d\u043e\u043a \u043d\u043e\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044f.
+optimization.modifier.nosecone.shapeparameter = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0444\u043e\u0440\u0438\u044b
+optimization.modifier.nosecone.shapeparameter.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043c\u0435\u0442\u0440 \u0444\u043e\u0440\u043c\u044b \u043d\u043e\u0441\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0442\u0435\u043a\u0430\u0442\u0435\u043b\u044f.
+
+optimization.modifier.transition.length = \u0414\u043b\u0438\u043d\u0430
+optimization.modifier.transition.length.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430.
+optimization.modifier.transition.forediameter = \u0412\u0445\u043e\u0434\u043d\u043e\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440
+optimization.modifier.transition.forediameter.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0445\u043e\u0434\u043d\u043e\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430.
+optimization.modifier.transition.aftdiameter = \u0412\u044b\u0445\u043e\u0434\u043d\u043e\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440
+optimization.modifier.transition.aftdiameter.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430.
+optimization.modifier.transition.thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430
+optimization.modifier.transition.thickness.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u0449\u0438\u043d\u0443 \u0441\u0442\u0435\u043d\u043e\u043a \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430.
+optimization.modifier.transition.shapeparameter = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0444\u043e\u0440\u043c\u044b
+optimization.modifier.transition.shapeparameter.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0444\u043e\u0440\u043c\u044b \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430.
+
+optimization.modifier.bodytube.length = \u0414\u043b\u0438\u043d\u0430
+optimization.modifier.bodytube.length.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u043a\u043e\u0440\u043f\u0443\u0441\u043d\u043e\u0439 \u0442\u0440\u0443\u0431\u044b.
+optimization.modifier.bodytube.outerDiameter = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440
+optimization.modifier.bodytube.outerDiameter.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u043a\u043e\u0440\u043f\u0443\u0441\u043d\u043e\u0439 \u0442\u0440\u0443\u0431\u044b \u0441 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0442\u043e\u043b\u0449\u0438\u043d\u044b \u0441\u0442\u0435\u043d\u043e\u043a.
+optimization.modifier.bodytube.thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430
+optimization.modifier.bodytube.thickness.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u0449\u0438\u043d\u0443 \u0441\u0442\u0435\u043d\u043e\u043a \u043a\u043e\u0440\u043f\u0443\u0441\u043d\u043e\u0439 \u0442\u0440\u0443\u0431\u044b.
+
+optimization.modifier.trapezoidfinset.rootChord = \u0414\u043b\u0438\u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f
+optimization.modifier.trapezoidfinset.rootChord.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u044f (\u0434\u043b\u0438\u043d\u0443 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430).
+optimization.modifier.trapezoidfinset.tipChord = \u0414\u043b\u0438\u043d\u0430 \u043d\u0430\u043a\u043e\u043d\u0435\u0447\u043d\u0438\u043a\u0430
+optimization.modifier.trapezoidfinset.tipChord.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u043d\u0430\u043a\u043e\u043d\u0435\u0447\u043d\u0438\u043a\u0430 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u044f.
+optimization.modifier.trapezoidfinset.sweep  = \u0421\u0442\u0440\u0435\u043b\u043e\u0432\u0438\u0434\u043d\u043e\u0441\u0442\u044c
+optimization.modifier.trapezoidfinset.sweep.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0440\u0435\u043b\u043e\u0432\u0438\u0434\u043d\u043e\u0441\u0442\u044c \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u044f.
+optimization.modifier.trapezoidfinset.height = \u0412\u044b\u0441\u043e\u0442\u0430
+optimization.modifier.trapezoidfinset.height.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u0442\u0443 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u044f.
+
+optimization.modifier.ellipticalfinset.length = \u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435
+optimization.modifier.ellipticalfinset.length.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0439 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432.
+optimization.modifier.ellipticalfinset.height = \u0412\u044b\u0441\u043e\u0442\u0430
+optimization.modifier.ellipticalfinset.height.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u0442\u0443 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u043e\u0432
+
+optimization.modifier.finset.cant = \u0423\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438
+optimization.modifier.finset.cant.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0433\u043e\u043b \u0430\u0442\u0430\u043a\u0438 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430.
+optimization.modifier.finset.position = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+optimization.modifier.finset.position.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043e\u043f\u0435\u0440\u0435\u043d\u0438\u044f \u043d\u0430 \u043a\u043e\u0440\u043f\u0443\u0441\u0435 \u0440\u0430\u043a\u0435\u0442\u044b.
+
+optimization.modifier.launchlug.length = \u0414\u043b\u0438\u043d\u0430
+optimization.modifier.launchlug.length.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u0441\u0442\u0430\u0440\u0442\u043e\u0432\u043e\u0433\u043e \u0441\u0442\u0435\u0440\u0436\u043d\u044f.
+optimization.modifier.launchlug.outerDiameter = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440
+optimization.modifier.launchlug.outerDiameter.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u043b\u044c\u0446\u0430.
+optimization.modifier.launchlug.thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430
+optimization.modifier.launchlug.thickness.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u0449\u0438\u043d\u0443 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u043b\u044c\u0446\u0430 \u0441 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435\u043c \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0434\u0438\u0430\u043c\u0435\u0442\u0440\u0430.
+optimization.modifier.launchlug.position = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+optimization.modifier.launchlug.position.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u043b\u044c\u0446\u0430 \u043d\u0430 \u043a\u043e\u0440\u043f\u0443\u0441\u0435 \u0440\u0430\u043a\u0435\u0442\u044b.
+
+
+optimization.modifier.internalcomponent.position = \u041f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435
+optimization.modifier.internalcomponent.position.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e.
+
+optimization.modifier.masscomponent.mass = \u041c\u0430\u0441\u0441\u0430
+optimization.modifier.masscomponent.mass.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c the \u043c\u0430\u0441\u0441\u0443 \u0432\u0435\u0441\u043e\u0432\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.
+
+optimization.modifier.parachute.diameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440
+optimization.modifier.parachute.diameter.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u043f\u0430\u0440\u0430\u0448\u044e\u0442\u043d\u043e\u0433\u043e \u043a\u0443\u043f\u043e\u043b\u0430.
+optimization.modifier.parachute.coefficient = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+optimization.modifier.parachute.coefficient.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u0448\u044e\u0442\u0430. \u041e\u0431\u044b\u0447\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u0448\u044e\u0442\u044b \u0438\u043c\u0435\u044e\u0442 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u043e\u043a\u043e\u043b\u043e 0.8.
+
+optimization.modifier.streamer.length = \u0414\u043b\u0438\u043d\u0430
+optimization.modifier.streamer.length.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u0438\u043d\u0443 \u0442\u043e\u0440\u043c\u043e\u0437\u043d\u043e\u0439 \u043b\u0435\u043d\u0442\u044b.
+optimization.modifier.streamer.width = \u0428\u0438\u0440\u0438\u043d\u0430
+optimization.modifier.streamer.width.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0448\u0438\u0440\u0438\u043d\u0443 \u0442\u043e\u0440\u043c\u043e\u0437\u043d\u043e\u0439 \u043b\u0435\u043d\u0442\u044b.
+optimization.modifier.streamer.aspectRatio = \u041e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d
+optimization.modifier.streamer.aspectRatio.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d \u0442\u043e\u0440\u043c\u043e\u0437\u043d\u043e\u0439 \u043b\u0435\u043d\u0442\u044b (\u0434\u043b\u0438\u043d\u0430/\u0448\u0438\u0440\u0438\u043d\u0430). \u041d\u0415 \u0432\u044b\u0431\u0438\u0440\u0430\u0439\u0442\u0435 \u0434\u043b\u0438\u043d\u0443 \u0442\u043e\u0440\u043c\u043e\u0437\u043d\u043e\u0439 \u043b\u0435\u043d\u0442\u044b \u0438 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0435 \u0441\u0442\u043e\u0440\u043e\u043d \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e!
+optimization.modifier.streamer.coefficient = \u041a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f
+optimization.modifier.streamer.coefficient.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0430\u044d\u0440\u043e\u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u0440\u043e\u0442\u0438\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u043e\u0440\u043c\u043e\u0437\u043d\u043e\u0439 \u043b\u0435\u043d\u0442\u044b.
+
+optimization.modifier.recoverydevice.deployDelay = \u0417\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u044f
+optimization.modifier.recoverydevice.deployDelay.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u043f\u0430\u0441\u0435\u043d\u0438\u044f.
+optimization.modifier.recoverydevice.deployAltitude = \u0412\u044b\u0441\u043e\u0442\u0430 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u044f
+optimization.modifier.recoverydevice.deployAltitude.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u044b\u0441\u043e\u0442\u0443 \u0441\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 \u0441\u043f\u0430\u0441\u0435\u043d\u0438\u044f.
+
+optimization.modifier.rocketcomponent.overrideMass = \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0430\u044f \u043c\u0430\u0441\u0441\u0430
+optimization.modifier.rocketcomponent.overrideMass.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u0443\u044e \u043c\u0430\u0441\u0441\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.
+optimization.modifier.rocketcomponent.overrideCG = \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0426\u0422
+optimization.modifier.rocketcomponent.overrideCG.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0446\u0435\u043d\u0442\u0440 \u0442\u044f\u0436\u0435\u0441\u0442\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430.
+
+optimization.modifier.motormount.overhang = \u0421\u0432\u0435\u0441 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+optimization.modifier.motormount.overhang.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u0435\u0441 \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f.
+optimization.modifier.motormount.delay = \u0417\u0430\u0434\u0435\u0440\u0436\u043a\u0430 \u0432\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f
+optimization.modifier.motormount.delay.desc = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0437\u0430\u0434\u0435\u0440\u0436\u043a\u0443 \u0432\u043e\u0441\u043f\u043b\u0430\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u0432\u0438\u0433\u0430\u0442\u0435\u043b\u044f.
 
 
 
 
 ! General rocket design optimization dialog
 
-GeneralOptimizationDialog.title= Rocket optimization
-GeneralOptimizationDialog.goal.maximize= Maximize value
-GeneralOptimizationDialog.goal.minimize= Minimize value
-GeneralOptimizationDialog.goal.seek= Seek value of
-GeneralOptimizationDialog.btn.start= Start optimization
-GeneralOptimizationDialog.btn.stop= Stop optimization
-GeneralOptimizationDialog.lbl.paramsToOptimize= Parameters to optimize:
-GeneralOptimizationDialog.btn.add= Add
-GeneralOptimizationDialog.btn.add.ttip= Add the selected parameter to the optimization
-GeneralOptimizationDialog.btn.remove= Remove
-GeneralOptimizationDialog.btn.remove.ttip= Remove the selected parameter from the optimization
-GeneralOptimizationDialog.btn.removeAll= Remove all
-GeneralOptimizationDialog.btn.removeAll.ttip= Remove all parameters from the optimization
-GeneralOptimizationDialog.lbl.availableParams= Available parameters:
-GeneralOptimizationDialog.lbl.optimizationOpts= Optimization options
-GeneralOptimizationDialog.lbl.optimizeSim= Optimize simulation:
-GeneralOptimizationDialog.lbl.optimizeSim.ttip= Select which simulation to optimize
-GeneralOptimizationDialog.lbl.optimizeValue= Optimized value:
-GeneralOptimizationDialog.lbl.optimizeValue.ttip= Select what value is to be optimized
-GeneralOptimizationDialog.lbl.optimizeGoal= Optimization goal:
-GeneralOptimizationDialog.lbl.optimizeGoal.ttip= Select the goal of the optimization
-GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip= Custom value to seek
-GeneralOptimizationDialog.lbl.requireStability= Required stability
-GeneralOptimizationDialog.lbl.requireMinStability= Minimum stability:
-GeneralOptimizationDialog.lbl.requireMinStability.ttip= Require a minimum static stability margin for the design
-GeneralOptimizationDialog.lbl.requireMaxStability= Maximum stability:
-GeneralOptimizationDialog.lbl.requireMaxStability.ttip= Require a maximum static stability margin for the design
-GeneralOptimizationDialog.status.bestValue= Best value:
-GeneralOptimizationDialog.status.bestValue.ttip= Best optimization value found so far.
-GeneralOptimizationDialog.status.stepCount= Step count:
-GeneralOptimizationDialog.status.stepCount.ttip= Number of optimization steps that have been performed.
-GeneralOptimizationDialog.status.evalCount= Evaluations:
-GeneralOptimizationDialog.status.evalCount.ttip= Total number of function evaluations (simulations) that have been performed.
-GeneralOptimizationDialog.status.stepSize= Step size:
-GeneralOptimizationDialog.status.stepSize.ttip= Current optimization step size (relative to the optimization parameter ranges)
-GeneralOptimizationDialog.btn.plotPath= Plot path
-GeneralOptimizationDialog.btn.plotPath.ttip= Plot the optimization path (one and two dimensional optimization only)
-GeneralOptimizationDialog.btn.save= Save path
-GeneralOptimizationDialog.btn.save.ttip= Save the results of the function evaluations (simulations) as a CSV file.
-GeneralOptimizationDialog.btn.apply= Apply optimization
-GeneralOptimizationDialog.btn.apply.ttip= Apply the optimization results to the rocket design
-GeneralOptimizationDialog.btn.reset= Reset
-GeneralOptimizationDialog.btn.reset.ttip= Reset the rocket design to the current rocket design
-GeneralOptimizationDialog.btn.close= Close
-GeneralOptimizationDialog.btn.close.ttip= Close the dialog without modifying the rocket design
-GeneralOptimizationDialog.error.selectParams.text= First select some parameters to optimize from the available parameters.
-GeneralOptimizationDialog.error.selectParams.title= Select optimization parameters
-GeneralOptimizationDialog.error.optimizationFailure.text= The optimization failed to run:
-GeneralOptimizationDialog.error.optimizationFailure.title= Optimization failed
-GeneralOptimizationDialog.undoText= Apply optimization
-GeneralOptimizationDialog.basicSimulationName= Basic simulation
-GeneralOptimizationDialog.noSimulationName= No simulation
-GeneralOptimizationDialog.table.col.parameter= Parameter
-GeneralOptimizationDialog.table.col.current= Current
-GeneralOptimizationDialog.table.col.min= Minimum
-GeneralOptimizationDialog.table.col.max= Maximum
-GeneralOptimizationDialog.export.header= Include header line
-GeneralOptimizationDialog.export.header.ttip= Include a header line as the first line containing the field descriptions.
-GeneralOptimizationDialog.export.stability= Stability
+GeneralOptimizationDialog.title = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0440\u0430\u043a\u0435\u0442\u044b
+GeneralOptimizationDialog.goal.maximize = \u041c\u0430\u043a\u0441\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f
+GeneralOptimizationDialog.goal.minimize = \u041c\u0438\u043d\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f
+GeneralOptimizationDialog.goal.seek = \u041f\u043e\u0438\u0441\u043a \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f
+GeneralOptimizationDialog.btn.start = \u041d\u0430\u0447\u0430\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e
+GeneralOptimizationDialog.btn.stop = \u041e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e
+GeneralOptimizationDialog.lbl.paramsToOptimize = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:
+GeneralOptimizationDialog.btn.add = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c
+GeneralOptimizationDialog.btn.add.ttip = \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e
+GeneralOptimizationDialog.btn.remove = \u0423\u0434\u0430\u043b\u0438\u0442\u044c
+GeneralOptimizationDialog.btn.remove.ttip = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0438\u0437 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+GeneralOptimizationDialog.btn.removeAll = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u0441\u0435
+GeneralOptimizationDialog.btn.removeAll.ttip = \u0423\u0434\u0430\u043b\u0438\u0442\u044c \u0432\u0441\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0437 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+GeneralOptimizationDialog.lbl.availableParams = \u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:
+GeneralOptimizationDialog.lbl.optimizationOpts = \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+GeneralOptimizationDialog.lbl.optimizeSim = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u0440\u0430\u0441\u0447\u0435\u0442:
+GeneralOptimizationDialog.lbl.optimizeSim.ttip = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0440\u0430\u0441\u0447\u0435\u0442 \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+GeneralOptimizationDialog.lbl.optimizeValue = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435:
+GeneralOptimizationDialog.lbl.optimizeValue.ttip = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0442\u0430\u044c
+GeneralOptimizationDialog.lbl.optimizeGoal = \u0426\u0435\u043b\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438:
+GeneralOptimizationDialog.lbl.optimizeGoal.ttip = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0446\u0435\u043b\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+GeneralOptimizationDialog.lbl.optimizeGoalValue.ttip = \u0426\u0435\u043b\u044c \u043f\u043e\u0438\u0441\u043a\u0430
+GeneralOptimizationDialog.lbl.requireStability = \u0422\u0440\u0435\u0431\u0443\u0435\u043c\u0430\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c
+GeneralOptimizationDialog.lbl.requireMinStability = \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c:
+GeneralOptimizationDialog.lbl.requireMinStability.ttip = \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u0430\u044f \u0433\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438
+GeneralOptimizationDialog.lbl.requireMaxStability = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c:
+GeneralOptimizationDialog.lbl.requireMaxStability.ttip = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u0430\u044f \u0433\u0440\u0430\u043d\u0438\u0446\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u0438
+GeneralOptimizationDialog.status.bestValue = \u041b\u0443\u0447\u0448\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435:
+GeneralOptimizationDialog.status.bestValue.ttip = \u041d\u0430\u0439\u0434\u0435\u043d\u043d\u043e\u0435 \u043b\u0443\u0447\u0448\u0435\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435.
+GeneralOptimizationDialog.status.stepCount = \u041d\u043e\u043c\u0435\u0440 \u0448\u0430\u0433\u0430:
+GeneralOptimizationDialog.status.stepCount.ttip = \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0445 \u0448\u0430\u0433\u043e\u0432 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438.
+GeneralOptimizationDialog.status.evalCount = \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f:
+GeneralOptimizationDialog.status.evalCount.ttip = \u041e\u0431\u0449\u0435\u0435 \u0447\u0438\u0441\u043b\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0445 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u0432.
+GeneralOptimizationDialog.status.stepSize = \u0420\u0430\u0437\u043c\u0435\u0440 \u0448\u0430\u0433\u0430:
+GeneralOptimizationDialog.status.stepSize.ttip = \u0422\u0435\u043a\u0443\u0449\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440 \u0448\u0430\u0433\u0430 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 (\u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0445 \u0433\u0440\u0430\u043d\u0438\u0446 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f)
+GeneralOptimizationDialog.btn.plotPath = \u0413\u0440\u0430\u0444\u0438\u043a \u043f\u0443\u0442\u0438
+GeneralOptimizationDialog.btn.plotPath.ttip = \u041f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a \u043f\u0443\u0442\u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 (\u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0439 \u0438\u043b\u0438 \u0434\u0432\u0443\u0445 \u0441\u0442\u0435\u043f\u0435\u043d\u0435\u0439)
+GeneralOptimizationDialog.btn.save = \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u0443\u0442\u044c
+GeneralOptimizationDialog.btn.save.ttip = \u0421\u043e\u0445\u0440\u043d\u0430\u0438\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u0432 \u0444\u0430\u0439\u043b CSV.
+GeneralOptimizationDialog.btn.apply = \u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044e
+GeneralOptimizationDialog.btn.apply.ttip = \u041f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043a \u0441\u0445\u0435\u043c\u0435 \u0440\u0430\u043a\u0435\u0442\u044b
+GeneralOptimizationDialog.btn.reset = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c
+GeneralOptimizationDialog.btn.reset.ttip = \u0412\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0445\u0435\u043c\u0443 \u0440\u0430\u043a\u0435\u0442\u044b
+GeneralOptimizationDialog.btn.close = \u0417\u0430\u043a\u0440\u044b\u0442\u044c
+GeneralOptimizationDialog.btn.close.ttip = \u0417\u0430\u043a\u0440\u044b\u0442\u044c \u043e\u043a\u043d\u043e \u0431\u0435\u0437 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+GeneralOptimizationDialog.error.selectParams.text = \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0434\u043b\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438.
+GeneralOptimizationDialog.error.selectParams.title = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+GeneralOptimizationDialog.error.optimizationFailure.text = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435 \u0443\u0434\u0430\u043b\u0430\u0441\u044c:
+GeneralOptimizationDialog.error.optimizationFailure.title = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0435 \u0443\u0434\u0430\u043b\u0430\u0441\u044c
+GeneralOptimizationDialog.undoText = \u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+GeneralOptimizationDialog.basicSimulationName = \u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u0440\u0430\u0441\u0447\u0435\u0442
+GeneralOptimizationDialog.noSimulationName = \u0411\u0435\u0437 \u0440\u0430\u0441\u0447\u0435\u0442\u0430
+GeneralOptimizationDialog.table.col.parameter = \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440
+GeneralOptimizationDialog.table.col.current = \u0422\u0435\u043a\u0443\u0449\u0435\u0435
+GeneralOptimizationDialog.table.col.min = \u041c\u0438\u043d\u0438\u043c\u0443\u043c
+GeneralOptimizationDialog.table.col.max = \u041c\u0430\u043a\u0441\u0438\u043c\u0443\u043c
+GeneralOptimizationDialog.export.header = \u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432
+GeneralOptimizationDialog.export.header.ttip = \u041f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043f\u0435\u0440\u0432\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0443, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0443\u044e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u043f\u043e\u043b\u0435\u0439.
+GeneralOptimizationDialog.export.stability = \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c
 
 
 ! Dialog for plotting optimization results
-OptimizationPlotDialog.title= Optimization results
-OptimizationPlotDialog.lbl.zoomInstructions= Click and drag down+right to zoom in, up+left to zoom out
-OptimizationPlotDialog.plot1d.title= Optimization result
-OptimizationPlotDialog.plot1d.series= Optimization result
-OptimizationPlotDialog.plot2d.title= Optimization path
-OptimizationPlotDialog.plot2d.path= Optimization path
-OptimizationPlotDialog.plot2d.evals= Evaluations
-OptimizationPlotDialog.plot.ttip.stability= Stability:
-OptimizationPlotDialog.plot.label.optimum= Optimum
+OptimizationPlotDialog.title = \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+OptimizationPlotDialog.lbl.zoomInstructions = \u041a\u043b\u0438\u043a \u0438 \u0442\u0430\u0449\u0438\u0442\u044c \u0432\u043f\u0440\u0430\u0432\u043e-\u0432\u043d\u0438\u0437 \u0434\u043b\u044f \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u0438\u044f, \u0432\u043b\u0435\u0432\u043e \u0432\u0432\u0435\u0440\u0445 \u0434\u043b\u044f \u043e\u0442\u0434\u0430\u043b\u0435\u043d\u0438\u044f
+OptimizationPlotDialog.plot1d.title = \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+OptimizationPlotDialog.plot1d.series = \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+OptimizationPlotDialog.plot2d.title = \u041f\u0443\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+OptimizationPlotDialog.plot2d.path = \u041f\u0443\u0442\u044c \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438
+OptimizationPlotDialog.plot2d.evals = \u0412\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f
+OptimizationPlotDialog.plot.ttip.stability = \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c:
+OptimizationPlotDialog.plot.label.optimum = \u041e\u043f\u0442\u0438\u043c\u0443\u043c
+
+! SimulationModifierTree
+SimulationModifierTree.OptimizationParameters = \u041e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b
 
 ! Optimization parameters
-MaximumAltitudeParameter.name= Apogee altitude
-MaximumVelocityParameter.name= Maximum velocity
-MaximumAccelerationParameter.name= Maximum acceleration
-StabilityParameter.name= Stability
-GroundHitVelocityParameter.name= Ground hit speed
-LandingDistanceParameter.name= Landing distance
-TotalFlightTimeParameter.name= Total flight time
-DeploymentVelocityParameter.name= Velocity at parachute deployment
+MaximumAltitudeParameter.name = \u0412\u044b\u0441\u043e\u0442\u0430 \u0430\u043f\u043e\u0433\u0435\u044f
+MaximumVelocityParameter.name = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c
+MaximumAccelerationParameter.name = \u041c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435
+StabilityParameter.name = \u0421\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u043e\u0441\u0442\u044c
+GroundHitVelocityParameter.name = \u0421\u043a\u043e\u0440\u0441\u0442\u044c \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u044f
+LandingDistanceParameter.name = \u0414\u0438\u0441\u0442\u0430\u043d\u0446\u0438\u044f \u043f\u0440\u0438\u0437\u0435\u043c\u043b\u0435\u043d\u0438\u044f
+TotalFlightTimeParameter.name = \u041e\u0431\u0449\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u043b\u0435\u0442\u0430
+DeploymentVelocityParameter.name = \u0421\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u0440\u0430\u0441\u043a\u0440\u044b\u0442\u0438\u0438 \u043f\u0430\u0440\u0430\u0448\u044e\u0442\u0430
 
 
 ! Compass directions drawn on a compass rose.
-CompassRose.lbl.north= N
-CompassRose.lbl.east= E
-CompassRose.lbl.south= S
-CompassRose.lbl.west= W
+CompassRose.lbl.north = \u0421
+CompassRose.lbl.east  = \u0412
+CompassRose.lbl.south = \u042e
+CompassRose.lbl.west  = \u0417
 
 ! Compass directions with subdirections.  These might not be localized even if the directions on the compass rose are.
-CompassSelectionButton.lbl.N= N
-CompassSelectionButton.lbl.NE= NE
-CompassSelectionButton.lbl.E= E
-CompassSelectionButton.lbl.SE= SE
-CompassSelectionButton.lbl.S= S
-CompassSelectionButton.lbl.SW= SW
-CompassSelectionButton.lbl.W= W
-CompassSelectionButton.lbl.NW= NW
-
-
-SlideShowDialog.btn.next= Next
-SlideShowDialog.btn.prev= Previous
-
-GuidedTourSelectionDialog.title= Guided tours
-GuidedTourSelectionDialog.lbl.selectTour= Select guided tour:
-GuidedTourSelectionDialog.lbl.description= Tour description:
-GuidedTourSelectionDialog.lbl.length= Number of slides:
-GuidedTourSelectionDialog.btn.start= Start tour!
+CompassSelectionButton.lbl.N = N
+CompassSelectionButton.lbl.NE = NE
+CompassSelectionButton.lbl.E = E
+CompassSelectionButton.lbl.SE = SE
+CompassSelectionButton.lbl.S = S
+CompassSelectionButton.lbl.SW = SW
+CompassSelectionButton.lbl.W = W
+CompassSelectionButton.lbl.NW = NW
+
+
+SlideShowDialog.btn.next = \u0414\u0430\u043b\u0435\u0435
+SlideShowDialog.btn.prev = \u041d\u0430\u0437\u0430\u0434
+
+SlideShowLinkListener.error.title = \u041f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0430 \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b
+SlideShowLinkListener.error.msg = \u0418\u0437\u0432\u0438\u043d\u0438\u0442\u0435, \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u0435\u0449\u0435 \u043d\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e.
+
+GuidedTourSelectionDialog.title = \u041f\u043e\u0448\u0430\u0433\u043e\u0432\u044b\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0430
+GuidedTourSelectionDialog.lbl.selectTour = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u043e\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e:
+GuidedTourSelectionDialog.lbl.description = \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0440\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u0430:
+GuidedTourSelectionDialog.lbl.length = \u041a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043b\u0430\u0439\u0434\u043e\u0432:
+GuidedTourSelectionDialog.btn.start = \u041d\u0430\u0447\u0430\u0442\u044c!
+
+
+! Custom Fin BMP Importer
+CustomFinImport.button.label = \u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0437 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f
+CustomFinImport.badFinImage = \u041d\u0435\u0432\u0435\u0440\u043d\u043e\u0435 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435. \u0423\u0434\u043e\u0441\u0442\u043e\u0432\u0435\u0440\u044c\u0442\u0435\u0441\u044c, \u0447\u0442\u043e \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d \u043e\u0434\u0438\u043d\u043c \u0447\u0435\u0440\u043d\u044b\u043c \u0438\u043b\u0438 \u0442\u0435\u043c\u043d\u044b\u043c \u0446\u0432\u0435\u0442\u043e\u043c \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441\u043d\u0438\u0437\u0443 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f.
+CustomFinImport.errorLoadingFile = \u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u0444\u0430\u0439\u043b\u0430:
+CustomFinImport.errorParsingFile = \u041e\u0448\u0438\u0431\u043a\u0430 \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430:
+CustomFinImport.undo = \u0418\u043c\u043f\u043e\u0440\u0442 \u0444\u043e\u0440\u043c\u044b \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430
+CustomFinImport.error.title = \u041e\u0448\u0438\u0431\u043a\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0438 \u043f\u0440\u043e\u0444\u0438\u043b\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430
+CustomFinImport.error.badimage = \u041d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0443 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u0438\u0437 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f.
+CustomFinImport.description = \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u0447\u0435\u0440\u043d\u043e-\u0431\u0435\u043b\u043e\u0435 (\u0433\u0434\u0435 \u0447\u0435\u0440\u043d\u044b\u0439 - \u0446\u0432\u0435\u0442 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430), \u0442\u0430\u043a \u0447\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0447\u0435\u0440\u043d\u044b\u0439 \u0446\u0432\u0435\u0442 \u0434\u043b\u044f \u0440\u0438\u0441\u0443\u043d\u043a\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u0438 \u0431\u0435\u043b\u044b\u0439 \u0438\u043b\u0438 \u0441\u0432\u0435\u0442\u043b\u044b\u0439 \u0446\u0432\u0435\u0442 \u0434\u043b\u044f \u0444\u043e\u043d\u0430. \u041e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0442\u0430\u0431\u0438\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430 \u0434\u043e\u043b\u0436\u043d\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u0442\u044c\u0441\u044f \u0441\u043d\u0438\u0437\u0443 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f.
+
+
+PresetModel.lbl.select = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0443
+PresetModel.lbl.database = \u0418\u0437 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445...
+
+
+! Component Preset Chooser Dialog
+ComponentPresetChooserDialog.title = \u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0437\u0430\u0433\u043e\u0442\u043e\u0432\u043a\u0443 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430
+ComponentPresetChooserDialog.filter.label = \u0424\u0438\u043b\u044c\u0442\u0440 \u043f\u043e \u0442\u0435\u043a\u0441\u0442\u0443:
+ComponentPresetChooserDialog.checkbox.filterAftDiameter = \u0418\u0441\u043a\u0430\u0442\u044c \u043f\u043e \u0434\u0438\u0430\u043c\u0435\u0442\u0440\u0443 \u043d\u0430\u0447\u0430\u043b\u0430
+ComponentPresetChooserDialog.checkbox.filterForeDiameter = \u0418\u0441\u043a\u0430\u0442\u044c \u043f\u043e \u0434\u0438\u0430\u043c\u0435\u0442\u0440\u0443 \u043a\u043e\u043d\u0446\u0430
+ComponentPresetChooserDialog.menu.sortAsc = \u041f\u043e \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430\u043d\u0438\u044e
+ComponentPresetChooserDialog.menu.sortDesc = \u041f\u043e \u0443\u0431\u044b\u0432\u0430\u043d\u0438\u044e
+ComponentPresetChooserDialog.menu.units = \u0415\u0434\u0438\u043d\u0438\u0446\u044b \u0438\u0437\u043c\u0435\u0440\u0435\u043d\u0438\u044f
+ComponentPresetChooserDialog.checkbox.showAllCompatible = \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0435
+table.column.Favorite = \u0418\u0437\u0431\u0440\u0430\u043d\u043d\u043e\u0435
+table.column.Manufacturer = \u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c
+table.column.PartNo = \u041d\u043e\u043c\u0435\u0440 \u0434\u0435\u0442\u0430\u043b\u0438
+table.column.Description = \u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435
+table.column.Type = \u0422\u0438\u043f
+table.column.Length = \u0414\u043b\u0438\u043d\u0430
+table.column.Width = \u0428\u0438\u0440\u0438\u043d\u0430
+table.column.InnerDiameter = \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440
+table.column.OuterDiameter = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440
+table.column.AftOuterDiameter = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430
+table.column.AftShoulderLength = \u0414\u043b\u0438\u043d\u0430 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430
+table.column.AftShoulderDiameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430
+table.column.ForeShoulderLength = \u0414\u043b\u0438\u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430
+table.column.ForeShoulderDiameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430
+table.column.ForeOuterDiameter = \u0412\u043d\u0435\u0448\u043d\u0438\u0439 \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0433\u043e \u0432\u044b\u0441\u0442\u0443\u043f\u0430
+table.column.Shape = \u0424\u043e\u0440\u043c\u0430
+table.column.Material = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b
+table.column.Finish = \u041e\u0442\u0434\u0435\u043b\u043a\u0430
+table.column.Thickness = \u0422\u043e\u043b\u0449\u0438\u043d\u0430
+table.column.Filled = \u0417\u0430\u043f\u043e\u043b\u043d\u0435\u043d
+table.column.Mass = \u041c\u0430\u0441\u0441\u0430
+table.column.Diameter = \u0414\u0438\u0430\u043c\u0435\u0442\u0440
+table.column.Sides = \u0421\u0442\u043e\u0440\u043e\u043d\u044b
+table.column.LineCount = \u0427\u0438\u0441\u043b\u043e \u0441\u0442\u0440\u043e\u043f
+table.column.LineLength = \u0414\u043b\u0438\u043d\u0430 \u0441\u0442\u0440\u043e\u043f
+table.column.LineMaterial = \u041c\u0430\u0442\u0435\u0440\u0438\u0430\u043b \u0441\u0442\u0440\u043e\u043f
+
 
diff --git a/core/resources/l10n/rename.sh b/core/resources/l10n/rename.sh
new file mode 100755 (executable)
index 0000000..96ca246
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Usage:
+# ./rename <file-containing-rename-keys> <files_to_modify ...>
+#
+# Rename keys file contains space-separated lines:
+#    <old.key> <new.key>
+
+RENAME="$1"
+shift
+
+cat "$RENAME" | while read line ; do
+
+    FROM=`echo $line | awk '{print $1}'`
+    TO=`echo $line | awk '{print $2}'`
+
+    sed -i "s/$FROM/$TO/g" "$@"
+
+done
index 7320b9501e4837033a5fbff2b5fd64220c18bbb5..b1fc04ea6b876554751874ce33e9e69a98b39c94 100644 (file)
@@ -20,6 +20,9 @@ edit-delete.png
 edit-paste.png
 edit-redo.png
 edit-undo.png
+down.png
+pencil.png
+up.png
 edit-scale.png (modified from edit-copy.png)
 
 
@@ -35,3 +38,5 @@ help-log.png
 help-about.png
 help-bug.png
 help-tours.png
+star_silver.png
+star_gold.png (modified from star_silver.png)
diff --git a/core/resources/pix/icons/down.png b/core/resources/pix/icons/down.png
new file mode 100644 (file)
index 0000000..f3bc4cd
Binary files /dev/null and b/core/resources/pix/icons/down.png differ
diff --git a/core/resources/pix/icons/pencil.png b/core/resources/pix/icons/pencil.png
new file mode 100644 (file)
index 0000000..5b8cc89
Binary files /dev/null and b/core/resources/pix/icons/pencil.png differ
diff --git a/core/resources/pix/icons/star_gold.png b/core/resources/pix/icons/star_gold.png
new file mode 100644 (file)
index 0000000..686aa93
Binary files /dev/null and b/core/resources/pix/icons/star_gold.png differ
diff --git a/core/resources/pix/icons/star_silver.png b/core/resources/pix/icons/star_silver.png
new file mode 100644 (file)
index 0000000..30245ee
Binary files /dev/null and b/core/resources/pix/icons/star_silver.png differ
diff --git a/core/resources/pix/icons/up.png b/core/resources/pix/icons/up.png
new file mode 100644 (file)
index 0000000..184c118
Binary files /dev/null and b/core/resources/pix/icons/up.png differ
index 1ec8ea6f5967f5b83056a30be8a37b0304df0136..3f480d3260492b5c3c78ed321bf5dd5f31c3f77d 100755 (executable)
@@ -13,6 +13,13 @@ while echo "$1" | grep -q "^-" ; do
     shift
 done
 
+LIBS="bin/"
+LIBS="$LIBS:resources/"
+for i in lib/*.jar ; do
+    LIBS="$LIBS:$i"
+done
+LIBS="$LIBS:lib/jogl/gluegen-rt.jar"
+LIBS="$LIBS:lib/jogl/jogl.all.jar"
 
-java -cp bin/:resources/:lib/miglayout15-swing.jar:lib/jcommon-1.0.16.jar:lib/jfreechart-1.0.13.jar:lib/iText-5.0.2.jar $JAVAOPTS net.sf.openrocket.startup.Startup "$@"
+java -cp $LIBS $JAVAOPTS net.sf.openrocket.startup.Startup "$@"
 
diff --git a/core/src/de/congrace/exp4j/AbstractExpression.java b/core/src/de/congrace/exp4j/AbstractExpression.java
new file mode 100644 (file)
index 0000000..fc7f56b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Abstract base class for mathematical expressions
+ * 
+ * @author fas@congrace.de
+ */
+abstract class AbstractExpression {
+       private final String expression;
+       private final Token[] tokens;
+       private final String[] variableStrings;
+       private final NumberFormat numberFormat = NumberFormat.getInstance();
+
+       /**
+        * Construct a new {@link AbstractExpression}
+        * 
+        * @param expression
+        *            the mathematical expression to be used
+        * @param tokens
+        *            the {@link Token}s in the expression
+        * @param variableNames
+        *            an array of variable names which are used in the expression
+        */
+       AbstractExpression(String expression, Token[] tokens, String[] variableStrings) {
+               this.expression = expression;
+               this.tokens = tokens;
+               this.variableStrings = variableStrings;
+       }
+
+       /**
+        * get the mathematical expression {@link String}
+        * 
+        * @return the expression
+        */
+       public String getExpression() {
+               return expression;
+       }
+
+       /**
+        * get the used {@link NumberFormat}
+        * 
+        * @return the used {@link NumberFormat}
+        */
+       public NumberFormat getNumberFormat() {
+               return numberFormat;
+       }
+
+       /**
+        * get the {@link Token}s
+        * 
+        * @return the array of {@link Token}s
+        */
+       Token[] getTokens() {
+               return tokens;
+       }
+       
+}
diff --git a/core/src/de/congrace/exp4j/Calculable.java b/core/src/de/congrace/exp4j/Calculable.java
new file mode 100644 (file)
index 0000000..4009cb5
--- /dev/null
@@ -0,0 +1,31 @@
+package de.congrace.exp4j;
+
+/**
+ * This is the basic result class of the exp4j {@link ExpressionBuilder}
+ * 
+ * @author ruckus
+ * 
+ */
+public interface Calculable {
+       /**
+        * calculate the result of the expression
+        * 
+        * @return the result of the calculation
+        */
+       public Variable calculate();
+
+       /**
+        * return the expression in reverse polish postfix notation
+        * 
+        * @return the expression used to construct this {@link Calculable}
+        */
+       public String getExpression();
+
+       /**
+        * set a variable value for the calculation
+        * 
+        * @param value
+        *            the value of the variable
+        */
+       public void setVariable(Variable var);
+}
diff --git a/core/src/de/congrace/exp4j/CalculationToken.java b/core/src/de/congrace/exp4j/CalculationToken.java
new file mode 100644 (file)
index 0000000..c40408a
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Arrays;
+import java.util.Stack;
+
+abstract class CalculationToken extends Token {
+
+       CalculationToken(String value) {
+               super(value);
+       }
+
+       abstract void mutateStackForCalculation(Stack<Variable> stack, VariableSet variables);
+
+       /*
+        * Given an array of variables, check if any are arrays and if so expand any other of the given variables to arrays of the same length.
+        * Doubles are turned into arrays of all the same value as original. Arrays of other lengths are padded with zeros. 
+        */
+       public Variable[] expandVariables(Variable[] values){
+               // Check if any variables have preferred representation as arrays
+               int maxLength = 0;
+               for (Variable v : values){
+                       if (v.getPrimary() == Variable.Primary.ARRAY && v.getArrayValue().length > maxLength){
+                               maxLength = v.getArrayValue().length;
+                       }
+               }
+               
+               // if necessary, expand any non-array variables to maximum length
+               if (maxLength > 0) {
+                       for (int n = 0; n<values.length; n++){
+                               Variable v = values[n];
+                               if (v.getPrimary() == Variable.Primary.DOUBLE){
+                                       double[] a = new double[maxLength];
+                                       Arrays.fill(a, v.getDoubleValue());
+                                       values[n] = new Variable(v.getName(), a);
+                               }
+                               else if (v.getPrimary() == Variable.Primary.ARRAY){
+                                       // inlining Arrays.copyOf to provide compatibility with Froyo
+                                       double[] a = new double[maxLength];
+                                       int i = 0;
+                                       double[] vArrayValues = v.getArrayValue();
+                                       while( i < vArrayValues.length && i < maxLength ) {
+                                               a[i] = vArrayValues[i];
+                                               i++;
+                                       }
+                                       while ( i< maxLength ) {
+                                               a[i] = 0.0;
+                                               i++;
+                                       }
+                                       values[n] = new Variable(v.getName(), a);
+                               } 
+                               else {
+                                       // Should not happen, if it does return invalid variable
+                                       return new Variable[] { new Variable("Invalid")};
+                               }
+                       }
+               }
+               
+               return values;
+       }
+}
diff --git a/core/src/de/congrace/exp4j/CommandlineInterpreter.java b/core/src/de/congrace/exp4j/CommandlineInterpreter.java
new file mode 100644 (file)
index 0000000..78670a4
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+/**
+ * Simple commandline interpreter for mathematical expressions the interpreter
+ * takes a mathematical expressions as a {@link String} argument, evaluates it
+ * and prints out the result.
+ * 
+ * 
+ * <pre>
+ * java de.congrace.exp4j.CommandlineInterpreter "2 * log(2.2223) - ((2-3.221) * 14.232^2)"
+ * > 248.91042049521056
+ * </pre>
+ * 
+ * @author fas@congrace.de
+ * 
+ */
+public class CommandlineInterpreter {
+       private static void calculateExpression(String string) {
+               try {
+                       final PostfixExpression pe = PostfixExpression.fromInfix(string);
+                       System.out.println(pe.calculate());
+               } catch (UnparsableExpressionException e) {
+                       e.printStackTrace();
+               } catch (UnknownFunctionException e) {
+                       e.printStackTrace();
+               }
+       }
+
+       public static void main(String[] args) {
+               if (args.length != 1) {
+                       printUsage();
+               } else {
+                       calculateExpression(args[0]);
+               }
+       }
+
+       private static void printUsage() {
+               final StringBuilder usage = new StringBuilder();
+               usage.append("Commandline Expression Parser\n\n").append("Example: ").append("\n").append("java -jar exp4j.jar \"2.12 * log(23) * (12 - 4)\"\n\n")
+                               .append("written by fas@congrace.de");
+               System.err.println(usage.toString());
+       }
+}
diff --git a/core/src/de/congrace/exp4j/CustomFunction.java b/core/src/de/congrace/exp4j/CustomFunction.java
new file mode 100644 (file)
index 0000000..f49f948
--- /dev/null
@@ -0,0 +1,90 @@
+package de.congrace.exp4j;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+
+import de.congrace.exp4j.FunctionToken.Function;
+
+/**
+ * this classed is used to create custom functions for exp4j<br/>
+ * <br/>
+ * <b>Example</b><br/>
+ * <code><pre>{@code 
+ * CustomFunction fooFunc = new CustomFunction("foo") {
+ *             public double applyFunction(double value) {
+ *                     return value*Math.E;
+ *             }
+ * };
+ * double varX=12d;
+ * Calculable calc = new ExpressionBuilder("foo(x)").withCustomFunction(fooFunc).withVariable("x",varX).build();
+ * assertTrue(calc.calculate() == Math.E * varX);
+ * }</pre></code>
+ * 
+ * @author ruckus
+ * 
+ */
+public abstract class CustomFunction extends CalculationToken {
+    private int argc=1;
+
+       /**
+        * create a new single value input CustomFunction with a set name
+        * 
+        * @param value
+        *            the name of the function (e.g. foo)
+        */
+       protected CustomFunction(String value) throws InvalidCustomFunctionException{
+               super(value);
+               for (Function f:Function.values()) {
+                       if (value.equalsIgnoreCase(f.toString())){
+                               throw new InvalidCustomFunctionException(value + " is already reserved as a function name");
+                       }
+               }
+       }
+
+    /**
+     * create a new single value input CustomFunction with a set name
+     * 
+     * @param value
+     *            the name of the function (e.g. foo)
+     */
+    protected CustomFunction(String value,int argumentCount) throws InvalidCustomFunctionException{
+        super(value);
+        this.argc=argumentCount;
+        for (Function f:Function.values()) {
+            if (value.equalsIgnoreCase(f.toString())){
+                throw new InvalidCustomFunctionException(value + " is already reserved as a function name");
+            }
+        }
+    }
+
+    /**
+        * apply the function to a value
+        * 
+        * @param values
+        *            the values to which the function should be applied.
+        * @return the function value
+        */
+       public abstract Variable applyFunction(List<Variable> vars);
+
+    @Override
+       void mutateStackForCalculation(Stack<Variable> stack, VariableSet variables) {
+           List<Variable> args = new ArrayList<Variable>(argc);
+           for (int i=0; i < argc; i++) {
+               args.add(i, stack.pop() );
+           }
+           Collections.reverse(args); // Put elements in logical order
+           
+               stack.push(this.applyFunction(args));
+       }
+
+       @Override
+       void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
+               operatorStack.push(this);
+       }
+       public int getArgumentCount() {
+           return argc;
+       }
+}
diff --git a/core/src/de/congrace/exp4j/Example.java b/core/src/de/congrace/exp4j/Example.java
new file mode 100644 (file)
index 0000000..0d70b0b
--- /dev/null
@@ -0,0 +1,77 @@
+package de.congrace.exp4j;
+
+import java.util.List;
+
+public class Example {
+
+       public static void main(String[] args) throws UnknownFunctionException, UnparsableExpressionException, InvalidCustomFunctionException {
+
+               // Test 1
+               // ======
+               
+               Calculable calc1 = new ExpressionBuilder("x * y - 2").withVariableNames("x", "y").build();
+               calc1.setVariable(new Variable("x", 1.2));
+               calc1.setVariable(new Variable("y", 2.2));
+               
+               System.out.println(calc1.calculate().toString());
+               //double result = calc1.calculate().getDoubleValue();
+               //System.out.println(result);
+                       
+               // Test 2
+               // ======
+               
+               // A function which calculates the mean of an array and scales it
+               CustomFunction meanFn = new CustomFunction("mean",2) {
+                   public Variable applyFunction(List<Variable> vars) {
+                       
+                       double[] vals;
+                       double scale;
+                       
+                       try{
+                               vals = vars.get(0).getArrayValue();
+                               scale = vars.get(1).getDoubleValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       
+                       double subtotal = 0;
+                       for (int i = 0; i < vals.length; i++ ){
+                               subtotal += vals[i];
+                       }
+                       
+                       subtotal = scale * subtotal / vals.length;
+                       return new Variable("double MEAN result, ", subtotal);
+                       
+                   }
+               };
+                               
+               ExpressionBuilder b = new ExpressionBuilder("mean(x,y)");
+               b.withCustomFunction(meanFn);
+               b.withVariable(new Variable("x", new double[] {1.1,2,10,3,2.4,10.2}));
+               b.withVariable(new Variable("y", 2));
+               Calculable calc2 = b.build();
+               
+               System.out.println( calc2.calculate().toString() );
+               
+               // Test 3
+               // ======
+               
+               Calculable calc3 = new ExpressionBuilder("x * y - 2").withVariableNames("x", "y").build();
+               calc3.setVariable(new Variable("x", new double[]{1.2, 10, 20, 15}));
+               calc3.setVariable(new Variable("y", new double[]{2.2, 5.2, 12, 9 }));
+               
+               //double result3 = calc3.calculate().getDoubleValue();
+               System.out.println(calc3.calculate().toString());
+               
+
+               // Test 4
+               // ======
+                               
+               Calculable calc4 = new ExpressionBuilder("log10(sqrt(x) * abs(y))").withVariableNames("x", "y").build();
+               calc4.setVariable(new Variable("x", new double[]{1.2, 10, 10, 15}));
+               calc4.setVariable(new Variable("y", new double[]{2.2, -5.2, 5.2, 9 }));
+               
+               //double result3 = calc3.calculate().getDoubleValue();
+               System.out.println(calc4.calculate().toString());               
+       }
+}
diff --git a/core/src/de/congrace/exp4j/ExpressionBuilder.java b/core/src/de/congrace/exp4j/ExpressionBuilder.java
new file mode 100644 (file)
index 0000000..8ecf1b5
--- /dev/null
@@ -0,0 +1,135 @@
+package de.congrace.exp4j;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * This is Builder implementation for the exp4j API used to create a Calculable
+ * instance for the user
+ * 
+ * @author ruckus
+ * 
+ */
+public class ExpressionBuilder {
+       private VariableSet variables = new VariableSet();
+       private final Set<CustomFunction> customFunctions = new HashSet<CustomFunction>();
+
+       private String expression;
+
+       /**
+        * Create a new ExpressionBuilder
+        * 
+        * @param expression
+        *            the expression to evaluate
+        */
+       public ExpressionBuilder(String expression) {
+               this.expression = expression;
+       }
+       
+       /**
+        * build a new {@link Calculable} from the expression using the supplied
+        * variables
+        * 
+        * @return the {@link Calculable} which can be used to evaluate the
+        *         expression
+        * @throws UnknownFunctionException
+        *             when an unrecognized function name is used in the expression
+        * @throws UnparsableExpressionException
+        *             if the expression could not be parsed
+        */
+       public Calculable build() throws UnknownFunctionException, UnparsableExpressionException {
+               if (expression.indexOf('=') == -1 && !variables.isEmpty()) {
+
+                       // User supplied an expression without leading "f(...)="
+                       // so we just append the user function to a proper "f()="
+                       // for PostfixExpression.fromInfix()
+                       StringBuilder function = new StringBuilder("f(");
+                       for (String name : variables.getVariableNames()) {
+                               function.append(name).append(',');
+                       }
+                       expression = function.deleteCharAt(function.length() - 1).toString() + ")=" + expression;
+               }
+               // create the PostfixExpression and return it as a Calculable
+               PostfixExpression delegate = PostfixExpression.fromInfix(expression, customFunctions);
+               for (Variable var : variables ) {                       
+                       delegate.setVariable(var);      
+                       for (CustomFunction fn:customFunctions){
+                               if (fn.getValue().equalsIgnoreCase(var.getName())){
+                                       throw new UnparsableExpressionException("variable '" + var + "' cannot have the same name as a custom function " + fn.getValue());
+                               }
+                       }
+               }
+               return delegate;
+       }
+
+       /**
+        * add a custom function instance for the evaluator to recognize
+        * 
+        * @param function
+        *            the {@link CustomFunction} to add
+        * @return the {@link ExpressionBuilder} instance
+        */
+       public ExpressionBuilder withCustomFunction(CustomFunction function) {
+               customFunctions.add(function);
+               return this;
+       }
+
+       public ExpressionBuilder withCustomFunctions(Collection<CustomFunction> functions) {
+               customFunctions.addAll(functions);
+               return this;
+       }
+
+       /**
+        * set the value for a variable
+        * 
+        * @param variableName
+        *            the variable name e.g. "x"
+        * @param value
+        *            the value e.g. 2.32d
+        * @return the {@link ExpressionBuilder} instance
+        */
+       public ExpressionBuilder withVariable(Variable value) {
+               variables.add(value);
+               return this;
+       }
+
+       /*
+        * Provided for backwards compatibility
+        */
+       @Deprecated
+       public ExpressionBuilder withVariable(String variableName, double value) {
+               variables.add(new Variable(variableName, value));
+               return this;
+       }
+               
+       /**
+        * set the variables names used in the expression without setting their
+        * values. Usefull for building an expression before you know the variable values.
+        * 
+        * @param variableNames
+        *            vararg {@link String} of the variable names used in the
+        *            expression
+        * @return the ExpressionBuilder instance
+        */
+       
+       public ExpressionBuilder withVariableNames(String... variableNames) {
+               for (String name : variableNames) {
+                       variables.add( new Variable(name, Double.NaN) );
+               }
+               return this;
+       }
+       
+
+       /**
+        * set the values for variables
+        * 
+        * @param variableMap
+        *            a map of variable names to variable values
+        * @return the {@link ExpressionBuilder} instance
+        */
+       public ExpressionBuilder withVariables(VariableSet variables) {
+               this.variables = variables;
+               return this;
+       }
+}
diff --git a/core/src/de/congrace/exp4j/FunctionSeparatorToken.java b/core/src/de/congrace/exp4j/FunctionSeparatorToken.java
new file mode 100644 (file)
index 0000000..24b1109
--- /dev/null
@@ -0,0 +1,17 @@
+package de.congrace.exp4j;
+
+import java.util.Stack;
+
+public class FunctionSeparatorToken extends Token{
+    public FunctionSeparatorToken() {
+        super(",");
+    }
+    @Override
+    void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
+        Token token;
+        while (!((token=operatorStack.peek()) instanceof ParenthesisToken) && !token.getValue().equals("(")){
+            output.append(operatorStack.pop().getValue()).append(" ");
+        }
+    }
+
+}
diff --git a/core/src/de/congrace/exp4j/FunctionToken.java b/core/src/de/congrace/exp4j/FunctionToken.java
new file mode 100644 (file)
index 0000000..6bc620c
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+Copyright 2011 frank asseg
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Stack;
+
+/**
+ * A {@link Token} for functions
+ * 
+ * @author fas@congrace.de
+ * 
+ */
+class FunctionToken extends CalculationToken {
+       /**
+        * the functionNames that can be used in an expression
+        * 
+        * @author ruckus
+        * 
+        */
+       enum Function {
+               ABS, ACOS, ASIN, ATAN, CBRT, CEIL, COS, COSH, EXP, EXPM1, FLOOR, ROUND, RANDOM, LOG, SIN, SINH, SQRT, TAN, TANH, LOG10
+       }
+
+       private Function function;
+
+       /**
+        * construct a new {@link FunctionToken}
+        * 
+        * @param value
+        *            the name of the function
+        * @throws UnknownFunctionException
+        *             if an unknown function name is encountered
+        */
+       FunctionToken(String value) throws UnknownFunctionException {
+               super(value);
+               try {
+                       function = Function.valueOf(value.toUpperCase());
+               } catch (IllegalArgumentException e) {
+                       throw new UnknownFunctionException(value);
+               }
+               if (function == null) {
+                       throw new UnknownFunctionException(value);
+               }
+       }
+
+       /**
+        * apply a function to a variable
+        * 
+        * @param x
+        *            the value the function should be applied to
+        * @return the result of the function
+        */
+       public Variable applyFunction(Variable var) {
+               
+               // The names here are strictly unused, but are useful for debugging
+               String name = function.name() + " result (#"+var.hashCode()+"), ";
+               
+               switch (var.getPrimary()) {
+                       case DOUBLE:
+                               name = "double "+name;
+                               double x = var.getDoubleValue();
+                               return new Variable(name, applyFunction(x) );   
+                       
+                       case ARRAY:
+                               name = "array "+name;
+                               double[] input = var.getArrayValue();
+                               double[] result = new double[input.length];
+                               for (int i = 0; i < input.length; i++){
+                                       result[i] = applyFunction(input[i]);
+                               }
+                               return new Variable(name, result);
+                       
+                       default:
+                               return new Variable("Invalid");
+               }
+       }
+       
+       /*
+        * The actual function application on a double
+        */
+       private double applyFunction(double x){
+               switch (function) {
+               case ABS:
+                       return Math.abs(x);
+               case ACOS:
+                       return Math.acos(x);
+               case ASIN:
+                       return Math.asin(x);
+               case ATAN:
+                       return Math.atan(x);
+               case CBRT:
+                       return Math.cbrt(x);
+               case CEIL:
+                       return Math.ceil(x);
+               case COS:
+                       return Math.cos(x);
+               case COSH:
+                       return Math.cosh(x);
+               case EXP:
+                       return Math.exp(x);
+               case EXPM1:
+                       return Math.expm1(x);
+               case FLOOR:
+                       return Math.floor(x);
+               case ROUND:
+                       return Math.round(x);
+               case RANDOM:
+                       return Math.random()*x;
+               case LOG:
+                       return Math.log(x);
+               case LOG10:
+                       return Math.log10(x);
+               case SIN:
+                       return Math.sin(x);
+               case SINH:
+                       return Math.sinh(x);
+               case SQRT:
+                       return Math.sqrt(x);
+               case TAN:
+                       return Math.tan(x);
+               case TANH:
+                       return Math.tanh(x);
+               default:
+                       return Double.NaN; // should not happen ;)
+               }
+       }
+
+       /**
+        * 
+        * get the {@link Function}
+        * 
+        * @return the correspoding {@link Function}
+        */
+       Function getFunction() {
+               return function;
+       }
+
+       @Override
+       void mutateStackForCalculation(Stack<Variable> stack, VariableSet variableValues) {
+               stack.push(this.applyFunction(stack.pop()));
+       }
+
+       @Override
+       void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
+               operatorStack.push(this);
+       }
+}
diff --git a/core/src/de/congrace/exp4j/InfixTranslator.java b/core/src/de/congrace/exp4j/InfixTranslator.java
new file mode 100644 (file)
index 0000000..9712bce
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Translate a mathematical expression in human readable infix notation to a
+ * Reverse Polish Notation (postfix) expression for easier parsing. by
+ * implementing the shunting yard algorithm by dijkstra
+ * 
+ * @author fas@congrace.de
+ */
+class InfixTranslator {
+
+       private static String substituteUnaryOperators(String expr) {
+               final StringBuilder exprBuilder = new StringBuilder(expr.length());
+               final char[] data = expr.toCharArray();
+               char lastChar = ' ';
+               for (int i = 0; i < expr.length(); i++) {
+                       if (exprBuilder.length() > 0) {
+                               lastChar = exprBuilder.charAt(exprBuilder.length() - 1);
+                       }
+                       final char c = data[i];
+                       switch (c) {
+                       case '+':
+                               if (i > 0 && lastChar != '(' && !(OperatorToken.isOperator(lastChar))) {
+                                       exprBuilder.append(c);
+                               }
+                               break;
+                       case '-':
+                               if (i > 0 && lastChar != '(' && !(OperatorToken.isOperator(lastChar))) {
+                                       exprBuilder.append(c);
+                               } else {
+                                       exprBuilder.append('#');
+                               }
+                               break;
+                       default:
+                               if (!Character.isWhitespace(c)) {
+                                       exprBuilder.append(c);
+                               }
+                       }
+               }
+               return exprBuilder.toString();
+       }
+
+       /**
+        * Delegation method for simple expression without variables or custom
+        * functions
+        * 
+        * @param infixExpression
+        *            the infix expression to be translated
+        * @return translated RNP postfix expression
+        * @throws UnparsableExpressionException
+        *             when the expression is invalid
+        * @throws UnknownFunctionException
+        *             when an unknown function has been used in the input.
+        */
+       static String toPostfixExpression(String infixExpression) throws UnparsableExpressionException, UnknownFunctionException {
+               return toPostfixExpression(infixExpression, null, null);
+       }
+
+       /**
+        * implement the shunting yard algorithm
+        * 
+        * @param infixExpression
+        *            the human readable expression which should be translated to
+        *            RPN
+        * @param variableNames
+        *            the variable names used in the expression
+        * @param customFunctions
+        *            the CustomFunction implementations used
+        * @return the expression in postfix format
+        * @throws UnparsableExpressionException
+        *             if the expression could not be translated to RPN
+        * @throws UnknownFunctionException
+        *             if an unknown function was encountered
+        */
+       static String toPostfixExpression(String infixExpression, String[] variableStrings, Set<CustomFunction> customFunctions)
+                       throws UnparsableExpressionException, UnknownFunctionException {
+               infixExpression = substituteUnaryOperators(infixExpression);
+               final Token[] tokens = new Tokenizer(variableStrings, customFunctions).tokenize(infixExpression);
+               final StringBuilder output = new StringBuilder(tokens.length);
+               final Stack<Token> operatorStack = new Stack<Token>();
+               for (final Token token : tokens) {
+                       token.mutateStackForInfixTranslation(operatorStack, output);
+               }
+               // all tokens read, put the rest of the operations on the output;
+               while (operatorStack.size() > 0) {
+                       output.append(operatorStack.pop().getValue()).append(" ");
+               }
+               return output.toString().trim();
+       }
+}
diff --git a/core/src/de/congrace/exp4j/InvalidCustomFunctionException.java b/core/src/de/congrace/exp4j/InvalidCustomFunctionException.java
new file mode 100644 (file)
index 0000000..e3810db
--- /dev/null
@@ -0,0 +1,9 @@
+package de.congrace.exp4j;
+
+public class InvalidCustomFunctionException extends Exception{
+       private static final long serialVersionUID = 1L;
+
+       public InvalidCustomFunctionException(String message) {
+               super(message);
+       }
+}
diff --git a/core/src/de/congrace/exp4j/NumberToken.java b/core/src/de/congrace/exp4j/NumberToken.java
new file mode 100644 (file)
index 0000000..b765d45
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * A {@link Token} for Numbers
+ * 
+ * @author fas@congrace.de
+ * 
+ */
+class NumberToken extends CalculationToken {
+
+       private final double doubleValue;
+
+       /**
+        * construct a new {@link NumberToken}
+        * 
+        * @param value
+        *            the value of the number as a {@link String}
+        */
+       NumberToken(String value) {
+               super(value);
+               this.doubleValue = Double.parseDouble(value);
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof NumberToken) {
+                       final NumberToken t = (NumberToken) obj;
+                       return t.getValue().equals(this.getValue());
+               }
+               return false;
+       }
+
+       @Override
+       public int hashCode() {
+               return getValue().hashCode();
+       }
+
+       @Override
+       void mutateStackForCalculation(Stack<Variable> stack, VariableSet variables) {
+               stack.push(new Variable("From number "+getValue()+" : "+hashCode(), this.doubleValue));
+       }
+
+       @Override
+       void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
+               output.append(this.getValue()).append(' ');
+       }
+}
diff --git a/core/src/de/congrace/exp4j/OperatorToken.java b/core/src/de/congrace/exp4j/OperatorToken.java
new file mode 100644 (file)
index 0000000..765f450
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Stack;
+
+/**
+ * {@link Token} for Operations like +,-,*,/,% and ^
+ * 
+ * @author fas@congrace.de
+ */
+class OperatorToken extends CalculationToken {
+
+       /**
+        * the valid {@link Operation}s for the {@link OperatorToken}
+        * 
+        * @author fas@congrace.de
+        */
+       enum Operation {
+               ADDITION(1, true), SUBTRACTION(1, true), MULTIPLICATION(2, true), DIVISION(2, true), MODULO(2, true), EXPONENTIATION(3, false), UNARY_MINUS(4, false), UNARY_PLUS(
+                               4, false);
+               private final int precedence;
+               private final boolean leftAssociative;
+
+               private Operation(int precedence, boolean leftAssociative) {
+                       this.precedence = precedence;
+                       this.leftAssociative = leftAssociative;
+               }
+       }
+
+       /**
+        * return a corresponding {@link Operation} for a symbol
+        * 
+        * @param c
+        *            the symbol of the operation
+        * @return the corresponding {@link Operation}
+        */
+       static Operation getOperation(char c) {
+               switch (c) {
+               case '+':
+                       return Operation.ADDITION;
+               case '-':
+                       return Operation.SUBTRACTION;
+               case '*':
+                       return Operation.MULTIPLICATION;
+               case '/':
+                       return Operation.DIVISION;
+               case '^':
+                       return Operation.EXPONENTIATION;
+               case '#':
+                       return Operation.UNARY_MINUS;
+               case '%':
+                       return Operation.MODULO;
+               default:
+                       return null;
+               }
+       }
+
+       static boolean isOperator(char c) {
+               return getOperation(c) != null;
+       }
+
+       private final Operation operation;
+
+       /**
+        * construct a new {@link OperatorToken}
+        * 
+        * @param value
+        *            the symbol (e.g.: '+')
+        * @param operation
+        *            the {@link Operation} of this {@link Token}
+        */
+       OperatorToken(String value, Operation operation) {
+               super(value);
+               this.operation = operation;
+       }
+       
+       /**
+        * apply the {@link Operation}
+        * 
+        * @param values
+        *            the doubles to operate on
+        * @return the result of the {@link Operation}
+        * @throws UnparsableExpressionException 
+        */
+       public Variable applyOperation(Variable... values) {
+               
+               values = expandVariables(values);
+               
+               double[] inputs = new double[values.length];
+               switch (values[0].getPrimary()){
+                       
+                       case DOUBLE:
+                               for (int i = 0; i<values.length; i++){
+                                       inputs[i] = values[i].getDoubleValue();
+                               }
+                               double result = applyOperation(inputs);
+                               return new Variable("double " + operation.name()+" result, ", result);
+                       
+                       case ARRAY:
+                               int maxLength = values[0].getArrayValue().length;
+                               double[] results = new double[maxLength];
+                               for (int i = 0; i< maxLength; i++){
+                                       // assemble the array of input values
+                                       for (int j = 0; j<values.length; j++){
+                                               inputs[j] = values[j].getArrayValue()[i];
+                                       }
+                                       results[i] = applyOperation(inputs);
+                               }
+                               //System.out.println("Done applying operation "+operation.name());
+                               return new Variable("array " + operation.name()+" result, ", results);
+                               
+                       default:
+                               return new Variable("Invalid");
+               }
+       }
+       
+       private double applyOperation(double[] values){
+                               
+               //System.out.println("Applying "+operation.toString()+" to values starting "+values[0]);
+               
+               switch (operation) {
+               case ADDITION:
+                       return values[0] + values[1];
+               case SUBTRACTION:
+                       return values[0] - values[1];
+               case MULTIPLICATION:
+                       return values[0] * values[1];
+               case EXPONENTIATION:
+                       return Math.pow(values[0], values[1]);
+               case DIVISION:
+                       return values[0] / values[1];
+               case UNARY_MINUS:
+                       return -values[0];
+               case UNARY_PLUS:
+                       return values[0];
+               case MODULO:
+                       return values[0] % values[1];
+               default:
+                       return 0;
+               }
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof OperatorToken) {
+                       final OperatorToken t = (OperatorToken) obj;
+                       return t.getValue().equals(this.getValue());
+               }
+               return false;
+       }
+
+       int getOperandCount() {
+               switch (operation) {
+               case ADDITION:
+               case SUBTRACTION:
+               case MULTIPLICATION:
+               case DIVISION:
+               case EXPONENTIATION:
+               case MODULO:
+                       return 2;
+               case UNARY_MINUS:
+               case UNARY_PLUS:
+                       return 1;
+               default:
+                       return 0;
+               }
+       }
+
+       /**
+        * get the {@link Operation} of this {@link Token}
+        * 
+        * @return the {@link Operation}
+        */
+       Operation getOperation() {
+               return operation;
+       }
+
+       int getPrecedence() {
+               return operation.precedence;
+       }
+
+       @Override
+       public int hashCode() {
+               return getValue().hashCode();
+       }
+
+       /**
+        * check if the operation is left associative
+        * 
+        * @return true if left associative, otherwise false
+        */
+       boolean isLeftAssociative() {
+               return operation.leftAssociative;
+       }
+
+       @Override
+       void mutateStackForCalculation(Stack<Variable> stack, VariableSet variables) {
+               if (this.getOperandCount() == 2) {
+                       final Variable n2 = stack.pop();
+                       final Variable n1 = stack.pop();
+                       stack.push(this.applyOperation(n1, n2));
+               } else if (this.getOperandCount() == 1) {
+                       final Variable n1 = stack.pop();
+                       stack.push(this.applyOperation(n1));
+               }
+       }
+
+       @Override
+       void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
+               Token before;
+               while (!operatorStack.isEmpty() && (before = operatorStack.peek()) != null && (before instanceof OperatorToken || before instanceof FunctionToken)) {
+                       if (before instanceof FunctionToken) {
+                               operatorStack.pop();
+                               output.append(before.getValue()).append(" ");
+                       } else {
+                               final OperatorToken stackOperator = (OperatorToken) before;
+                               if (this.isLeftAssociative() && this.getPrecedence() <= stackOperator.getPrecedence()) {
+                                       output.append(operatorStack.pop().getValue()).append(" ");
+                               } else if (!this.isLeftAssociative() && this.getPrecedence() < stackOperator.getPrecedence()) {
+                                       output.append(operatorStack.pop().getValue()).append(" ");
+                               } else {
+                                       break;
+                               }
+                       }
+               }
+               operatorStack.push(this);
+       }
+}
diff --git a/core/src/de/congrace/exp4j/ParenthesisToken.java b/core/src/de/congrace/exp4j/ParenthesisToken.java
new file mode 100644 (file)
index 0000000..ad8ab0f
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Stack;
+
+/**
+ * Token for parenthesis
+ * 
+ * @author fas@congrace.de
+ */
+class ParenthesisToken extends Token {
+
+       ParenthesisToken(String value) {
+               super(value);
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (obj instanceof ParenthesisToken) {
+                       final ParenthesisToken t = (ParenthesisToken) obj;
+                       return t.getValue().equals(this.getValue());
+               }
+               return false;
+       }
+
+       @Override
+       public int hashCode() {
+               return getValue().hashCode();
+       }
+
+       /**
+        * check the direction of the parenthesis
+        * 
+        * @return true if it's a left parenthesis (open) false if it is a right
+        *         parenthesis (closed)
+        */
+       boolean isOpen() {
+               return getValue().equals("(") || getValue().equals("[") || getValue().equals("{");
+       }
+
+       @Override
+       void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
+               if (this.isOpen()) {
+                       operatorStack.push(this);
+               } else {
+                       Token next;
+                       while ((next = operatorStack.peek()) instanceof OperatorToken || next instanceof FunctionToken || next instanceof CustomFunction
+                                       || (next instanceof ParenthesisToken && !((ParenthesisToken) next).isOpen())) {
+                               output.append(operatorStack.pop().getValue()).append(" ");
+                       }
+                       operatorStack.pop();
+               }
+       }
+}
diff --git a/core/src/de/congrace/exp4j/PostfixExpression.java b/core/src/de/congrace/exp4j/PostfixExpression.java
new file mode 100644 (file)
index 0000000..0bbcc14
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Class for calculating values from a RPN postfix expression.<br/>
+ * The default way to create a new instance of {@link PostfixExpression} is by
+ * using the static factory method fromInfix()
+ * 
+ * @author fas@congrace.de
+ */
+public final class PostfixExpression extends AbstractExpression implements Calculable {
+       
+       private VariableSet variables = new VariableSet();
+       
+       /**
+        * Factory method for creating {@link PostfixExpression}s from human
+        * readable infix expressions
+        * 
+        * @param expression
+        *            the infix expression to be used
+        * @return an equivalent {@link PostfixExpression}
+        * @throws UnparsableExpressionException
+        *             if the expression was invalid
+        * @throws UnknownFunctionException
+        *             if an unknown function has been used
+        * @deprecated please use {@link ExpressionBuilder} API
+        */
+    @Deprecated
+       public static PostfixExpression fromInfix(String expression) throws UnparsableExpressionException, UnknownFunctionException {
+               return fromInfix(expression, null);
+       }
+
+       /**
+        * Factory method for creating {@link PostfixExpression}s from human
+        * readable infix expressions
+        * 
+        * @param expression
+        *            the infix expression to be used
+        * @param customFunctions
+        *            the CustomFunction implementations used
+        * @return an equivalent {@link PostfixExpression}
+        * @throws UnparsableExpressionException
+        *             if the expression was invalid
+        * @throws UnknownFunctionException
+        *             if an unknown function has been used
+        * @deprecated please use {@link ExpressionBuilder}
+        */
+    @Deprecated
+       public static PostfixExpression fromInfix(String expression, Set<CustomFunction> customFunctions) throws UnparsableExpressionException,
+                       UnknownFunctionException {
+               String[] variableStrings = null;
+               int posStart, posEnd;
+               if ((posStart = expression.indexOf('=')) > 0) {
+                       String functionDef = expression.substring(0, posStart);
+                       expression = expression.substring(posStart + 1);
+                       if ((posStart = functionDef.indexOf('(')) > 0 && (posEnd = functionDef.indexOf(')')) > 0) {
+                               variableStrings = functionDef.substring(posStart + 1, posEnd).split(",");
+                       }
+               }
+               return new PostfixExpression(InfixTranslator.toPostfixExpression(expression, variableStrings, customFunctions), variableStrings, customFunctions);
+       }
+       
+       /**
+        * Construct a new simple {@link PostfixExpression}
+        * 
+        * @param expression
+        *            the postfix expression to be calculated
+        * @param variableNames
+        *            the variable names in the expression
+        * @param customFunctions
+        *            the CustomFunction implementations used
+        * @throws UnparsableExpressionException
+        *             when expression is invalid
+        * @throws UnknownFunctionException
+        *             when an unknown function has been used
+        */
+       private PostfixExpression(String expression, String[] variableStrings, Set<CustomFunction> customFunctions) throws UnparsableExpressionException,
+                       UnknownFunctionException {
+               super(expression, new Tokenizer(variableStrings, customFunctions).tokenize(expression), variableStrings);
+       }
+
+       /**
+        * delegate the calculation of a simple expression 
+        */
+       public Variable calculate() throws IllegalArgumentException {
+
+               final Stack<Variable> stack = new Stack<Variable>();
+               for (final Token t : getTokens()) {
+                       ((CalculationToken) t).mutateStackForCalculation(stack, variables);
+               }
+               return stack.pop();
+
+       }
+
+       public void setVariable(Variable value) {
+               variables.add(value);
+       }
+}
diff --git a/core/src/de/congrace/exp4j/Token.java b/core/src/de/congrace/exp4j/Token.java
new file mode 100644 (file)
index 0000000..2ce4030
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Stack;
+
+/**
+ * Superclass for tokenized Strings
+ * 
+ * @author fas@congrace.de
+ */
+abstract class Token {
+       private final String value;
+
+       /**
+        * construct a new {@link Token}
+        * 
+        * @param value
+        *            the value of the {@link Token}
+        */
+       Token(String value) {
+               super();
+               this.value = value;
+       }
+
+       /**
+        * get the value (String representation) of the token
+        * 
+        * @return the value
+        */
+       String getValue() {
+               return value;
+       }
+
+       abstract void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output);
+}
diff --git a/core/src/de/congrace/exp4j/Tokenizer.java b/core/src/de/congrace/exp4j/Tokenizer.java
new file mode 100644 (file)
index 0000000..c2c99d9
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import de.congrace.exp4j.FunctionToken.Function;
+
+/**
+ * Class for tokenizing mathematical expressions by breaking an expression up
+ * into multiple different {@link Token}s
+ * 
+ * @author fas@congrace.de
+ */
+class Tokenizer {
+       private String[] variableNames;
+       private final Set<String> functionNames = new HashSet<String>();
+       private final Set<CustomFunction> customFunctions;
+
+       {
+               functionNames.add("abs");
+               functionNames.add("acos");
+               functionNames.add("asin");
+               functionNames.add("atan");
+               functionNames.add("cbrt");
+               functionNames.add("ceil");
+               functionNames.add("cos");
+               functionNames.add("cosh");
+               functionNames.add("exp");
+               functionNames.add("expm1");
+               functionNames.add("floor");
+               functionNames.add("log");
+               functionNames.add("sin");
+               functionNames.add("sinh");
+               functionNames.add("sqrt");
+               functionNames.add("tan");
+               functionNames.add("tanh");
+       }
+
+       Tokenizer() {
+               super();
+               customFunctions = null;
+       }
+
+       /**
+        * construct a new Tokenizer that recognizes variable names
+        * 
+        * @param variableNames
+        *            the variable names in the expression
+        * @throws IllegalArgumentException
+        *             if a variable has the name as a function
+        * @param customFunctions
+        *            the CustomFunction implementations used if the variableNames
+        *            are not valid
+        */
+       Tokenizer(String[] variableNames, Set<CustomFunction> customFunctions) throws IllegalArgumentException {
+               super();                
+               this.variableNames = variableNames;
+                               
+               if (variableNames != null) {
+                       for (String varName : variableNames) {
+                               if (functionNames.contains(varName.toLowerCase())) {
+                                       throw new IllegalArgumentException("Variable '" + varName + "' can not have the same name as a function");
+                               }
+                       }
+               }
+               this.customFunctions = customFunctions;
+       }
+
+       private Token getCustomFunctionToken(String name) throws UnknownFunctionException {
+               for (CustomFunction func : customFunctions) {
+                       if (func.getValue().equals(name)) {
+                               return func;
+                       }
+               }
+               throw new UnknownFunctionException(name);
+       }
+
+       private boolean isCustomFunction(String name) {
+               if (customFunctions == null) {
+                       return false;
+               }
+               for (CustomFunction func : customFunctions) {
+                       if (func.getValue().equals(name)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * check if a char is part of a number
+        * 
+        * @param c
+        *            the char to be checked
+        * @return true if the char is part of a number
+        */
+       private boolean isDigit(char c) {
+               return Character.isDigit(c) || c == '.';
+       }
+
+       private boolean isFunction(String name) {
+               for (Function fn : Function.values()) {
+                       if (fn.name().equals(name.toUpperCase())) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * check if a String is a variable name
+        * 
+        * @param name
+        *            the variable name which is checked to be valid the char to be
+        *            checked
+        * @return true if the char is a variable name (e.g. x)
+        */
+       private boolean isVariable(String name) {
+               //String[] variableNames = variables.getVariableNames();
+               
+               if (variableNames != null) {
+                       for (String var : variableNames) {
+                               if (name.equals(var)) {
+                                       return true;
+                               }
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * tokenize an infix expression by breaking it up into different
+        * {@link Token} that can represent operations,functions,numbers,
+        * parenthesis or variables
+        * 
+        * @param infix
+        *            the infix expression to be tokenized
+        * @return the {@link Token}s representing the expression
+        * @throws UnparsableExpressionException
+        *             when the expression is invalid
+        * @throws UnknownFunctionException
+        *             when an unknown function name has been used.
+        */
+       Token[] tokenize(String infix) throws UnparsableExpressionException, UnknownFunctionException {
+               final List<Token> tokens = new ArrayList<Token>();
+               final char[] chars = infix.toCharArray();
+               // iterate over the chars and fork on different types of input
+               Token lastToken;
+               for (int i = 0; i < chars.length; i++) {
+                       char c = chars[i];
+                       
+                       if (c == ' ')
+                               continue;
+                       if (isDigit(c)) {
+                               final StringBuilder valueBuilder = new StringBuilder(1);
+                               // handle the numbers of the expression
+                               valueBuilder.append(c);
+                               int numberLen = 1;
+                               while (chars.length > i + numberLen && isDigit(chars[i + numberLen])) {
+                                       valueBuilder.append(chars[i + numberLen]);
+                                       numberLen++;
+                               }
+                               i += numberLen - 1;
+                               lastToken = new NumberToken(valueBuilder.toString());
+                       } else if (Character.isLetter(c) || c == '_' || c == '$') {                             
+                               // can be a variable or function
+                               final StringBuilder nameBuilder = new StringBuilder();
+                               nameBuilder.append(c);
+                               int offset = 1;
+                               while (chars.length > i + offset && (Character.isLetter(chars[i + offset]) || Character.isDigit(chars[i + offset]) || chars[i + offset] == '_' || chars[i + offset] == '$')) {
+                                       nameBuilder.append(chars[i + offset++]);
+                               }
+                               String name = nameBuilder.toString();
+                               if (this.isVariable(name)) {
+                                       // a variable
+                                       i += offset - 1;
+                                       lastToken = new VariableToken(name);
+                               } else if (this.isFunction(name)) {
+                                       // might be a function
+                                       i += offset - 1;
+                                       lastToken = new FunctionToken(name);
+                               } else if (this.isCustomFunction(name)) {
+                                       // a custom function
+                                       i += offset - 1;
+                                       lastToken = getCustomFunctionToken(name);
+                               } else {
+                                       // an unknown symbol was encountered
+                                       throw new UnparsableExpressionException(c, i);
+                               }
+                       }else if (c == ',') {
+                           // a function separator, hopefully
+                           lastToken=new FunctionSeparatorToken();
+                       } else if (OperatorToken.isOperator(c)) {
+                               lastToken = new OperatorToken(String.valueOf(c), OperatorToken.getOperation(c));
+                       } else if (c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c == '}') {
+                               lastToken = new ParenthesisToken(String.valueOf(c));
+                       } else {
+                               // an unknown symbol was encountered
+                               throw new UnparsableExpressionException(c, i);
+                       }
+                       tokens.add(lastToken);
+               }
+               return tokens.toArray(new Token[tokens.size()]);
+       }
+}
diff --git a/core/src/de/congrace/exp4j/UnknownFunctionException.java b/core/src/de/congrace/exp4j/UnknownFunctionException.java
new file mode 100644 (file)
index 0000000..ae35093
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+/**
+ * Exception for handling unknown Functions.
+ * 
+ * @see FunctionToken
+ * @author fas@congrace.de
+ */
+public class UnknownFunctionException extends Exception {
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * construct a new {@link UnknownFunctionException}
+        * 
+        * @param functionName
+        *            the function name which could not be found
+        */
+       public UnknownFunctionException(String functionName) {
+               super("Unknown function: " + functionName);
+       }
+}
diff --git a/core/src/de/congrace/exp4j/UnparsableExpressionException.java b/core/src/de/congrace/exp4j/UnparsableExpressionException.java
new file mode 100644 (file)
index 0000000..fcbf7da
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+/**
+ * Exception for invalid expressions
+ * 
+ * @author fas@congrace.de
+ */
+public class UnparsableExpressionException extends Exception {
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * construct a new {@link UnparsableExpressionException}
+        * 
+        * @param c
+        *            the character which could not be parsed
+        * @param pos
+        *            the position of the character in the expression
+        */
+       public UnparsableExpressionException(char c, int pos) {
+               super("Unable to parse character at position " + pos + ": '" + String.valueOf(c) + "'");
+       }
+       /**
+        * construct a new {@link UnparsableExpressionException}
+        * 
+        * @param msg 
+        *            the error message
+        */
+       public UnparsableExpressionException(String msg) {
+               super(msg);
+       }
+}
diff --git a/core/src/de/congrace/exp4j/Variable.java b/core/src/de/congrace/exp4j/Variable.java
new file mode 100644 (file)
index 0000000..0030e70
--- /dev/null
@@ -0,0 +1,107 @@
+package de.congrace.exp4j;
+
+/*
+ * Represents a generic variable which can have double or array values.
+ * Optionally the start and step values corresponding to each array index can be specified for array values
+ * Tries to do something sensible if you try and apply a regular function / operator to an array
+ * and vice-versa.
+ */
+public class Variable {
+       
+       // The primary or preferred representation 
+       public enum Primary {DOUBLE, ARRAY, PLACEHOLDER};
+       private final Primary primary;
+       
+       private final String name;
+       
+       private final double doubleValue;  
+       private final double[] arrayValue; 
+       
+       private final double start, step;
+       
+       /*
+        * Initialize a new variable with a name only. This can be used as a place holder
+        */
+       public Variable(String name){
+               this.name = name;
+               this.primary = Primary.PLACEHOLDER;
+               this.doubleValue = Double.NaN;
+               this.arrayValue = new double[] {Double.NaN};
+               this.start = Double.NaN;
+               this.step = Double.NaN;
+       }
+       
+       /*
+        * Initialize a new double variable
+        */
+       public Variable(String name, double d){
+               this.doubleValue = d;
+               this.arrayValue = new double[] {d};
+               this.name = name;
+               this.primary = Primary.DOUBLE;
+               this.start = Double.NaN;
+               this.step = Double.NaN;
+       }
+       
+       /*
+        * Initialize a new array variable
+        */
+       public Variable(String name, double[] d){
+               this.arrayValue = d;
+               this.doubleValue = d[0];
+               this.name = name;
+               this.primary = Primary.ARRAY;
+               this.start = Double.NaN;
+               this.step = Double.NaN;
+       }
+       
+       /*
+        * Initialize a new array variable, specifying the start and step values
+        */
+       public Variable(String name, double[] d, double start, double step){
+               this.arrayValue = d;
+               this.doubleValue = d[0];
+               this.name = name;
+               this.primary = Primary.ARRAY;
+               this.start = start;
+               this.step = step;
+       }
+       
+       public String getName(){
+               return name;
+       }
+       
+       public Primary getPrimary(){
+               return this.primary;
+       }
+       
+       public double getDoubleValue(){
+               return doubleValue;
+       }
+       
+       public double[] getArrayValue(){
+               return arrayValue;
+       }
+       
+       public double getStep(){
+               return step;
+       }
+       
+       public double getStart(){
+               return start;
+       }
+       
+       public String toString(){
+               if ( arrayValue.length > 1 ){
+                       String out = name + " is Array (length " + new Integer(arrayValue.length).toString() + ") : {";
+                       for (double x : arrayValue){
+                               out = out + x + ",";
+                       }
+                       out = out.substring(0, out.length()-1);
+                       return out + "}";
+               }
+               else{
+                       return name + " is double : {" + new Double(doubleValue).toString() + "}";
+               }
+       }
+}
\ No newline at end of file
diff --git a/core/src/de/congrace/exp4j/VariableSet.java b/core/src/de/congrace/exp4j/VariableSet.java
new file mode 100644 (file)
index 0000000..f567006
--- /dev/null
@@ -0,0 +1,42 @@
+package de.congrace.exp4j;
+
+import java.util.HashSet;
+
+public class VariableSet extends HashSet<Variable> {
+
+       /**
+        * 
+        */
+       private static final long serialVersionUID = -4212803364398351279L;
+
+       public boolean add(Variable v){
+               Variable previous = getVariableNamed(v.getName());
+               if ( previous != null ){
+                       this.remove( previous );
+               }
+                       
+               return super.add(v);
+       }
+       
+       public Variable getVariableNamed(String name){
+               for (Variable var : this){
+                       if (var.getName().equals(name) ){
+                               return var;
+                       }
+               }
+               return null;
+       }
+       
+       public String[] getVariableNames(){
+               if (this.size() == 0){
+                       return null;
+               }
+               String names[] = new String[this.size()];
+               int i = 0;
+               for (Variable var : this){
+                       names[i] = var.getName();
+                       i++;
+               }
+               return names;
+       }       
+}
diff --git a/core/src/de/congrace/exp4j/VariableToken.java b/core/src/de/congrace/exp4j/VariableToken.java
new file mode 100644 (file)
index 0000000..716ef2e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+   Copyright 2011 frank asseg
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+package de.congrace.exp4j;
+
+import java.util.Stack;
+
+/**
+ * A {@link Token} for representing variables
+ * 
+ * @author fas
+ */
+class VariableToken extends CalculationToken {
+       /**
+        * construct a new {@link VariableToken}
+        * 
+        * @param value
+        *            the value of the token
+        */
+       VariableToken(String value) {
+               super(value);
+       }
+
+       @Override
+       void mutateStackForCalculation(Stack<Variable> stack, VariableSet variableValues) {
+               Variable value = variableValues.getVariableNamed(this.getValue());
+               stack.push(value);
+       }
+
+       @Override
+       void mutateStackForInfixTranslation(Stack<Token> operatorStack, StringBuilder output) {
+               output.append(this.getValue()).append(" ");
+       }
+}
index 56c65a3a4c53535a328b2870217ad9cb57bb4f33..363606d722c7984a446b191842ceb0d452640083 100644 (file)
@@ -102,6 +102,7 @@ public abstract class Warning {
                private double length = Double.NaN;
                private double delay = Double.NaN;
 
+               @Override
                public String toString() {
                        String str = "No motor with designation '" + designation + "'";
                        if (manufacturer != null)
@@ -315,4 +316,13 @@ public abstract class Warning {
        //// Invalid parameter encountered, ignoring.
        public static final Warning FILE_INVALID_PARAMETER =
                new Other(trans.get("Warning.FILE_INVALID_PARAMETER"));
+
+       public static final Warning PARALLEL_FINS =
+               new Other(trans.get("Warning.PARALLEL_FINS"));
+       
+       public static final Warning SUPERSONIC =
+               new Other(trans.get("Warning.SUPERSONIC"));
+
+       public static final Warning RECOVERY_LAUNCH_ROD =
+               new Other(trans.get("Warning.RECOVERY_LAUNCH_ROD"));
 }
index bd8ee75e52f80985be18967b8feb631c0edfc6da..96abf7a627694bd331bab37fbda70c5d6843a1cf 100644 (file)
@@ -163,7 +163,7 @@ public class FinSetCalc extends RocketComponentCalc {
                default:
                        // Assume 75% efficiency
                        cna *= 0.75;
-                       warnings.add("Too many parallel fins");
+                       warnings.add(Warning.PARALLEL_FINS);
                        break;
                }
                
index 23178a33b8a58d822f3f9e559541efd355ab7275..458cbe1973b660c9b5f4b36972f35ecd4e162626 100644 (file)
@@ -5,6 +5,7 @@ import static net.sf.openrocket.util.MathUtil.pow2;
 import net.sf.openrocket.aerodynamics.AerodynamicForces;
 import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
 import net.sf.openrocket.aerodynamics.FlightConditions;
+import net.sf.openrocket.aerodynamics.Warning;
 import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.rocketcomponent.BodyTube;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
@@ -140,7 +141,7 @@ public class SymmetricComponentCalc extends RocketComponentCalc {
 
                // Add warning on supersonic flight
                if (conditions.getMach() > 1.1) {
-                       warnings.add("Body calculations may not be entirely accurate at supersonic speeds.");
+                       warnings.add(Warning.SUPERSONIC);
                }
                
        }
index 7b526f2c484b78bb2c58e9f369b4e10eedaa32a2..316f313cc70f33d3edbb877900c8aaabd1c53901 100644 (file)
@@ -1,12 +1,13 @@
 package net.sf.openrocket.arch;
 
 import java.io.File;
+import java.util.Locale;
 
 import net.sf.openrocket.util.BugException;
 
 public class SystemInfo {
        
-
+       
        /**
         * Enumeration of supported operating systems.
         * 
@@ -26,7 +27,7 @@ public class SystemInfo {
         * @return      the operating system of the current system.
         */
        public static Platform getPlatform() {
-               String os = System.getProperty("os.name").toLowerCase();
+               String os = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
                
                if (os.indexOf("win") >= 0) {
                        return Platform.WINDOWS;
@@ -41,8 +42,8 @@ public class SystemInfo {
        }
        
        
-
-
+       
+       
        /**
         * Return the application data directory of this user.  The location depends
         * on the current platform.
index 3122f0859c310b68e6000c685d29e00a101a4f1a..799c2a3dff512d1e07304a87e9e1d22f6a8ed242 100644 (file)
@@ -28,6 +28,7 @@ public class UpdateInfoRetriever {
         */
        public void start() {
                fetcher = new UpdateInfoFetcher();
+               fetcher.setName("UpdateInfoFetcher");
                fetcher.setDaemon(true);
                fetcher.start();
        }
@@ -67,7 +68,7 @@ public class UpdateInfoRetriever {
        }
        
        
-
+       
        /**
         * Parse the data received from the server.
         * 
@@ -84,7 +85,7 @@ public class UpdateInfoRetriever {
                        reader = new BufferedReader(r);
                }
                
-
+               
                String version = null;
                ArrayList<ComparablePair<Integer, String>> updates =
                                new ArrayList<ComparablePair<Integer, String>>();
@@ -113,7 +114,7 @@ public class UpdateInfoRetriever {
        }
        
        
-
+       
        /**
         * An asynchronous task that fetches and parses the update info.
         * 
@@ -183,7 +184,7 @@ public class UpdateInfoRetriever {
                                
                                String contentType = connection.getContentType();
                                if (contentType == null ||
-                                               contentType.toLowerCase().indexOf(Communicator.UPDATE_INFO_CONTENT_TYPE) < 0) {
+                                               contentType.toLowerCase(Locale.ENGLISH).indexOf(Communicator.UPDATE_INFO_CONTENT_TYPE) < 0) {
                                        // Unknown response type
                                        log.warn("Unknown Content-type received:" + contentType);
                                        return;
@@ -223,7 +224,7 @@ public class UpdateInfoRetriever {
                                        return;
                                }
                                
-
+                               
                                info = new UpdateInfo(version, updates);
                                log.info("Found update: " + info);
                        } finally {
diff --git a/core/src/net/sf/openrocket/database/ComponentPresetDao.java b/core/src/net/sf/openrocket/database/ComponentPresetDao.java
new file mode 100644 (file)
index 0000000..a27a7f5
--- /dev/null
@@ -0,0 +1,33 @@
+package net.sf.openrocket.database;
+
+import java.util.List;
+
+import net.sf.openrocket.preset.ComponentPreset;
+
+public interface ComponentPresetDao {
+
+       public List<ComponentPreset> listAll();
+       
+       public void insert( ComponentPreset preset );
+
+       public List<ComponentPreset> listForType( ComponentPreset.Type type );
+
+       /**
+        * Return a list of component presets based on the type.
+        * All components returned will be of Type type.
+        * 
+        * @param type  
+        * @param favorite if true, only return the favorites.  otherwise return all matching.
+        * @return
+        */
+       public List<ComponentPreset> listForType( ComponentPreset.Type type, boolean favorite );
+
+       public List<ComponentPreset> listForTypes( ComponentPreset.Type ... type );
+       
+       public List<ComponentPreset> listForTypes( List<ComponentPreset.Type> types );
+
+       public void setFavorite( ComponentPreset preset, ComponentPreset.Type type, boolean favorite );
+       
+       public List<ComponentPreset> find( String manufacturer, String partNo );
+       
+}
\ No newline at end of file
diff --git a/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java b/core/src/net/sf/openrocket/database/ComponentPresetDatabase.java
new file mode 100644 (file)
index 0000000..bb2fae2
--- /dev/null
@@ -0,0 +1,208 @@
+package net.sf.openrocket.database;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.startup.Application;
+
+public abstract class ComponentPresetDatabase extends Database<ComponentPreset> implements ComponentPresetDao {
+
+       private static final LogHelper logger = Application.getLogger();
+
+       private volatile boolean startedLoading = false;
+       private volatile boolean endedLoading = false;
+       private final boolean asynchronous;
+
+       /** Set to true the first time {@link #blockUntilLoaded()} is called. */
+       protected volatile boolean inUse = false;
+
+       public ComponentPresetDatabase() {
+               super();
+               this.asynchronous = false;
+       }
+       
+       public ComponentPresetDatabase(boolean asynchronous ) {
+               super();
+               this.asynchronous = asynchronous;
+       }
+
+       @Override
+       public List<ComponentPreset> listAll() {
+               blockUntilLoaded();
+               return list;
+       }
+
+       @Override
+       public void insert( ComponentPreset preset ) {
+               list.add(preset);
+       }
+
+       @Override
+       public List<ComponentPreset> listForType( ComponentPreset.Type type ) {
+               blockUntilLoaded();
+               if ( type == null ) {
+                       return Collections.<ComponentPreset>emptyList();
+               }
+
+               List<ComponentPreset> result = new ArrayList<ComponentPreset>(list.size()/6);
+
+               for( ComponentPreset preset : list ) {
+                       if ( preset.get(ComponentPreset.TYPE).equals(type) ) {
+                               result.add(preset);
+                       }
+               }
+               return result;
+
+       }
+
+       /**
+        * Return a list of component presets based on the type.
+        * All components returned will be of Type type.
+        * 
+        * @param type  
+        * @param favorite if true, only return the favorites.  otherwise return all matching.
+        * @return
+        */
+       @Override
+       public List<ComponentPreset> listForType( ComponentPreset.Type type, boolean favorite ) {
+               blockUntilLoaded();
+
+               if ( !favorite ) {
+                       return listForType(type);
+               }
+
+               List<ComponentPreset> result = new ArrayList<ComponentPreset>(list.size()/6);
+
+               Set<String> favorites = Application.getPreferences().getComponentFavorites(type);
+
+               for( ComponentPreset preset : list ) {
+                       if ( preset.get(ComponentPreset.TYPE).equals(type) && favorites.contains(preset.preferenceKey())) {
+                               result.add(preset);
+                       }
+               }
+               return result;
+       }
+
+       @Override
+       public List<ComponentPreset> listForTypes( ComponentPreset.Type ... type ) {
+               blockUntilLoaded();
+
+               if( type == null || type.length == 0 ) {
+                       return Collections.<ComponentPreset>emptyList();
+               }
+
+               if (type.length == 1 ) {
+                       return listForType(type[0]);
+               }
+
+               List<ComponentPreset> result = new ArrayList<ComponentPreset>(list.size()/6);
+
+               for( ComponentPreset preset : list ) {
+                       ComponentPreset.Type presetType = preset.get(ComponentPreset.TYPE);
+                       typeLoop: for( int i=0; i<type.length; i++ ) {
+                               if ( presetType.equals(type[i]) ) {
+                                       result.add(preset);
+                                       break typeLoop; // from inner loop.
+                               }
+                       }
+
+               }
+               return result;
+       }
+
+       @Override
+       public List<ComponentPreset> listForTypes( List<ComponentPreset.Type> types ) {
+               blockUntilLoaded();
+               return listForTypes( (ComponentPreset.Type[]) types.toArray() );
+       }
+
+       @Override
+       public List<ComponentPreset> find(String manufacturer, String partNo) {
+               blockUntilLoaded();
+               List<ComponentPreset> presets = new ArrayList<ComponentPreset>();
+               for( ComponentPreset preset : list ) {
+                       if ( preset.getManufacturer().getSimpleName().equals(manufacturer) && preset.getPartNo().equals(partNo) ) {
+                               presets.add(preset);
+                       }
+               }
+               return presets;
+       }
+
+       @Override
+       public void setFavorite( ComponentPreset preset, ComponentPreset.Type type, boolean favorite ) {
+               blockUntilLoaded();
+               Application.getPreferences().setComponentFavorite( preset, type, favorite );
+               this.fireAddEvent(preset);
+       }
+
+
+       /**
+        * Used for loading the component preset database.  This method will be called in a background
+        * thread to load the presets asynchronously.
+        */
+       protected abstract void load();
+
+       /**
+        * Start loading the presets.
+        * 
+        * @throws  IllegalStateException       if this method has already been called.
+        */
+       public void startLoading() {
+               if (startedLoading) {
+                       throw new IllegalStateException("Already called startLoading");
+               }
+               startedLoading = true;
+               if (asynchronous) {
+                       new LoadingThread().start();
+               } else {
+                       load();
+               }
+               synchronized (this) {
+                       endedLoading = true;
+                       this.notifyAll();
+               }
+       }
+
+       /**
+        * Background thread for loading the presets. 
+        */
+       private class LoadingThread extends Thread {
+               
+               private LoadingThread() {
+                       this.setName("PresetLoadingThread");
+                       this.setPriority(MIN_PRIORITY);
+               }
+               @Override
+               public void run() {
+                       load();
+               }
+       }
+
+       /**
+        * Block the current thread until loading of the presets has been completed.
+        * 
+        * @throws IllegalStateException        if startLoading() has not been called.
+        */
+       public void blockUntilLoaded() {
+               inUse = true;
+               if (!startedLoading) {
+                       throw new IllegalStateException("startLoading() has not been called");
+               }
+               if (!endedLoading) {
+                       synchronized (this) {
+                               while (!endedLoading) {
+                                       try {
+                                               this.wait();
+                                       } catch (InterruptedException e) {
+                                               logger.warn("InterruptedException occurred, ignoring", e);
+                                       }
+                               }
+                       }
+               }
+       }
+
+}
index 37636304e9da756900658714d333792343c91667..d0909cd6e8547a27588fdbd7ae48e11c04404daf 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.database;
 
 import java.io.File;
+import java.io.FileFilter;
 import java.io.FileInputStream;
 import java.io.FilenameFilter;
 import java.io.IOException;
@@ -15,9 +16,12 @@ import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
 import net.sf.openrocket.file.Loader;
+import net.sf.openrocket.file.iterator.DirectoryIterator;
+import net.sf.openrocket.file.iterator.FileIterator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.JarUtil;
+import net.sf.openrocket.util.Pair;
 
 
 
@@ -31,7 +35,7 @@ import net.sf.openrocket.util.JarUtil;
 public class Database<T extends Comparable<T>> extends AbstractSet<T> {
        private static final LogHelper log = Application.getLogger();
        
-       private final List<T> list = new ArrayList<T>();
+       protected final List<T> list = new ArrayList<T>();
        private final ArrayList<DatabaseListener<T>> listeners =
                        new ArrayList<DatabaseListener<T>>();
        private final Loader<T> loader;
@@ -126,7 +130,30 @@ public class Database<T extends Comparable<T>> extends AbstractSet<T> {
 
        ////////  Directory loading
        
+       public void load( String dir, final String pattern ) throws IOException {
+               
+               FileFilter filter = new FileFilter() {
 
+                       @Override
+                       public boolean accept(File pathname) {
+                               return pathname.getName().matches(pattern);
+                       }
+                       
+               };
+               
+               FileIterator files = DirectoryIterator.findDirectory(dir, filter);
+               while( files != null && files.hasNext() ) {
+                       Pair<String, InputStream> file = files.next();
+                       try {
+                               this.addAll(loader.load(file.getV(), file.getU()));
+                       } catch (IOException e) {
+                               log.warn("Error loading file " + file + ": " + e.getMessage(), e);
+                       }
+               }
+               if ( files != null ) {
+                       files.close();
+               }
+       }
 
        /**
         * Load all files in a directory to the motor database.  Only files with file
index 30797e31a7561dd48de7e5623e7e8c0db1dbe349..853790bf8c0826b0307f25054e75d0887271e63e 100644 (file)
@@ -3,6 +3,7 @@ package net.sf.openrocket.database;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.material.Material.Type;
 import net.sf.openrocket.material.MaterialStorage;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.MathUtil;
@@ -17,6 +18,7 @@ public class Databases {
        private static final LogHelper log = Application.getLogger();
        private static final Translator trans = Application.getTranslator();
        
+       
        /* Static implementations of specific databases: */
        
        /**
@@ -37,65 +39,53 @@ public class Databases {
        static {
                
                // Add default materials
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Acrylic"), 1190, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Aluminum"), 2700, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Balsa"), 170, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Basswood"), 500, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Birch"), 670, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Brass"), 8600, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Cardboard"), 680, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Carbonfiber"), 1780, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Cork"), 240, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.DepronXPS"), 40, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Fiberglass"), 1850, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Kraftphenolic"), 950, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Maple"), 755, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Paperoffice"), 820, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Pine"), 530, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Plywoodbirch"), 630, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.PolycarbonateLexan"), 1200, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Polystyrene"), 1050, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.PVC"), 1390, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Spruce"), 450, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Steel"), 7850, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.StyrofoamgenericEPS"), 20, false));
-               //              BULK_MATERIAL.add(new Material.Bulk("Styrofoam (Blue foam, XPS)", 32, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.StyrofoamBluefoamXPS"), 32, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Titanium"), 4500, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.Quantumtubing"), 1050, false));
-               BULK_MATERIAL.add(new Material.Bulk(trans.get("Databases.materials.BlueTube"), 1300, false));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Acrylic", 1190));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Aluminum", 2700));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Balsa", 170));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Basswood", 500));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Birch", 670));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Brass", 8600));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Cardboard", 680));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Carbon fiber", 1780));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Cork", 240));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Depron (XPS)", 40));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Fiberglass", 1850));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Kraft phenolic", 950));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Maple", 755));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Paper (office)", 820));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Pine", 530));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Plywood (birch)", 630));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Polycarbonate (Lexan)", 1200));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Polystyrene", 1050));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "PVC", 1390));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Spruce", 450));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Steel", 7850));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Styrofoam (generic EPS)", 20));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Styrofoam \"Blue foam\" (XPS)", 32));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Titanium", 4500));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Quantum tubing", 1050));
+               BULK_MATERIAL.add(newMaterial(Material.Type.BULK, "Blue tube", 1300));
                
-               SURFACE_MATERIAL.add(new Material.Surface(trans.get("Databases.materials.Ripstopnylon"), 0.067, false));
-               SURFACE_MATERIAL.add(new Material.Surface(trans.get("Databases.materials.Mylar"), 0.021, false));
-               SURFACE_MATERIAL.add(new Material.Surface(trans.get("Databases.materials.Polyethylenethin"), 0.015, false));
-               SURFACE_MATERIAL.add(new Material.Surface(trans.get("Databases.materials.Polyethyleneheavy"), 0.040, false));
-               SURFACE_MATERIAL.add(new Material.Surface(trans.get("Databases.materials.Silk"), 0.060, false));
-               SURFACE_MATERIAL.add(new Material.Surface(trans.get("Databases.materials.Paperoffice"), 0.080, false));
-               SURFACE_MATERIAL.add(new Material.Surface(trans.get("Databases.materials.Cellophane"), 0.018, false));
-               SURFACE_MATERIAL.add(new Material.Surface(trans.get("Databases.materials.Crepepaper"), 0.025, false));
+               SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Ripstop nylon", 0.067));
+               SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Mylar", 0.021));
+               SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Polyethylene (thin)", 0.015));
+               SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Polyethylene (heavy)", 0.040));
+               SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Silk", 0.060));
+               SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Paper (office)", 0.080));
+               SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Cellophane", 0.018));
+               SURFACE_MATERIAL.add(newMaterial(Material.Type.SURFACE, "Cr\u00eape paper", 0.025));
                
-               //// Thread (heavy-duty)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Threadheavy-duty"), 0.0003, false));
-               //// Elastic cord (round 2mm, 1/16 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Elasticcordround2mm"), 0.0018, false));
-               //// Elastic cord (flat  6mm, 1/4 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Elasticcordflat6mm"), 0.0043, false));
-               //// Elastic cord (flat 12mm, 1/2 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Elasticcordflat12mm"), 0.008, false));
-               //// Elastic cord (flat 19mm, 3/4 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Elasticcordflat19mm"), 0.0012, false));
-               //// Elastic cord (flat 25mm, 1 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Elasticcordflat25mm"), 0.0016, false));
-               //// Braided nylon (2 mm, 1/16 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Braidednylon2mm"), 0.001, false));
-               //// Braided nylon (3 mm, 1/8 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Braidednylon3mm"), 0.0035, false));
-               //// Tubular nylon (11 mm, 7/16 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Tubularnylon11mm"), 0.013, false));
-               //// Tubular nylon (14 mm, 9/16 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Tubularnylon14mm"), 0.016, false));
-               //// Tubular nylon (25 mm, 1 in)
-               LINE_MATERIAL.add(new Material.Line(trans.get("Databases.materials.Tubularnylon25mm"), 0.029, false));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Thread (heavy-duty)", 0.0003));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (round 2 mm, 1/16 in)", 0.0018));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 6 mm, 1/4 in)", 0.0043));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 12 mm, 1/2 in)", 0.008));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 19 mm, 3/4 in)", 0.0012));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Elastic cord (flat 25 mm, 1 in)", 0.0016));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Braided nylon (2 mm, 1/16 in)", 0.001));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Braided nylon (3 mm, 1/8 in)", 0.0035));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (11 mm, 7/16 in)", 0.013));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (14 mm, 9/16 in)", 0.016));
+               LINE_MATERIAL.add(newMaterial(Material.Type.LINE, "Tubular nylon (25 mm, 1 in)", 0.029));
                
                
                // Add user-defined materials
@@ -126,6 +116,14 @@ public class Databases {
        }
        
        
+       private static Material newMaterial(Type type, String baseName, double density) {
+               String name = trans.get("material", baseName);
+               return Material.newMaterial(type, name, density, false);
+       }
+       
+       
+       
+       
        /*
         * Used just for ensuring initialization of the class.
         */
@@ -133,16 +131,18 @@ public class Databases {
                
        }
        
-       
        /**
         * Find a material from the database with the specified type and name.  Returns
         * <code>null</code> if the specified material could not be found.
+        * <p>
+        * This method will attempt to localize the material name to the current locale, or use
+        * the provided name if unable to do so.
         * 
-        * @param type  the material type.
-        * @param name  the material name in the database.
-        * @return              the material, or <code>null</code> if not found.
+        * @param type          the material type.
+        * @param baseName      the material base name in the database.
+        * @return                      the material, or <code>null</code> if not found.
         */
-       public static Material findMaterial(Material.Type type, String name) {
+       public static Material findMaterial(Material.Type type, String baseName) {
                Database<Material> db;
                switch (type) {
                case BULK:
@@ -158,6 +158,8 @@ public class Databases {
                        throw new IllegalArgumentException("Illegal material type: " + type);
                }
                
+               String name = trans.get("material", baseName);
+               
                for (Material m : db) {
                        if (m.getName().equalsIgnoreCase(name)) {
                                return m;
@@ -168,17 +170,18 @@ public class Databases {
        
        
        /**
-        * Find a material from the database or return a new material if the specified
+        * Find a material from the database or return a new user defined material if the specified
         * material with the specified density is not found.
+        * <p>
+        * This method will attempt to localize the material name to the current locale, or use
+        * the provided name if unable to do so.
         * 
         * @param type                  the material type.
-        * @param name                  the material name.
+        * @param baseName                      the base name of the material.
         * @param density               the density of the material.
-        * @param userDefined   whether a newly created material should be user-defined.
         * @return                              the material object from the database or a new material.
         */
-       public static Material findMaterial(Material.Type type, String name, double density,
-                       boolean userDefined) {
+       public static Material findMaterial(Material.Type type, String baseName, double density) {
                Database<Material> db;
                switch (type) {
                case BULK:
@@ -194,13 +197,14 @@ public class Databases {
                        throw new IllegalArgumentException("Illegal material type: " + type);
                }
                
+               String name = trans.get("material", baseName);
+               
                for (Material m : db) {
                        if (m.getName().equalsIgnoreCase(name) && MathUtil.equals(m.getDensity(), density)) {
                                return m;
                        }
                }
-               return Material.newMaterial(type, name, density, userDefined);
+               return Material.newMaterial(type, name, density, true);
        }
        
-       
 }
index 1aeb6cd4c70e456c0e9abaa433f506fc39514f0a..9b4c8b18d83bc8a90c285f7910889053a15f1530 100644 (file)
@@ -204,6 +204,10 @@ public abstract class ThrustCurveMotorSetDatabase implements MotorDatabase {
         * marks the database as loaded and notifies any blocked threads.
         */
        private class LoadingThread extends Thread {
+               private LoadingThread() {
+                       this.setName("MotorLoadingThread");
+                       this.setPriority(MIN_PRIORITY);
+               }
                @Override
                public void run() {
                        performMotorLoading();
index cafc98f33d174665a88081ad3ca9e34cd1be97a9..12535220b75bcfecc4f983b98b101763d85f6b71 100644 (file)
@@ -1,8 +1,12 @@
 package net.sf.openrocket.document;
 
 import java.io.File;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 
 import net.sf.openrocket.document.events.DocumentChangeEvent;
 import net.sf.openrocket.document.events.DocumentChangeListener;
@@ -13,6 +17,10 @@ import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
 import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
 import net.sf.openrocket.rocketcomponent.Configuration;
 import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.simulation.exception.SimulationListenerException;
+import net.sf.openrocket.simulation.listeners.SimulationListener;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.ArrayList;
 
@@ -50,7 +58,8 @@ public class OpenRocketDocument implements ComponentChangeListener {
        private final Configuration configuration;
        
        private final ArrayList<Simulation> simulations = new ArrayList<Simulation>();
-       
+       private ArrayList<CustomExpression> customExpressions = new ArrayList<CustomExpression>();
+
 
        /*
         * The undo/redo variables and mechanism are documented in doc/undo-redo-flow.*
@@ -103,7 +112,59 @@ public class OpenRocketDocument implements ComponentChangeListener {
        }
        
        
-
+       public void addCustomExpression(CustomExpression expression){
+               if (customExpressions.contains(expression)){
+                       log.user("Could not add custom expression "+expression.getName()+" to document as document alerady has a matching expression.");
+               } else {
+                       customExpressions.add(expression);
+               }
+       }
+       
+       public void removeCustomExpression(CustomExpression expression){
+               customExpressions.remove(expression);
+       }
+       
+       public List<CustomExpression> getCustomExpressions(){
+               return customExpressions;
+       }
+       
+       /*
+        * Returns a set of all the flight data types defined or available in any way in the rocket document
+        */
+       public Set<FlightDataType> getFlightDataTypes(){
+               Set<FlightDataType> allTypes = new LinkedHashSet<FlightDataType>();
+               
+               // built in
+               Collections.addAll(allTypes, FlightDataType.ALL_TYPES);
+               
+               // custom expressions
+               for (CustomExpression exp : customExpressions){
+                       allTypes.add(exp.getType());
+               }
+               
+               // simulation listeners
+               for (Simulation sim : simulations){
+                       for (String className : sim.getSimulationListeners()) {
+                               SimulationListener l = null;
+                               try {
+                                       Class<?> c = Class.forName(className);
+                                       l = (SimulationListener) c.newInstance();
+                                       
+                                       Collections.addAll(allTypes, l.getFlightDataTypes());
+                                       //System.out.println("This document has expression datatype from "+l.getName());
+                               } catch (Exception e) {
+                                       log.error("Could not instantiate listener: " + className);
+                               }
+                       }                       
+               }
+               
+               // imported data
+               /// not implemented yet
+               
+               
+               return allTypes;
+       }
+       
 
        public Rocket getRocket() {
                return rocket;
index 74d3ab28ed517b03f9d2163f95b999f47054ffde..edb093c3b9b016c813ce61ba1ddf0858f42340ff 100644 (file)
@@ -75,8 +75,6 @@ public class Simulation implements ChangeSource, Cloneable {
        private Class<? extends SimulationStepper> simulationStepperClass = RK4SimulationStepper.class;
        private Class<? extends AerodynamicCalculator> aerodynamicCalculatorClass = BarrowmanCalculator.class;
        private Class<? extends MassCalculator> massCalculatorClass = BasicMassCalculator.class;
-       
-
 
        /** Listeners for this object */
        private List<EventListener> listeners = new ArrayList<EventListener>();
@@ -90,8 +88,8 @@ public class Simulation implements ChangeSource, Cloneable {
        
        
        /**
-        * Create a new simulation for the rocket.  The initial motor configuration is
-        * taken from the default rocket configuration.
+        * Create a new simulation for the rocket. Parent document should also be provided.
+        * The initial motor configuration is taken from the default rocket configuration.
         * 
         * @param rocket        the rocket associated with the simulation.
         */
@@ -148,7 +146,6 @@ public class Simulation implements ChangeSource, Cloneable {
                
        }
        
-       
        /**
         * Return the rocket associated with this simulation.
         * 
@@ -280,6 +277,7 @@ public class Simulation implements ChangeSource, Cloneable {
                        }
                        
                        SimulationConditions simulationConditions = options.toSimulationConditions();
+                       simulationConditions.setSimulation(this);
                        for (SimulationListener l : additionalListeners) {
                                simulationConditions.getSimulationListenerList().add(l);
                        }
index 775d9eddfa9dc219ce1e3b1a2bbea9ce3398f60f..da6858d89cb912f9e424a172c79ccc6b7cbc71d9 100644 (file)
@@ -12,6 +12,8 @@ import java.util.zip.ZipInputStream;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.file.openrocket.importt.OpenRocketLoader;
 import net.sf.openrocket.file.rocksim.importt.RocksimLoader;
+import net.sf.openrocket.util.ArrayUtils;
+import net.sf.openrocket.util.TextUtil;
 
 
 /**
@@ -26,9 +28,9 @@ public class GeneralRocketLoader extends AbstractRocketLoader {
        private static final int READ_BYTES = 300;
        
        private static final byte[] GZIP_SIGNATURE = { 31, -117 }; // 0x1f, 0x8b
-       private static final byte[] ZIP_SIGNATURE = "PK".getBytes(Charset.forName("US-ASCII"));
-       private static final byte[] OPENROCKET_SIGNATURE = "<openrocket".getBytes(Charset.forName("US-ASCII"));
-       private static final byte[] ROCKSIM_SIGNATURE = "<RockSimDoc".getBytes(Charset.forName("US-ASCII"));
+       private static final byte[] ZIP_SIGNATURE = TextUtil.convertStringToBytes("PK",Charset.forName("US-ASCII"));
+       private static final byte[] OPENROCKET_SIGNATURE = TextUtil.convertStringToBytes("<openrocket",Charset.forName("US-ASCII"));
+       private static final byte[] ROCKSIM_SIGNATURE = TextUtil.convertStringToBytes("<RockSimDoc",Charset.forName("US-ASCII"));
        
        private final OpenRocketLoader openRocketLoader = new OpenRocketLoader();
        
@@ -76,6 +78,9 @@ public class GeneralRocketLoader extends AbstractRocketLoader {
                                        OpenRocketDocument doc = loadFromStream(in, motorFinder);
                                        doc.getDefaultStorageOptions().setCompressionEnabled(true);
                                        return doc;
+                               } else if ( entry.getName().matches(".*\\.[rR][kK][tT]$")) {
+                                       OpenRocketDocument doc = loadFromStream(in, motorFinder);
+                                       return doc;
                                }
                        }
                }
@@ -93,7 +98,7 @@ public class GeneralRocketLoader extends AbstractRocketLoader {
                        }
                }
                
-               byte[] typeIdentifier = Arrays.copyOf(buffer, ROCKSIM_SIGNATURE.length);
+               byte[] typeIdentifier = ArrayUtils.copyOf(buffer, ROCKSIM_SIGNATURE.length);
                if (Arrays.equals(ROCKSIM_SIGNATURE, typeIdentifier)) {
                        return loadUsing(source, rocksimLoader, motorFinder);
                }
index 3d3e6df5ff28027a495d92fed98935a660cc9dd7..7cf5488b80b4eec708a2743c51de50a1670af774 100644 (file)
@@ -96,8 +96,6 @@ public class ZipDirectoryIterator extends FileIterator {
                        }
                }
                
-               // No more elements exist
-               close();
                return null;
        }
 
index e9051f7a7dced3ca328f32ef66f4818c61c29caf..b166706f82daca95707032244594f9411987f026 100644 (file)
@@ -6,11 +6,11 @@ import java.io.InputStreamReader;
 import java.io.Reader;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
 import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.util.ArrayUtils;
 import net.sf.openrocket.util.MathUtil;
 
 public abstract class AbstractMotorLoader implements MotorLoader {
@@ -136,7 +136,7 @@ public abstract class AbstractMotorLoader implements MotorLoader {
                String[] pieces = str.split(delim);
                if (pieces.length == 0 || !pieces[0].equals(""))
                        return pieces;
-               return Arrays.copyOfRange(pieces, 1, pieces.length);
+               return ArrayUtils.copyOfRange(pieces, 1, pieces.length);
        }
        
        
index 049738a49a42e17a1ed99361f0106f7b8bb40f8f..13a2e423667757d5370893592d43368cab9a24ea 100644 (file)
@@ -19,13 +19,13 @@ import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Pair;
 
 public final class MotorLoaderHelper {
-       
+
        private static final LogHelper log = Application.getLogger();
-       
+
        private MotorLoaderHelper() {
                // Prevent construction
        }
-       
+
        /**
         * Load a file or directory of thrust curves.  Directories are loaded
         * recursively.  Any errors during loading are logged, but otherwise ignored.
@@ -35,18 +35,18 @@ public final class MotorLoaderHelper {
         */
        public static List<Motor> load(File target) {
                GeneralMotorLoader loader = new GeneralMotorLoader();
-               
+
                if (target.isDirectory()) {
-                       
+
                        try {
                                return load(new DirectoryIterator(target, new SimpleFileFilter("", loader.getSupportedExtensions()), true));
                        } catch (IOException e) {
                                log.warn("Could not read directory " + target, e);
                                return Collections.emptyList();
                        }
-                       
+
                } else {
-                       
+
                        InputStream is = null;
                        try {
                                is = new FileInputStream(target);
@@ -63,11 +63,24 @@ public final class MotorLoaderHelper {
                                        }
                                }
                        }
-                       
+
+               }
+       }
+
+       public static List<Motor> load( InputStream is, String fileName ) {
+               GeneralMotorLoader loader = new GeneralMotorLoader();
+               try {
+                       List<Motor> motors = loader.load(is, fileName);
+                       if (motors.size() == 0) {
+                               log.warn("No motors found in file " + fileName);
+                       }
+                       return motors;
+               } catch (IOException e) {
+                       log.warn("IOException when loading motor file " + fileName, e);
                }
+               return Collections.<Motor>emptyList();
        }
-       
-       
+
        /**
         * Load motors from files iterated over by a FileIterator.  Any errors during
         * loading are logged, but otherwise ignored.
@@ -78,22 +91,16 @@ public final class MotorLoaderHelper {
         * @return                      a list of all motors loaded.
         */
        public static List<Motor> load(FileIterator iterator) {
-               GeneralMotorLoader loader = new GeneralMotorLoader();
                List<Motor> list = new ArrayList<Motor>();
-               
+
                while (iterator.hasNext()) {
                        final Pair<String, InputStream> input = iterator.next();
                        log.debug("Loading motors from file " + input.getU());
                        try {
-                               List<Motor> motors = loader.load(input.getV(), input.getU());
-                               if (motors.size() == 0) {
-                                       log.warn("No motors found in file " + input.getU());
-                               }
+                               List<Motor> motors = load(input.getV(), input.getU());
                                for (Motor m : motors) {
                                        list.add((ThrustCurveMotor) m);
                                }
-                       } catch (IOException e) {
-                               log.warn("IOException when loading motor file " + input.getU(), e);
                        } finally {
                                try {
                                        input.getV().close();
@@ -103,8 +110,8 @@ public final class MotorLoaderHelper {
                        }
                }
                iterator.close();
-               
+
                return list;
        }
-       
+
 }
index 5b863158ad54cdda9e8f79777c49c9b58a72e4b1..0a5e04790caa407459640e5ef3d95ddd0abf59a7 100644 (file)
@@ -8,6 +8,7 @@ import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.zip.GZIPOutputStream;
 
 import net.sf.openrocket.aerodynamics.Warning;
@@ -18,6 +19,8 @@ import net.sf.openrocket.file.RocketSaver;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.FinSet;
 import net.sf.openrocket.rocketcomponent.MotorMount;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice.DeployEvent;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.TubeCoupler;
@@ -26,6 +29,7 @@ import net.sf.openrocket.simulation.FlightDataBranch;
 import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.SimulationOptions;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.BuildProperties;
@@ -97,6 +101,9 @@ public class OpenRocketSaver extends RocketSaver {
                
                writeln("");
                
+               // Save custom expressions;
+               saveCustomDatatypes(document);
+               
                // Save all simulations
                writeln("<simulations>");
                indent++;
@@ -120,7 +127,41 @@ public class OpenRocketSaver extends RocketSaver {
                }
        }
        
+       /*
+        * Save all the custom expressions
+        */
+       private void saveCustomDatatypes(OpenRocketDocument doc) throws IOException {
+               
+               if (doc.getCustomExpressions().isEmpty())
+                       return;
+               
+               writeln("<datatypes>");
+               indent++;
+               
+               for (CustomExpression exp : doc.getCustomExpressions()) {
+                       saveCustomExpressionDatatype(exp);
+               }
+               
+               indent--;
+               writeln("</datatypes>");
+               writeln("");
+       }
        
+       /*
+        * Save one custom expression datatype
+        */
+       private void saveCustomExpressionDatatype(CustomExpression exp) throws IOException {
+               // Write out custom expression
+               
+               writeln("<type source=\"customexpression\">");
+               indent++;
+               writeln("<name>" + exp.getName() + "</name>");
+               writeln("<symbol>" + exp.getSymbol() + "</symbol>");
+               writeln("<unit unittype=\"auto\">" + exp.getUnit() + "</unit>"); // auto unit type means it will be determined from string
+               writeln("<expression>" + exp.getExpressionString() + "</expression>");
+               indent--;
+               writeln("</type>");
+       }
        
        @Override
        public long estimateFileSize(OpenRocketDocument doc, StorageOptions options) {
@@ -183,6 +224,11 @@ public class OpenRocketSaver extends RocketSaver {
         */
        private int calculateNecessaryFileVersion(OpenRocketDocument document, StorageOptions opts) {
                /*
+                * File version 1.5 is requires for:
+                *  - saving designs using ComponentPrests
+                *  - recovery device deployment on lower stage separation
+                *  - custom expressions
+                *  
                 * File version 1.4 is required for:
                 *  - saving simulation data
                 *  - saving motor data
@@ -194,15 +240,34 @@ public class OpenRocketSaver extends RocketSaver {
                 * Otherwise use version 1.0.
                 */
                
+               // Search the rocket for any ComponentPresets (version 1.5)
+               for (RocketComponent c : document.getRocket()) {
+                       if (c.getPresetComponent() != null) {
+                               return FILE_VERSION_DIVISOR + 5;
+                       }
+               }
+               
+               // Search for recovery device deployment type LOWER_STAGE_SEPARATION (version 1.5)
+               for (RocketComponent c : document.getRocket()) {
+                       if (c instanceof RecoveryDevice) {
+                               if (((RecoveryDevice) c).getDeployEvent() == DeployEvent.LOWER_STAGE_SEPARATION) {
+                                       return FILE_VERSION_DIVISOR + 5;
+                               }
+                       }
+               }
+               
+               // Check for custom expressions
+               if (!document.getCustomExpressions().isEmpty()) {
+                       return FILE_VERSION_DIVISOR + 5;
+               }
+               
                // Check if design has simulations defined (version 1.4)
                if (document.getSimulationCount() > 0) {
                        return FILE_VERSION_DIVISOR + 4;
                }
                
                // Check for motor definitions (version 1.4)
-               Iterator<RocketComponent> iterator = document.getRocket().iterator();
-               while (iterator.hasNext()) {
-                       RocketComponent c = iterator.next();
+               for (RocketComponent c : document.getRocket()) {
                        if (!(c instanceof MotorMount))
                                continue;
                        
@@ -215,10 +280,7 @@ public class OpenRocketSaver extends RocketSaver {
                }
                
                // Check for fin tabs (version 1.1)
-               iterator = document.getRocket().iterator();
-               while (iterator.hasNext()) {
-                       RocketComponent c = iterator.next();
-                       
+               for (RocketComponent c : document.getRocket()) {
                        // Check for fin tabs
                        if (c instanceof FinSet) {
                                FinSet fin = (FinSet) c;
@@ -304,8 +366,10 @@ public class OpenRocketSaver extends RocketSaver {
                
                writeln("<name>" + escapeXML(simulation.getName()) + "</name>");
                // TODO: MEDIUM: Other simulators/calculators
+               
                writeln("<simulator>RK4Simulator</simulator>");
                writeln("<calculator>BarrowmanCalculator</calculator>");
+               
                writeln("<conditions>");
                indent++;
                
@@ -318,7 +382,7 @@ public class OpenRocketSaver extends RocketSaver {
                writeElement("launchaltitude", cond.getLaunchAltitude());
                writeElement("launchlatitude", cond.getLaunchLatitude());
                writeElement("launchlongitude", cond.getLaunchLongitude());
-               writeElement("geodeticmethod", cond.getGeodeticComputation().name().toLowerCase());
+               writeElement("geodeticmethod", cond.getGeodeticComputation().name().toLowerCase(Locale.ENGLISH));
                
                if (cond.isISAAtmosphere()) {
                        writeln("<atmosphere model=\"isa\"/>");
@@ -341,7 +405,6 @@ public class OpenRocketSaver extends RocketSaver {
                        writeElement("listener", escapeXML(s));
                }
                
-               
                // Write basic simulation data
                
                FlightData data = simulation.getSimulatedData();
@@ -419,6 +482,17 @@ public class OpenRocketSaver extends RocketSaver {
                StringBuilder sb = new StringBuilder();
                sb.append("<databranch name=\"");
                sb.append(escapeXML(branch.getBranchName()));
+               
+               // Kevins version where typekeys are used
+               /*
+               sb.append("\" typekeys=\"");
+               for (int i = 0; i < types.length; i++) {
+                       if (i > 0)
+                               sb.append(",");
+                       sb.append(escapeXML(types[i].getKey()));
+               }
+               */
+               
                sb.append("\" types=\"");
                for (int i = 0; i < types.length; i++) {
                        if (i > 0)
@@ -553,7 +627,7 @@ public class OpenRocketSaver extends RocketSaver {
         * @return              the corresponding XML name.
         */
        public static String enumToXMLName(Enum<?> e) {
-               return e.name().toLowerCase().replace("_", "");
+               return e.name().toLowerCase(Locale.ENGLISH).replace("_", "");
        }
        
 }
index 313fa981a158d96206c6f9d2aa410e85e706020f..4efdf9dbd5f962b15ce2bccbec136884c2796d63 100644 (file)
@@ -7,6 +7,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -27,6 +28,7 @@ import net.sf.openrocket.file.simplesax.SimpleSAX;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.rocketcomponent.BodyComponent;
 import net.sf.openrocket.rocketcomponent.BodyTube;
 import net.sf.openrocket.rocketcomponent.Bulkhead;
@@ -71,6 +73,7 @@ import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.FlightEvent.Type;
 import net.sf.openrocket.simulation.SimulationOptions;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.BugException;
@@ -163,7 +166,7 @@ public class OpenRocketLoader extends AbstractRocketLoader {
 class DocumentConfig {
        
        /* Remember to update OpenRocketSaver as well! */
-       public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4" };
+       public static final String[] SUPPORTED_VERSIONS = { "1.0", "1.1", "1.2", "1.3", "1.4", "1.5" };
        
        /**
         * Divisor used in converting an integer version to the point-represented version.
@@ -235,6 +238,8 @@ class DocumentConfig {
                                Reflection.findMethod(RocketComponent.class, "setOverrideSubcomponents", boolean.class)));
                setters.put("RocketComponent:comment", new StringSetter(
                                Reflection.findMethod(RocketComponent.class, "setComment", String.class)));
+               setters.put("RocketComponent:preset", new ComponentPresetSetter(
+                               Reflection.findMethod(RocketComponent.class, "loadPreset", ComponentPreset.class)));
                
                // ExternalComponent
                setters.put("ExternalComponent:finish", new EnumSetter<Finish>(
@@ -508,7 +513,7 @@ class DocumentConfig {
                        return null;
                name = name.trim();
                for (Enum<T> e : enumClass.getEnumConstants()) {
-                       if (e.name().toLowerCase().replace("_", "").equals(name)) {
+                       if (e.name().toLowerCase(Locale.ENGLISH).replace("_", "").equals(name)) {
                                return e;
                        }
                }
@@ -644,6 +649,7 @@ class OpenRocketContentHandler extends AbstractElementHandler {
        
        private boolean rocketDefined = false;
        private boolean simulationsDefined = false;
+       private boolean datatypesDefined = false;
        
        public OpenRocketContentHandler(DocumentLoadingContext context) {
                this.context = context;
@@ -651,7 +657,6 @@ class OpenRocketContentHandler extends AbstractElementHandler {
                this.doc = new OpenRocketDocument(rocket);
        }
        
-       
        public OpenRocketDocument getDocument() {
                if (!rocketDefined)
                        return null;
@@ -673,6 +678,15 @@ class OpenRocketContentHandler extends AbstractElementHandler {
                        return new ComponentParameterHandler(rocket, context);
                }
                
+               if (element.equals("datatypes")) {
+                       if (datatypesDefined) {
+                               warnings.add(Warning.fromString("Multiple datatype blocks. Ignoring later ones."));
+                               return null;
+                       }
+                       datatypesDefined = true;
+                       return new DatatypeHandler(this, context);
+               }
+               
                if (element.equals("simulations")) {
                        if (simulationsDefined) {
                                warnings.add(Warning
@@ -690,8 +704,90 @@ class OpenRocketContentHandler extends AbstractElementHandler {
        }
 }
 
+class DatatypeHandler extends AbstractElementHandler {
+       private final DocumentLoadingContext context;
+       private final OpenRocketContentHandler contentHandler;
+       private CustomExpressionHandler customExpressionHandler = null;
+       
+       public DatatypeHandler(OpenRocketContentHandler contentHandler, DocumentLoadingContext context) {
+               this.context = context;
+               this.contentHandler = contentHandler;
+       }
+       
+       @Override
+       public ElementHandler openElement(String element,
+                       HashMap<String, String> attributes, WarningSet warnings)
+                       throws SAXException {
+               
+               if (element.equals("type") && attributes.get("source").equals("customexpression")) {
+                       customExpressionHandler = new CustomExpressionHandler(contentHandler, context);
+                       return customExpressionHandler;
+               }
+               else {
+                       warnings.add(Warning.fromString("Unknown datatype " + element + " defined, ignoring"));
+               }
+               
+               return this;
+       }
+       
+       @Override
+       public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
+               attributes.remove("source");
+               super.closeElement(element, attributes, content, warnings);
+               
+               if (customExpressionHandler != null) {
+                       contentHandler.getDocument().addCustomExpression(customExpressionHandler.currentExpression);
+               }
+               
+       }
+       
+}
 
-
+class CustomExpressionHandler extends AbstractElementHandler {
+       private final DocumentLoadingContext context;
+       private final OpenRocketContentHandler contentHandler;
+       public CustomExpression currentExpression;
+       
+       public CustomExpressionHandler(OpenRocketContentHandler contentHandler, DocumentLoadingContext context) {
+               this.context = context;
+               this.contentHandler = contentHandler;
+               currentExpression = new CustomExpression(contentHandler.getDocument());
+               
+       }
+       
+       @Override
+       public ElementHandler openElement(String element,
+                       HashMap<String, String> attributes, WarningSet warnings)
+                       throws SAXException {
+               
+               return this;
+       }
+       
+       @Override
+       public void closeElement(String element, HashMap<String, String> attributes,
+                       String content, WarningSet warnings) throws SAXException {
+               
+               if (element.equals("type")) {
+                       contentHandler.getDocument().addCustomExpression(currentExpression);
+               }
+               
+               if (element.equals("name")) {
+                       currentExpression.setName(content);
+               }
+               
+               if (element.equals("symbol")) {
+                       currentExpression.setSymbol(content);
+               }
+               
+               if (element.equals("unit") && attributes.get("unittype").equals("auto")) {
+                       currentExpression.setUnit(content);
+               }
+               
+               if (element.equals("expression")) {
+                       currentExpression.setExpression(content);
+               }
+       }
+}
 
 /**
  * A handler that creates components from the corresponding elements.  The control of the
@@ -926,7 +1022,7 @@ class MotorMountHandler extends AbstractElementHandler {
                if (element.equals("ignitionevent")) {
                        MotorMount.IgnitionEvent event = null;
                        for (MotorMount.IgnitionEvent e : MotorMount.IgnitionEvent.values()) {
-                               if (e.name().toLowerCase().replaceAll("_", "").equals(content)) {
+                               if (e.name().toLowerCase(Locale.ENGLISH).replaceAll("_", "").equals(content)) {
                                        event = e;
                                        break;
                                }
@@ -1084,7 +1180,7 @@ class MotorHandler extends AbstractElementHandler {
                        // Motor type
                        type = null;
                        for (Motor.Type t : Motor.Type.values()) {
-                               if (t.name().toLowerCase().equals(content.trim())) {
+                               if (t.name().toLowerCase(Locale.ENGLISH).equals(content.trim())) {
                                        type = t;
                                        break;
                                }
@@ -1190,13 +1286,18 @@ class SimulationsHandler extends AbstractElementHandler {
        public void closeElement(String element, HashMap<String, String> attributes,
                        String content, WarningSet warnings) throws SAXException {
                attributes.remove("status");
+               
+               //Finished loading. Rebuilding custom expressions in case something has changed such as listener variable come available.
+               for (CustomExpression exp : doc.getCustomExpressions()){
+                       exp.setExpression(exp.getExpressionString());
+               }
+               
                super.closeElement(element, attributes, content, warnings);
        }
-       
-       
 }
 
 class SingleSimulationHandler extends AbstractElementHandler {
+       
        private final DocumentLoadingContext context;
        
        private final OpenRocketDocument doc;
@@ -1213,7 +1314,9 @@ class SingleSimulationHandler extends AbstractElementHandler {
                this.context = context;
        }
        
-       
+       public OpenRocketDocument getDocument() {
+               return doc;
+       }
        
        @Override
        public ElementHandler openElement(String element, HashMap<String, String> attributes,
@@ -1226,7 +1329,7 @@ class SingleSimulationHandler extends AbstractElementHandler {
                        conditionHandler = new SimulationConditionsHandler(doc.getRocket(), context);
                        return conditionHandler;
                } else if (element.equals("flightdata")) {
-                       dataHandler = new FlightDataHandler(context);
+                       dataHandler = new FlightDataHandler(this, context);
                        return dataHandler;
                } else {
                        warnings.add("Unknown element '" + element + "', ignoring.");
@@ -1289,8 +1392,6 @@ class SingleSimulationHandler extends AbstractElementHandler {
        }
 }
 
-
-
 class SimulationConditionsHandler extends AbstractElementHandler {
        private final DocumentLoadingContext context;
        private SimulationOptions conditions;
@@ -1475,11 +1576,13 @@ class FlightDataHandler extends AbstractElementHandler {
        private WarningSet warningSet = new WarningSet();
        private List<FlightDataBranch> branches = new ArrayList<FlightDataBranch>();
        
+       private SingleSimulationHandler simHandler;
        private FlightData data;
        
        
-       public FlightDataHandler(DocumentLoadingContext context) {
+       public FlightDataHandler(SingleSimulationHandler simHandler, DocumentLoadingContext context) {
                this.context = context;
+               this.simHandler = simHandler;
        }
        
        public FlightData getFlightData() {
@@ -1499,7 +1602,8 @@ class FlightDataHandler extends AbstractElementHandler {
                                return null;
                        }
                        dataHandler = new FlightDataBranchHandler(attributes.get("name"),
-                                       attributes.get("types"), context);
+                                       attributes.get("types"),
+                                       simHandler, context);
                        return dataHandler;
                }
                
@@ -1596,18 +1700,59 @@ class FlightDataBranchHandler extends AbstractElementHandler {
        private final FlightDataType[] types;
        private final FlightDataBranch branch;
        
-       public FlightDataBranchHandler(String name, String typeList, DocumentLoadingContext context) {
+       private static final LogHelper log = Application.getLogger();
+       private final SingleSimulationHandler simHandler;
+       
+       public FlightDataBranchHandler(String name, String typeList, SingleSimulationHandler simHandler, DocumentLoadingContext context) {
+               this.simHandler = simHandler;
                this.context = context;
                String[] split = typeList.split(",");
                types = new FlightDataType[split.length];
                for (int i = 0; i < split.length; i++) {
-                       types[i] = FlightDataType.getType(split[i], UnitGroup.UNITS_NONE);
+                       String typeName = split[i];
+                       FlightDataType matching = findFlightDataType(typeName);
+                       types[i] = matching;
+                       //types[i] = FlightDataType.getType(typeName, matching.getSymbol(), matching.getUnitGroup());
                }
                
                // TODO: LOW: May throw an IllegalArgumentException
                branch = new FlightDataBranch(name, types);
        }
        
+       // Find the full flight data type given name only
+       // Note: this way of doing it requires that custom expressions always come before flight data in the file,
+       // not the nicest but this is always the case anyway.
+       private FlightDataType findFlightDataType(String name) {
+               
+               // Kevins version with lookup by key. Not using right now
+               /*
+               if ( key != null ) {
+                       for (FlightDataType t : FlightDataType.ALL_TYPES){
+                               if (t.getKey().equals(key) ){
+                                       return t;
+                               }
+                       }
+               }
+               */
+               
+               // Look in built in types
+               for (FlightDataType t : FlightDataType.ALL_TYPES) {
+                       if (t.getName().equals(name)) {
+                               return t;
+                       }
+               }
+               
+               // Look in custom expressions
+               for (CustomExpression exp : simHandler.getDocument().getCustomExpressions()) {
+                       if (exp.getName().equals(name)) {
+                               return exp.getType();
+                       }
+               }
+               
+               log.warn("Could not find the flight data type '" + name + "' used in the XML file. Substituted type with unknown symbol and units.");
+               return FlightDataType.getType(name, "Unknown", UnitGroup.UNITS_NONE);
+       }
+       
        public FlightDataBranch getBranch() {
                branch.immute();
                return branch;
@@ -1933,8 +2078,71 @@ class ColorSetter implements Setter {
        }
 }
 
+////ComponentPresetSetter  -  sets a ComponentPreset value
+class ComponentPresetSetter implements Setter {
+       private final Reflection.Method setMethod;
+       
+       public ComponentPresetSetter(Reflection.Method set) {
+               this.setMethod = set;
+       }
+       
+       @Override
+       public void set(RocketComponent c, String name, HashMap<String, String> attributes,
+                       WarningSet warnings) {
+               String manufacturerName = attributes.get("manufacturer");
+               if (manufacturerName == null) {
+                       warnings.add(Warning.fromString("Invalid ComponentPreset for component " + c.getName() + ", no manufacturer specified.  Ignored"));
+                       return;
+               }
+               
+               String productNo = attributes.get("partno");
+               if (productNo == null) {
+                       warnings.add(Warning.fromString("Invalid ComponentPreset for component " + c.getName() + ", no partno specified.  Ignored"));
+                       return;
+               }
+               
+               String digest = attributes.get("digest");
+               if (digest == null) {
+                       warnings.add(Warning.fromString("Invalid ComponentPreset for component " + c.getName() + ", no digest specified."));
+               }
+               
+               String type = attributes.get("type");
+               if (type == null) {
+                       warnings.add(Warning.fromString("Invalid ComponentPreset for component " + c.getName() + ", no type specified."));
+               }
+               
+               List<ComponentPreset> presets = Application.getComponentPresetDao().find(manufacturerName, productNo);
+               
+               ComponentPreset matchingPreset = null;
+               
+               for (ComponentPreset preset : presets) {
+                       if (digest != null && preset.getDigest().equals(digest)) {
+                               // Found one with matching digest.  Take it.
+                               matchingPreset = preset;
+                               break;
+                       }
+                       if (type != null && preset.getType().name().equals(type) && matchingPreset != null) {
+                               // Found the first one with matching type.
+                               matchingPreset = preset;
+                       }
+               }
+               
+               // Was any found?
+               if (matchingPreset == null) {
+                       warnings.add(Warning.fromString("No matching ComponentPreset for component " + c.getName() + " found matching " + manufacturerName + " " + productNo));
+                       return;
+               }
+               
+               if (digest != null && !matchingPreset.getDigest().equals(digest)) {
+                       warnings.add(Warning.fromString("ComponentPreset for component " + c.getName() + " has wrong digest"));
+               }
+               
+               setMethod.invoke(c, matchingPreset);
+       }
+}
 
 
+////MaterialSetter  -  sets a Material value
 class MaterialSetter implements Setter {
        private final Reflection.Method setMethod;
        private final Material.Type type;
@@ -1985,12 +2193,12 @@ class MaterialSetter implements Setter {
                
                // Check type if specified
                str = attributes.remove("type");
-               if (str != null && !type.name().toLowerCase().equals(str)) {
+               if (str != null && !type.name().toLowerCase(Locale.ENGLISH).equals(str)) {
                        warnings.add(Warning.fromString("Illegal material type specified, ignoring."));
                        return;
                }
                
-               mat = Databases.findMaterial(type, name, density, false);
+               mat = Databases.findMaterial(type, name, density);
                
                setMethod.invoke(c, mat);
        }
@@ -1999,6 +2207,7 @@ class MaterialSetter implements Setter {
 
 
 
+
 class PositionSetter implements Setter {
        
        @Override
index 2f1b2a4ec14052222a773e0254c4c63fa894885f..5415832a7ea53810d667520b2fd43c026068f22d 100644 (file)
@@ -1,23 +1,24 @@
 package net.sf.openrocket.file.openrocket.savers;
 
 import java.util.List;
+import java.util.Locale;
 
 import net.sf.openrocket.rocketcomponent.ExternalComponent;
 
 
 public class ExternalComponentSaver extends RocketComponentSaver {
-
+       
        @Override
        protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
                super.addParams(c, elements);
                
-               ExternalComponent ext = (ExternalComponent)c;
+               ExternalComponent ext = (ExternalComponent) c;
                
                // Finish enum names are currently the same except for case
-               elements.add("<finish>" + ext.getFinish().name().toLowerCase() + "</finish>");
+               elements.add("<finish>" + ext.getFinish().name().toLowerCase(Locale.ENGLISH) + "</finish>");
                
                // Material
                elements.add(materialParam(ext.getMaterial()));
        }
-               
+       
 }
index 8756d89f72d1b7eefc3c646877682174a9cfbb53..7eaffc69334a59936b883478570e2dfbfe16148c 100644 (file)
@@ -1,34 +1,35 @@
 package net.sf.openrocket.file.openrocket.savers;
 
 import java.util.List;
+import java.util.Locale;
 
 import net.sf.openrocket.util.MathUtil;
 
 public class FinSetSaver extends ExternalComponentSaver {
-
+       
        @Override
        protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
                super.addParams(c, elements);
-
+               
                net.sf.openrocket.rocketcomponent.FinSet fins = (net.sf.openrocket.rocketcomponent.FinSet) c;
                elements.add("<fincount>" + fins.getFinCount() + "</fincount>");
                elements.add("<rotation>" + (fins.getBaseRotation() * 180.0 / Math.PI) + "</rotation>");
                elements.add("<thickness>" + fins.getThickness() + "</thickness>");
-               elements.add("<crosssection>" + fins.getCrossSection().name().toLowerCase()
+               elements.add("<crosssection>" + fins.getCrossSection().name().toLowerCase(Locale.ENGLISH)
                                + "</crosssection>");
                elements.add("<cant>" + (fins.getCantAngle() * 180.0 / Math.PI) + "</cant>");
                
                // Save fin tabs only if they exist (compatibility with file version < 1.1)
-               if (!MathUtil.equals(fins.getTabHeight(),0) &&
+               if (!MathUtil.equals(fins.getTabHeight(), 0) &&
                                !MathUtil.equals(fins.getTabLength(), 0)) {
                        
                        elements.add("<tabheight>" + fins.getTabHeight() + "</tabheight>");
                        elements.add("<tablength>" + fins.getTabLength() + "</tablength>");
                        elements.add("<tabposition relativeto=\"" +
-                                       fins.getTabRelativePosition().name().toLowerCase() + "\">" +
+                                       fins.getTabRelativePosition().name().toLowerCase(Locale.ENGLISH) + "\">" +
                                        fins.getTabShift() + "</tabposition>");
-               
+                       
                }
        }
-
+       
 }
index 22dcaa9cc2a11f53a3feaca7c02f415c729146f4..a73d8fd6988729e0fbbc8c8db015d2b575d62749 100644 (file)
@@ -1,27 +1,28 @@
 package net.sf.openrocket.file.openrocket.savers;
 
 import java.util.List;
+import java.util.Locale;
 
 import net.sf.openrocket.rocketcomponent.RecoveryDevice;
 
 
 public class RecoveryDeviceSaver extends MassObjectSaver {
-
+       
        @Override
        protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
                super.addParams(c, elements);
-
+               
                RecoveryDevice dev = (RecoveryDevice) c;
-
+               
                if (dev.isCDAutomatic())
                        elements.add("<cd>auto</cd>");
                else
                        elements.add("<cd>" + dev.getCD() + "</cd>");
-
-               elements.add("<deployevent>" + dev.getDeployEvent().name().toLowerCase() + "</deployevent>");
+               
+               elements.add("<deployevent>" + dev.getDeployEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "") + "</deployevent>");
                elements.add("<deployaltitude>" + dev.getDeployAltitude() + "</deployaltitude>");
                elements.add("<deploydelay>" + dev.getDeployDelay() + "</deploydelay>");
                elements.add(materialParam(dev.getMaterial()));
        }
-
+       
 }
index 3cd29acb14de07113c8d0fb859b4dc47432e2d9f..a4892902afa73822e9eca0d46e8112ab131feea5 100644 (file)
@@ -3,21 +3,26 @@ package net.sf.openrocket.file.openrocket.savers;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 
 import net.sf.openrocket.file.RocketSaver;
+import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.ThrustCurveMotor;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.rocketcomponent.ComponentAssembly;
 import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Color;
 import net.sf.openrocket.util.LineStyle;
 
 
 public class RocketComponentSaver {
+       private static final Translator trans = Application.getTranslator();
        
        protected RocketComponentSaver() {
                // Prevent instantiation from outside the package
@@ -26,7 +31,14 @@ public class RocketComponentSaver {
        protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
                elements.add("<name>" + RocketSaver.escapeXML(c.getName()) + "</name>");
                
-
+               ComponentPreset preset = c.getPresetComponent();
+               if (preset != null) {
+                       elements.add("<preset type=\"" + preset.getType() +
+                                       "\" manufacturer=\"" + preset.getManufacturer().getSimpleName() +
+                                       "\" partno=\"" + preset.getPartNo() + "\" digest=\"" + preset.getDigest() + "\"/>");
+               }
+               
+               
                // Save color and line style if significant
                if (!(c instanceof Rocket || c instanceof ComponentAssembly)) {
                        Color color = c.getColor();
@@ -38,19 +50,19 @@ public class RocketComponentSaver {
                        LineStyle style = c.getLineStyle();
                        if (style != null) {
                                // Type names currently equivalent to the enum names except for case.
-                               elements.add("<linestyle>" + style.name().toLowerCase() + "</linestyle>");
+                               elements.add("<linestyle>" + style.name().toLowerCase(Locale.ENGLISH) + "</linestyle>");
                        }
                }
                
-
+               
                // Save position unless "AFTER"
                if (c.getRelativePosition() != RocketComponent.Position.AFTER) {
                        // The type names are currently equivalent to the enum names except for case.
-                       String type = c.getRelativePosition().name().toLowerCase();
+                       String type = c.getRelativePosition().name().toLowerCase(Locale.ENGLISH);
                        elements.add("<position type=\"" + type + "\">" + c.getPositionValue() + "</position>");
                }
                
-
+               
                // Overrides
                boolean overridden = false;
                if (c.isMassOverridden()) {
@@ -66,7 +78,7 @@ public class RocketComponentSaver {
                                        + "</overridesubcomponents>");
                }
                
-
+               
                // Comment
                if (c.getComment().length() > 0) {
                        elements.add("<comment>" + RocketSaver.escapeXML(c.getComment()) + "</comment>");
@@ -75,8 +87,8 @@ public class RocketComponentSaver {
        }
        
        
-
-
+       
+       
        protected final String materialParam(Material mat) {
                return materialParam("material", mat);
        }
@@ -99,7 +111,9 @@ public class RocketComponentSaver {
                        throw new BugException("Unknown material type: " + mat.getType());
                }
                
-               return str + " density=\"" + mat.getDensity() + "\">" + RocketSaver.escapeXML(mat.getName()) + "</" + tag + ">";
+               String baseName = trans.getBaseText("material", mat.getName());
+               
+               return str + " density=\"" + mat.getDensity() + "\">" + RocketSaver.escapeXML(baseName) + "</" + tag + ">";
        }
        
        
@@ -121,7 +135,7 @@ public class RocketComponentSaver {
                        
                        elements.add("  <motor configid=\"" + id + "\">");
                        if (motor.getMotorType() != Motor.Type.UNKNOWN) {
-                               elements.add("    <type>" + motor.getMotorType().name().toLowerCase() + "</type>");
+                               elements.add("    <type>" + motor.getMotorType().name().toLowerCase(Locale.ENGLISH) + "</type>");
                        }
                        if (motor instanceof ThrustCurveMotor) {
                                ThrustCurveMotor m = (ThrustCurveMotor) motor;
@@ -144,7 +158,7 @@ public class RocketComponentSaver {
                }
                
                elements.add("  <ignitionevent>"
-                               + mount.getIgnitionEvent().name().toLowerCase().replace("_", "")
+                               + mount.getIgnitionEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "")
                                + "</ignitionevent>");
                
                elements.add("  <ignitiondelay>" + mount.getIgnitionDelay() + "</ignitiondelay>");
index e8b7a345570222718d2b7186249b5f6dcca775cb..be7c52af809133a7fa31239e1b20065b7d1d74f1 100644 (file)
@@ -2,51 +2,49 @@ package net.sf.openrocket.file.openrocket.savers;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 import net.sf.openrocket.rocketcomponent.ReferenceType;
 import net.sf.openrocket.rocketcomponent.Rocket;
 
-
 public class RocketSaver extends RocketComponentSaver {
-
+       
        private static final RocketSaver instance = new RocketSaver();
-
+       
        public static ArrayList<String> getElements(net.sf.openrocket.rocketcomponent.RocketComponent c) {
                ArrayList<String> list = new ArrayList<String>();
-
+               
                list.add("<rocket>");
                instance.addParams(c, list);
                list.add("</rocket>");
-
+               
                return list;
        }
-
-
-
+       
        @Override
        protected void addParams(net.sf.openrocket.rocketcomponent.RocketComponent c, List<String> elements) {
                super.addParams(c, elements);
-
+               
                Rocket rocket = (Rocket) c;
                
                if (rocket.getDesigner().length() > 0) {
-                       elements.add("<designer>" 
+                       elements.add("<designer>"
                                        + net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getDesigner())
                                        + "</designer>");
                }
                if (rocket.getRevision().length() > 0) {
-                       elements.add("<revision>" 
-                                       + net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getRevision()) 
+                       elements.add("<revision>"
+                                       + net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getRevision())
                                        + "</revision>");
                }
-
-
+               
+               
                // Motor configurations
                String defId = rocket.getDefaultConfiguration().getMotorConfigurationID();
                for (String id : rocket.getMotorConfigurationIDs()) {
                        if (id == null)
                                continue;
-
+                       
                        String str = "<motorconfiguration configid=\"" + id + "\"";
                        if (id.equals(defId))
                                str += " default=\"true\"";
@@ -55,19 +53,19 @@ public class RocketSaver extends RocketComponentSaver {
                                str += "/>";
                        } else {
                                str += "><name>" + net.sf.openrocket.file.RocketSaver.escapeXML(rocket.getMotorConfigurationName(id))
-                                       + "</name></motorconfiguration>";
+                                               + "</name></motorconfiguration>";
                        }
                        elements.add(str);
                }
                
                // Reference diameter
-               elements.add("<referencetype>" + rocket.getReferenceType().name().toLowerCase()
+               elements.add("<referencetype>" + rocket.getReferenceType().name().toLowerCase(Locale.ENGLISH)
                                + "</referencetype>");
                if (rocket.getReferenceType() == ReferenceType.CUSTOM) {
                        elements.add("<customreference>" + rocket.getCustomReferenceLength()
                                        + "</customreference>");
                }
-
+               
        }
-
+       
 }
index e0b1b58dc13a7b3cb1e94a9d32eba3b4a4310a77..23f591f313ea445e4a0a19295799692f65704b6e 100644 (file)
@@ -2,6 +2,7 @@ package net.sf.openrocket.file.openrocket.savers;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Stage;
@@ -27,7 +28,7 @@ public class StageSaver extends ComponentAssemblySaver {
                
                if (stage.getStageNumber() > 0) {
                        elements.add("<separationevent>"
-                                       + stage.getSeparationEvent().name().toLowerCase().replace("_", "")
+                                       + stage.getSeparationEvent().name().toLowerCase(Locale.ENGLISH).replace("_", "")
                                        + "</separationevent>");
                        elements.add("<separationdelay>" + stage.getSeparationDelay() + "</separationdelay>");
                }
index d7bb1ed7b0cb8d5e75f8982e7c5428f20cbe4058..0a4169f9e143880a826161c77b666306b86a89ff 100644 (file)
@@ -2,26 +2,27 @@ package net.sf.openrocket.file.openrocket.savers;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 import net.sf.openrocket.rocketcomponent.NoseCone;
 import net.sf.openrocket.rocketcomponent.Transition;
 
 
 public class TransitionSaver extends SymmetricComponentSaver {
-
+       
        private static final TransitionSaver instance = new TransitionSaver();
-
+       
        public static ArrayList<String> getElements(net.sf.openrocket.rocketcomponent.RocketComponent c) {
                ArrayList<String> list = new ArrayList<String>();
-
+               
                list.add("<transition>");
                instance.addParams(c, list);
                list.add("</transition>");
-
+               
                return list;
        }
-
-
+       
+       
        /*
         * Note:  This method must be capable of handling nose cones as well.
         */
@@ -30,31 +31,31 @@ public class TransitionSaver extends SymmetricComponentSaver {
                super.addParams(c, elements);
                net.sf.openrocket.rocketcomponent.Transition trans = (net.sf.openrocket.rocketcomponent.Transition) c;
                boolean nosecone = (trans instanceof NoseCone);
-
-
+               
+               
                Transition.Shape shape = trans.getType();
-               elements.add("<shape>" + shape.name().toLowerCase() + "</shape>");
+               elements.add("<shape>" + shape.name().toLowerCase(Locale.ENGLISH) + "</shape>");
                if (shape.isClippable()) {
                        elements.add("<shapeclipped>" + trans.isClipped() + "</shapeclipped>");
                }
                if (shape.usesParameter()) {
                        elements.add("<shapeparameter>" + trans.getShapeParameter() + "</shapeparameter>");
                }
-
-
+               
+               
                if (!nosecone) {
                        if (trans.isForeRadiusAutomatic())
                                elements.add("<foreradius>auto</foreradius>");
                        else
                                elements.add("<foreradius>" + trans.getForeRadius() + "</foreradius>");
                }
-
+               
                if (trans.isAftRadiusAutomatic())
                        elements.add("<aftradius>auto</aftradius>");
                else
                        elements.add("<aftradius>" + trans.getAftRadius() + "</aftradius>");
-
-
+               
+               
                if (!nosecone) {
                        elements.add("<foreshoulderradius>" + trans.getForeShoulderRadius()
                                        + "</foreshoulderradius>");
@@ -65,7 +66,7 @@ public class TransitionSaver extends SymmetricComponentSaver {
                        elements.add("<foreshouldercapped>" + trans.isForeShoulderCapped()
                                        + "</foreshouldercapped>");
                }
-
+               
                elements.add("<aftshoulderradius>" + trans.getAftShoulderRadius()
                                + "</aftshoulderradius>");
                elements.add("<aftshoulderlength>" + trans.getAftShoulderLength()
@@ -75,5 +76,5 @@ public class TransitionSaver extends SymmetricComponentSaver {
                elements.add("<aftshouldercapped>" + trans.isAftShoulderCapped()
                                + "</aftshouldercapped>");
        }
-
+       
 }
index 9686b9794a481f5f08dadcc331274509f93a5dad..431db2650dd2cde09d0ad207e33250769252d28e 100644 (file)
@@ -79,6 +79,10 @@ public class RocksimCommonConstants {
     public static final String ROCK_SIM_DOCUMENT = "RockSimDocument";
     public static final String FILE_VERSION = "FileVersion";
     public static final String DESIGN_INFORMATION = "DesignInformation";
+    public static final String TUBE_FIN_SET = "TubeFinSet";
+    public static final String RING_TAIL = "RingTail";
+    public static final String EXTERNAL_POD = "ExternalPod";
+
     /**
      * Length conversion.  Rocksim is in millimeters, OpenRocket in meters.
      */
@@ -103,7 +107,4 @@ public class RocksimCommonConstants {
      * Radius conversion.  Rocksim is always in diameters, OpenRocket mostly in radius.
      */
     public static final int ROCKSIM_TO_OPENROCKET_RADIUS = 2 * ROCKSIM_TO_OPENROCKET_LENGTH;
-    public static final String TUBE_FIN_SET = "TubeFinSet";
-    public static final String RING_TAIL = "RingTail";
-    public static final String EXTERNAL_POD = "ExternalPod";
 }
index cd580ea1e82835c13e4b341575f8ac695c7107fd..8d24e24447ec284b86eb5596c3f65e87c9fb8d74 100644 (file)
@@ -5,38 +5,57 @@ package net.sf.openrocket.file.rocksim;
 
 import net.sf.openrocket.rocketcomponent.Transition;
 
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * Models the nose cone shape of a rocket.  Maps from Rocksim's notion to OpenRocket's.
  */
 public enum RocksimNoseConeCode {
-    CONICAL         (0, Transition.Shape.CONICAL),
-    OGIVE           (1, Transition.Shape.OGIVE),
-    PARABOLIC       (2, Transition.Shape.ELLIPSOID),  //Rocksim' PARABOLIC most closely resembles an ELLIPSOID in OpenRocket
-    ELLIPTICAL      (3, Transition.Shape.ELLIPSOID),
-    POWER_SERIES    (4, Transition.Shape.POWER),
+    CONICAL(0, Transition.Shape.CONICAL, "Conic", "Cone"),
+    OGIVE(1, Transition.Shape.OGIVE),
+    PARABOLIC(2, Transition.Shape.ELLIPSOID),  //Rocksim' PARABOLIC most closely resembles an ELLIPSOID in OpenRocket
+    ELLIPTICAL(3, Transition.Shape.ELLIPSOID),
+    POWER_SERIES(4, Transition.Shape.POWER),
     PARABOLIC_SERIES(5, Transition.Shape.PARABOLIC),
-    HAACK           (6, Transition.Shape.HAACK);
+    HAACK(6, Transition.Shape.HAACK);
 
-    /** The Rocksim enumeration value. Sent in XML. */
+    /**
+     * The Rocksim enumeration value. Sent in XML.
+     */
     private final int ordinal;
-    
-    /** The corresponding OpenRocket shape. */
+
+    /**
+     * The corresponding OpenRocket shape.
+     */
     private final Transition.Shape shape;
 
+    /**
+     * Names of the shape that are sometimes found in NCDATA.CSV
+     */
+    private Set<String> shapeNames = new HashSet<String>();
+
     /**
      * Constructor.
-     * 
-     * @param idx    the Rocksim shape code
-     * @param aShape the corresponding OpenRocket shape
+     *
+     * @param idx           the Rocksim shape code
+     * @param aShape        the corresponding OpenRocket shape
+     * @param theShapeNames an array of alternate names
      */
-    private RocksimNoseConeCode(int idx, Transition.Shape aShape) {
+    private RocksimNoseConeCode(int idx, Transition.Shape aShape, String... theShapeNames) {
         ordinal = idx;
         shape = aShape;
+        shapeNames.add(this.name().toLowerCase());
+        if (theShapeNames != null) {
+            for (String theShapeName : theShapeNames) {
+                shapeNames.add(theShapeName.toLowerCase());
+            }
+        }
     }
 
     /**
      * Get the OpenRocket shape that corresponds to the Rocksim shape.
-     * 
+     *
      * @return a shape
      */
     public Transition.Shape asOpenRocket() {
@@ -45,8 +64,8 @@ public enum RocksimNoseConeCode {
 
     /**
      * Lookup an instance of this enum based upon the Rocksim code.
-     * 
-     * @param rocksimShapeCode  the Rocksim code (from XML)
+     *
+     * @param rocksimShapeCode the Rocksim code (from XML)
      * @return an instance of this enum
      */
     public static RocksimNoseConeCode fromCode(int rocksimShapeCode) {
@@ -61,9 +80,8 @@ public enum RocksimNoseConeCode {
 
     /**
      * Lookup an ordinal value for the Rocksim code.
-     * 
-     * @param type  the OR Shape
-     *              
+     *
+     * @param type the OR Shape
      * @return the Rocksim code
      */
     public static int toCode(Transition.Shape type) {
@@ -78,4 +96,36 @@ public enum RocksimNoseConeCode {
         }
         return ELLIPTICAL.ordinal; //Default
     }
+
+    /**
+     * Given the name of a shape, map it into an instance of this enum.
+     *
+     * @param theName the name of the shape; case does not matter
+     * @return the corresponding enum instance; defaults to PARABOLIC if not found.
+     */
+    public static RocksimNoseConeCode fromShapeName(String theName) {
+        RocksimNoseConeCode[] values = values();
+        for (RocksimNoseConeCode value : values) {
+            if (value.shapeNames.contains(theName.toLowerCase())) {
+                return value;
+            }
+        }
+        return PARABOLIC; //Default
+    }
+
+    /**
+     * Convenience method that determines if the parameter is an integer that refers to a shape code, or the name
+     * of the shape itself.  This basically combines fromCode and fromShapeName into one method.
+     *
+     * @param nameOrOrdinalString the shape number or shape name
+     * @return an instance of this enum; defaults to PARABOLIC if not found
+     */
+    public static RocksimNoseConeCode fromShapeNameOrCode(String nameOrOrdinalString) {
+        try {
+            return fromCode(Integer.parseInt(nameOrOrdinalString));
+        }
+        catch (NumberFormatException nfe) {
+            return fromShapeName(nameOrOrdinalString);
+        }
+    }
 }
index 47e28bd5c5426c562fa561d5739bdfac171c5d50..9d601efb287d80b466aba82960fad12c4958ac0d 100644 (file)
@@ -48,7 +48,7 @@ public class RocksimSaver extends RocketSaver {
             marshaller.marshal(toRocksimDocumentDTO(doc), sw);
             return sw.toString();
         } catch (Exception e) {
-            e.printStackTrace();
+            log.error("Could not marshall a design to Rocksim format. " + e.getMessage());
         }
 
         return null;
index 6302c62a3e19baa9a3ea917764c8f3ef9b37ba32..35296d415ea2e868d31aea12ccc57a0c9aafe990 100644 (file)
  */
 package net.sf.openrocket.file.rocksim.importt;
 
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+
 import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.database.Databases;
 import net.sf.openrocket.file.rocksim.RocksimCommonConstants;
 import net.sf.openrocket.file.rocksim.RocksimDensityType;
 import net.sf.openrocket.file.simplesax.AbstractElementHandler;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
-import org.xml.sax.SAXException;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.HashMap;
+import org.xml.sax.SAXException;
 
 /**
  * An abstract base class that handles common parsing.  All Rocksim component handlers are subclassed from here.
  *
- * @param <C>   the specific RocketComponent subtype for which the concrete handler can create
+ * @param <C> the specific RocketComponent subtype for which the concrete handler can create
  */
 public abstract class BaseHandler<C extends RocketComponent> extends AbstractElementHandler {
-
-    /**
-     * Prepend rocksim materials.
-     */
-    public static final String ROCKSIM_MATERIAL_PREFIX = "RS: ";
-    /**
-     * The overridden mass.
-     */
-    private Double mass = 0d;
-    /**
-     * The overridden Cg.
-     */
-    private Double cg = 0d;
-    /**
-     * The density of the material in the component.
-     */
-    private Double density = 0d;
-    /**
-     * The internal Rocksim density type.
-     */
-    private RocksimDensityType densityType = RocksimDensityType.ROCKSIM_BULK;
-
-    /**
-     * The material name.
-     */
-    private String materialName = "";
-
-    /**
-     * The SAX method called when the closing element tag is reached.
-     *
-     * @param element        the element name.
-     * @param attributes    attributes of the element.
-     * @param content        the textual content of the element.
-     * @param warnings        the warning set to store warnings in.
-     * @throws SAXException
-     */
-
-    @Override
-    public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        final C component = getComponent();
-        try {
-            if (RocksimCommonConstants.NAME.equals(element)) {
-                component.setName(content);
-            }
-            if (RocksimCommonConstants.KNOWN_MASS.equals(element)) {
-                mass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
-            }
-            if (RocksimCommonConstants.DENSITY.equals(element)) {
-                density = Math.max(0d, Double.parseDouble(content) );
-            }
-            if (RocksimCommonConstants.KNOWN_CG.equals(element)) {
-                cg = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
-            }
-            if (RocksimCommonConstants.USE_KNOWN_CG.equals(element)) {  //Rocksim sets UseKnownCG to true to control the override of both cg and mass
-                boolean override = "1".equals(content);
-                setOverride(component, override, mass, cg);
-            }
-            if (RocksimCommonConstants.DENSITY_TYPE.equals(element)) {
-                densityType = RocksimDensityType.fromCode(Integer.parseInt(content));
-            }
-        }
-        catch (NumberFormatException nfe) {
-            warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
-            throws SAXException {
-        /* Because of the order of XML elements in Rocksim, not all information is known at the time it really needs
-           to be acted upon.  So we keep temporary instance variables to be used here at the end of the parsing.
-         */
-        density = computeDensity(densityType, density);
-        RocketComponent component = getComponent();
-        updateComponentMaterial(component, materialName, getMaterialType(), density);
-    }
-
-    /**
-     * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
-     * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
-     * Some G10 fiberglass materials are in cubic units, other G10 fiberglass is in square units.  And due to a
-     * Rocksim bug, some densities are 0 when they clearly should not be.
-     *
-     * This may be overridden for specific component density computations.
-     *
-     * @param type       the rocksim density
-     * @param rawDensity the density as specified in the Rocksim design file
-     * @return a value in OpenRocket SURFACE density units
-     */
-    protected double computeDensity(RocksimDensityType type, double rawDensity) {
-        return rawDensity / type.asOpenRocket();
-    }
-
-    /**
-     * If the Rocksim component does not override the mass, then create a Material based upon the density defined
-     * for that component.  This *should* result in a consistent representation of Cg between Rocksim and OpenRocket.
-     *
-     * @param component       the component
-     * @param type            the type of the material
-     * @param density         the density in g/cm^3
-     * @param definedMaterial the material that is currently defined on the component; used only to get the name
-     *                        as it appears in Rocksim
-     */
-    public static void updateComponentMaterial(RocketComponent component, String definedMaterial, Material.Type type,
-                                               double density) {
-        if (definedMaterial != null) {
-            Material custom = createCustomMaterial(type, definedMaterial, density);
-            setMaterial(component, custom);
-        }
-    }
-
-    /**
-     * Override the mass and Cg of the component.
-     *
-     * @param component  the component
-     * @param override   true if any override should happen
-     * @param mass       the override mass
-     * @param cg         the override cg
-     */
-    public static void setOverride(RocketComponent component, boolean override, double mass, double cg) {
-        if (override) {
-            component.setCGOverridden(override);
-            component.setMassOverridden(override);
-            component.setOverrideSubcomponents(false); //Rocksim does not support this type of override
-            component.setOverrideMass(mass);
-            component.setOverrideCGX(cg);
-        }
-    }
-
-    /**
-     * Get the component this handler is working upon.
-     *
-     * @return a component
-     */
-    protected abstract C getComponent();
-
-    /**
-     * Get the required type of material for this component.
-     *
-     * @return the required material type
-     */
-    protected abstract Material.Type getMaterialType();
-
-    /**
-     * Some CG positions in Rocksim do not correspond to the CG position reference in OpenRocket.
-     *
-     * @param theCG  the CG value to really use when overriding CG on the OpenRocket component
-     */
-    protected void setCG(double theCG) {
-        cg = theCG;
-    }
-
-    /**
-     * Set the material name as specified in the Rocksim design file.
-     *
-     * @param content  the material name
-     */
-    protected void setMaterialName(String content) {
-        materialName = content;
-    }
-
-    /**
-     * Add child to parent only if the child is compatible.  Otherwise add to warning set.
-     * 
-     * @param parent  the parent component
-     * @param child   the child component
-     * @param warnings the warning set
-     * 
-     * @return true if the child is compatible with parent
-     */
-    protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child, WarningSet warnings) {
-        if (!parent.isCompatible(child)) {
-            warnings.add(child.getName() + " can not be attached to "
-                         + parent.getComponentName() + ", ignoring component.");
-            return false;
-        }
-        else {
-            return true;
-        }
-    }
-    
-    /**
-     * Create a custom material based on the density.  The name of the material is prepended with 'RS: ' to
-     * indicate it came from a RockSim material.
-     *
-     * @param type    the type of the material
-     * @param name    the name of the component
-     * @param density the density
-     *
-     * @return a Material instance
-     */
-    public static Material createCustomMaterial(Material.Type type, String name, double density) {
-        return Material.newMaterial(type, ROCKSIM_MATERIAL_PREFIX + name, density, true);
-    }
-
-    /**
-     * Set the material onto an instance of RocketComponent.  This is done because only some subtypes of RocketComponent
-     * have the setMaterial method.  Unfortunately the supertype cannot be used.
-     *
-     * @param component  the component who's material is to be set
-     * @param material the material to be set on the component (defined by getComponent())
-     */
-    private static void setMaterial(RocketComponent component, Material material) {
-        try {
-            final Method method = getMethod(component, "setMaterial", new Class[]{Material.class});
-            if (method != null) {
-                method.invoke(component, material);
-            }
-        }
-        catch (IllegalAccessException ignored) {
-        }
-        catch (InvocationTargetException ignored) {
-        }
-    }
-
-    /**
-     * Find a method by name and argument list.
-     *
-     * @param component  the component who's material is to be seta
-     * @param name the method name
-     * @param args the class types of the parameters
-     *
-     * @return the Method instance, or null
-     */
-    private static Method getMethod(RocketComponent component, String name, Class[] args) {
-        Method method = null;
-        try {
-            method = component.getClass().getMethod(name, args);
-        }
-        catch (NoSuchMethodException ignored) {
-        }
-        return method;
-    }
-
+       
+       /**
+        * Prepend rocksim materials.
+        */
+       public static final String ROCKSIM_MATERIAL_PREFIX = "RS: ";
+       /**
+        * The overridden mass.
+        */
+       private Double mass = 0d;
+       /**
+        * The overridden Cg.
+        */
+       private Double cg = 0d;
+       /**
+        * The density of the material in the component.
+        */
+       private Double density = 0d;
+       /**
+        * The internal Rocksim density type.
+        */
+       private RocksimDensityType densityType = RocksimDensityType.ROCKSIM_BULK;
+       
+       /**
+        * The material name.
+        */
+       private String materialName = "";
+       
+       /**
+        * The SAX method called when the closing element tag is reached.
+        *
+        * @param element    the element name.
+        * @param attributes attributes of the element.
+        * @param content    the textual content of the element.
+        * @param warnings   the warning set to store warnings in.
+        *
+        * @throws SAXException
+        */
+       
+       @Override
+       public void closeElement(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+                       throws SAXException {
+               final C component = getComponent();
+               try {
+                       if (RocksimCommonConstants.NAME.equals(element)) {
+                               component.setName(content);
+                       }
+                       if (RocksimCommonConstants.KNOWN_MASS.equals(element)) {
+                               mass = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_MASS);
+                       }
+                       if (RocksimCommonConstants.DENSITY.equals(element)) {
+                               density = Math.max(0d, Double.parseDouble(content));
+                       }
+                       if (RocksimCommonConstants.KNOWN_CG.equals(element)) {
+                               cg = Math.max(0d, Double.parseDouble(content) / RocksimCommonConstants.ROCKSIM_TO_OPENROCKET_LENGTH);
+                       }
+                       if (RocksimCommonConstants.USE_KNOWN_CG.equals(element)) { //Rocksim sets UseKnownCG to true to control the override of both cg and mass
+                               boolean override = "1".equals(content);
+                               setOverride(component, override, mass, cg);
+                       }
+                       if (RocksimCommonConstants.DENSITY_TYPE.equals(element)) {
+                               densityType = RocksimDensityType.fromCode(Integer.parseInt(content));
+                       }
+               } catch (NumberFormatException nfe) {
+                       warnings.add("Could not convert " + element + " value of " + content + ".  It is expected to be a number.");
+               }
+       }
+       
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings)
+                       throws SAXException {
+               /* Because of the order of XML elements in Rocksim, not all information is known at the time it really needs
+                  to be acted upon.  So we keep temporary instance variables to be used here at the end of the parsing.
+                */
+               density = computeDensity(densityType, density);
+               RocketComponent component = getComponent();
+               updateComponentMaterial(component, materialName, getMaterialType(), density);
+       }
+       
+       /**
+        * Compute the density.  Rocksim does strange things with densities.  For some streamer material it's in cubic,
+        * rather than square, units.  In those cases it needs to be converted to an appropriate SURFACE material density.
+        * Some G10 fiberglass materials are in cubic units, other G10 fiberglass is in square units.  And due to a Rocksim
+        * bug, some densities are 0 when they clearly should not be.
+        * <p/>
+        * This may be overridden for specific component density computations.
+        *
+        * @param type       the rocksim density
+        * @param rawDensity the density as specified in the Rocksim design file
+        *
+        * @return a value in OpenRocket SURFACE density units
+        */
+       protected double computeDensity(RocksimDensityType type, double rawDensity) {
+               return rawDensity / type.asOpenRocket();
+       }
+       
+       /**
+        * If the Rocksim component does not override the mass, then create a Material based upon the density defined for
+        * that component.  This *should* result in a consistent representation of Cg between Rocksim and OpenRocket.
+        *
+        * @param component       the component
+        * @param type            the type of the material
+        * @param density         the density in g/cm^3
+        * @param definedMaterial the material that is currently defined on the component; used only to get the name as it
+        *                        appears in Rocksim
+        */
+       public static void updateComponentMaterial(RocketComponent component, String definedMaterial, Material.Type type,
+                       double density) {
+               if (definedMaterial != null) {
+                       Material custom = createCustomMaterial(type, definedMaterial, density);
+                       setMaterial(component, custom);
+               }
+       }
+       
+       /**
+        * Override the mass and Cg of the component.
+        *
+        * @param component the component
+        * @param override  true if any override should happen
+        * @param mass      the override mass
+        * @param cg        the override cg
+        */
+       public static void setOverride(RocketComponent component, boolean override, double mass, double cg) {
+               if (override) {
+                       component.setCGOverridden(override);
+                       component.setMassOverridden(override);
+                       component.setOverrideSubcomponents(false); //Rocksim does not support this type of override
+                       component.setOverrideMass(mass);
+                       component.setOverrideCGX(cg);
+               }
+       }
+       
+       /**
+        * Get the component this handler is working upon.
+        *
+        * @return a component
+        */
+       protected abstract C getComponent();
+       
+       /**
+        * Get the required type of material for this component.
+        *
+        * @return the required material type
+        */
+       protected abstract Material.Type getMaterialType();
+       
+       /**
+        * Some CG positions in Rocksim do not correspond to the CG position reference in OpenRocket.
+        *
+        * @param theCG the CG value to really use when overriding CG on the OpenRocket component
+        */
+       protected void setCG(double theCG) {
+               cg = theCG;
+       }
+       
+       /**
+        * Set the material name as specified in the Rocksim design file.
+        *
+        * @param content the material name
+        */
+       protected void setMaterialName(String content) {
+               materialName = content;
+       }
+       
+       /**
+        * Get the Rocksim enum of the component's density type.
+        *
+        * @return a Rocksim density type
+        */
+       protected RocksimDensityType getDensityType() {
+               return densityType;
+       }
+       
+       /**
+        * Add child to parent only if the child is compatible.  Otherwise add to warning set.
+        *
+        * @param parent   the parent component
+        * @param child    the child component
+        * @param warnings the warning set
+        *
+        * @return true if the child is compatible with parent
+        */
+       protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child, WarningSet warnings) {
+               return isCompatible(parent, child, warnings, false);
+       }
+       
+       /**
+        * Add child to parent only if the child is compatible.  Otherwise add to warning set.
+        *
+        * @param parent   the parent component
+        * @param child    the child component
+        * @param warnings the warning set
+        * @param suppressWarnings suppress warnings, just return the boolean
+        *
+        * @return true if the child is compatible with parent
+        */
+       protected static boolean isCompatible(RocketComponent parent, Class<? extends RocketComponent> child,
+                       WarningSet warnings,
+                       boolean suppressWarnings) {
+               if (!parent.isCompatible(child)) {
+                       if (!suppressWarnings) {
+                               warnings.add(child.getName() + " can not be attached to "
+                                               + parent.getComponentName() + ", ignoring component.");
+                       }
+                       return false;
+               }
+               else {
+                       return true;
+               }
+       }
+       
+       /**
+        * Create a custom material based on the density.
+        *
+        * @param type    the type of the material
+        * @param name    the name of the component
+        * @param density the density
+        *
+        * @return a Material instance
+        */
+       public static Material createCustomMaterial(Material.Type type, String name, double density) {
+               return Databases.findMaterial(type, name, density);
+       }
+       
+       /**
+        * Set the material onto an instance of RocketComponent.  This is done because only some subtypes of RocketComponent
+        * have the setMaterial method.  Unfortunately the supertype cannot be used.
+        *
+        * @param component the component who's material is to be set
+        * @param material  the material to be set on the component (defined by getComponent())
+        */
+       private static void setMaterial(RocketComponent component, Material material) {
+               try {
+                       final Method method = getMethod(component, "setMaterial", new Class[] { Material.class });
+                       if (method != null) {
+                               method.invoke(component, material);
+                       }
+               } catch (IllegalAccessException ignored) {
+               } catch (InvocationTargetException ignored) {
+               }
+       }
+       
+       /**
+        * Find a method by name and argument list.
+        *
+        * @param component the component who's material is to be set
+        * @param name      the method name
+        * @param args      the class types of the parameters
+        *
+        * @return the Method instance, or null
+        */
+       private static Method getMethod(RocketComponent component, String name, Class[] args) {
+               Method method = null;
+               try {
+                       method = component.getClass().getMethod(name, args);
+               } catch (NoSuchMethodException ignored) {
+               }
+               return method;
+       }
+       
 }
index 048a2fd4f2a730b9cefd57fbded3ec34fa323acc..01b49030d0ccf1428bee439da11601780e7416ac 100644 (file)
@@ -330,7 +330,7 @@ class FinSetHandler extends AbstractElementHandler {
      */
     private Coordinate[] toCoordinates (String pointList, WarningSet warnings) {
         List<Coordinate> result = new ArrayList<Coordinate>();
-        if (pointList != null && !pointList.isEmpty()) {
+        if (pointList != null && pointList.length() > 0) {
             String[] points = pointList.split("\\Q|\\E");
             for (String point : points) {
                 String[] aPoint = point.split(",");
index ee8cd22db4aeb7977234aa6632c1c9cbd12b6a0f..2d918af9a4c49bc5d7951c51967228b364e25014 100644 (file)
@@ -5,9 +5,11 @@ package net.sf.openrocket.file.rocksim.importt;
 
 import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.file.rocksim.RocksimCommonConstants;
+import net.sf.openrocket.file.rocksim.RocksimDensityType;
 import net.sf.openrocket.file.simplesax.ElementHandler;
 import net.sf.openrocket.file.simplesax.PlainTextHandler;
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.rocketcomponent.Coaxial;
 import net.sf.openrocket.rocketcomponent.MassComponent;
 import net.sf.openrocket.rocketcomponent.MassObject;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
@@ -21,12 +23,12 @@ import java.util.HashMap;
  */
 class MassObjectHandler extends PositionDependentHandler<MassObject> {
 
-    /** 
+    /**
      * The Rocksim Mass length fudge factor.  Rocksim completely exaggerates the length of a mass object to the point
      * that it looks ridiculous in OpenRocket.  This fudge factor is here merely to get the typical mass object to
-     * render in the OpenRocket UI with it's bounds mostly inside it's parent.  The odd thing about it is that 
-     * Rocksim does not expose the length of a mass object in the UI and actually treats mass objects as point objects -
-     * not 3 or even 2 dimensional.
+     * render in the OpenRocket UI with it's bounds mostly inside it's parent.  The odd thing about it is that Rocksim
+     * does not expose the length of a mass object in the UI and actually treats mass objects as point objects - not 3
+     * or even 2 dimensional.
      */
     public static final int MASS_LEN_FUDGE_FACTOR = 100;
 
@@ -51,12 +53,12 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
     private int typeCode = 0;
 
     /**
-     * Constructor.
-     *l
-     * @param c the parent component
-     * @param warnings  the warning set
-     * 
-     * @throws IllegalArgumentException  thrown if <code>c</code> is null
+     * Constructor. l
+     *
+     * @param c        the parent component
+     * @param warnings the warning set
+     *
+     * @throws IllegalArgumentException thrown if <code>c</code> is null
      */
     public MassObjectHandler(RocketComponent c, WarningSet warnings) throws IllegalArgumentException {
         if (c == null) {
@@ -89,7 +91,7 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
                 //length) and because Rocksim sets the CG of the mass object to really be relative to the front of
                 //the parent.  But that value is already assumed in the position and position value for the component.
                 //Thus it needs to be set to 0 to say that the mass object's CG is at the point of the mass object.
-                super.setCG(0); 
+                super.setCG(0);
             }
             if (RocksimCommonConstants.TYPE_CODE.equals(element)) {
                 typeCode = Integer.parseInt(content);
@@ -104,32 +106,68 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
     }
 
     @Override
-    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws SAXException {
-        if (typeCode == 0) { //General Mass Object
+    public void endHandler(String element, HashMap<String, String> attributes, String content, WarningSet warnings) throws
+                                                                                                                    SAXException {
+        if (inferAsShockCord(typeCode, warnings)) { //Shock Cord
+            mapMassObjectAsShockCord(element, attributes, content, warnings);
+        }
+        else { // typeCode == 0   General Mass Object
             if (isCompatible(parent, MassComponent.class, warnings)) {
                 parent.addChild(mass);
             }
             super.endHandler(element, attributes, content, warnings);
         }
-        else if (typeCode == 1) { //Shock Cord
-            ShockCord cord = new ShockCord();
-            current = cord;
-            if (isCompatible(parent, ShockCord.class, warnings)) {
-                parent.addChild(cord);
-            }
-            super.endHandler(element, attributes, content, warnings);
-            cord.setName(mass.getName());
-
-            setOverride(cord, mass.isMassOverridden(), mass.getOverrideMass(), mass.getOverrideCGX());
+    }
 
-            cord.setRadialDirection(mass.getRadialDirection());
-            cord.setRadialPosition(mass.getRadialPosition());
-            cord.setRadius(mass.getRadius());
+    /**
+     * Rocksim does not have a separate entity for Shock Cords.  It has to be inferred.  Sometimes the typeCode
+     * indicates it's a shock cord, but most times it does not.  This is due to bugs in the Rocksim Component and
+     * Material databases.  Try to infer a shock cord based on it's length and it's material type.  It's somewhat
+     * arbitrary, but if the mass object's length is more than twice the length of it's parent component and it's a LINE
+     * material, then assume a shock cord.
+     *
+     * @param theTypeCode the code from the RKT XML file
+     *
+     * @return true if we think it's a shock cord
+     */
+    private boolean inferAsShockCord(int theTypeCode, WarningSet warnings) {
+        return (theTypeCode == 1 || (mass.getLength() >= 2 * parent.getLength() && RocksimDensityType.ROCKSIM_LINE
+                .equals(getDensityType()))) && isCompatible(parent, ShockCord.class, warnings, true);
+    }
 
-            //Rocksim does not distinguish between total length of the cord and the packed length.  Fudge the
-            //packed length and set the real length.
-            cord.setCordLength(mass.getLength());
-            cord.setLength(cord.getCordLength()/MASS_LEN_FUDGE_FACTOR);
+    /**
+     * If it appears that the mass object is a shock cord, then create an OR shock cord instance.
+     *
+     * @param element    the element name
+     * @param attributes the attributes
+     * @param content    the content of the element
+     * @param warnings   the warning set to store warnings in.
+     *
+     * @throws org.xml.sax.SAXException not thrown
+     */
+    private void mapMassObjectAsShockCord(final String element, final HashMap<String, String> attributes,
+                                          final String content, final WarningSet warnings) throws SAXException {
+        ShockCord cord = new ShockCord();
+        current = cord;
+        if (isCompatible(parent, ShockCord.class, warnings)) {
+            parent.addChild(cord);
+        }
+        super.endHandler(element, attributes, content, warnings);
+        cord.setName(mass.getName());
+
+        setOverride(cord, mass.isMassOverridden(), mass.getOverrideMass(), mass.getOverrideCGX());
+
+        cord.setRadialDirection(mass.getRadialDirection());
+        cord.setRadialPosition(mass.getRadialPosition());
+        cord.setRadius(mass.getRadius());
+
+        //Rocksim does not distinguish between total length of the cord and the packed length.  Fudge the
+        //packed length and set the real length.
+        cord.setCordLength(mass.getLength());
+        cord.setLength(cord.getCordLength() / MASS_LEN_FUDGE_FACTOR);
+        if (parent instanceof Coaxial) {
+            Coaxial parentCoaxial = (Coaxial) parent;
+            cord.setRadius(parentCoaxial.getInnerRadius());
         }
     }
 
@@ -154,7 +192,8 @@ class MassObjectHandler extends PositionDependentHandler<MassObject> {
     }
 
     /**
-     * Get the required type of material for this component.  Does not apply to MassComponents, but does apply to Shock Cords.
+     * Get the required type of material for this component.  Does not apply to MassComponents, but does apply to Shock
+     * Cords.
      *
      * @return LINE
      */
index 0cd180e951cc5e8042067d114cc4ff66ae24b9ee..f4b1720a119ab04f30adf7c910e23d61e05ea6e8 100644 (file)
@@ -48,6 +48,9 @@ class TransitionHandler extends BaseHandler<Transition> {
 
     @Override
     public ElementHandler openElement(String element, HashMap<String, String> attributes, WarningSet warnings) {
+        if (RocksimCommonConstants.ATTACHED_PARTS.equals(element)) {
+            return new AttachedPartsHandler(transition);
+        }
         return PlainTextHandler.INSTANCE;
     }
 
index d5c1f37312df9c759bbb3bf7ef09bf6c66234120..169a4d707208a460a66f2e2ce1c6e1c6534918a1 100644 (file)
@@ -1,11 +1,10 @@
 package net.sf.openrocket.file.simplesax;
 
-import java.util.ArrayDeque;
-import java.util.Deque;
 import java.util.HashMap;
 
 import net.sf.openrocket.aerodynamics.Warning;
 import net.sf.openrocket.aerodynamics.WarningSet;
+import net.sf.openrocket.util.SimpleStack;
 
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
@@ -18,9 +17,9 @@ import org.xml.sax.helpers.DefaultHandler;
 class DelegatorHandler extends DefaultHandler {
        private final WarningSet warnings;
        
-       private final Deque<ElementHandler> handlerStack = new ArrayDeque<ElementHandler>();
-       private final Deque<StringBuilder> elementData = new ArrayDeque<StringBuilder>();
-       private final Deque<HashMap<String, String>> elementAttributes = new ArrayDeque<HashMap<String, String>>();
+       private final SimpleStack<ElementHandler> handlerStack = new SimpleStack<ElementHandler>();
+       private final SimpleStack<StringBuilder> elementData = new SimpleStack<StringBuilder>();
+       private final SimpleStack<HashMap<String, String>> elementAttributes = new SimpleStack<HashMap<String, String>>();
        
        
        // Ignore all elements as long as ignore > 0
index ec17b77514271200d5b23123dc3d4301a302b563..6f9bc2eb2b413d4bafbf7b7a93ff3e0ecd981b4f 100644 (file)
@@ -1,6 +1,8 @@
 package net.sf.openrocket.file.simplesax;
 
 import java.io.IOException;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
 
 import net.sf.openrocket.aerodynamics.WarningSet;
 
@@ -23,7 +25,9 @@ import org.xml.sax.helpers.XMLReaderFactory;
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public class SimpleSAX {
-       
+
+       static final XMLReaderCache cache = new XMLReaderCache(10);
+
        /**
         * Read a simple XML file.
         * 
@@ -35,13 +39,35 @@ public class SimpleSAX {
         */
        public static void readXML(InputSource source, ElementHandler initialHandler,
                        WarningSet warnings) throws IOException, SAXException {
-               
+
                DelegatorHandler xmlhandler = new DelegatorHandler(initialHandler, warnings);
-               
-               XMLReader reader = XMLReaderFactory.createXMLReader();
+
+               XMLReader reader = cache.createXMLReader();
                reader.setContentHandler(xmlhandler);
                reader.setErrorHandler(xmlhandler);
                reader.parse(source);
+               cache.releaseXMLReader(reader);
        }
-       
+
+       private static class XMLReaderCache {
+
+               private final BlockingQueue<XMLReader> queue;
+               private XMLReaderCache( int maxSize ) {
+                       this.queue = new LinkedBlockingQueue<XMLReader>(maxSize);
+               }
+
+               private XMLReader createXMLReader() throws SAXException {
+
+                       XMLReader reader = queue.poll();
+                       if ( reader == null ) {
+                               reader = XMLReaderFactory.createXMLReader();
+                       }
+                       return reader;
+               }
+
+               private void releaseXMLReader( XMLReader reader ) {
+                       queue.offer( reader );
+               }
+       }
+
 }
index 843eed6a77bed1d9c21352f09d4d579de02df2bf..be4b79525a8e57b65ba3d30eb434c3ef7e57bf60 100644 (file)
@@ -1,6 +1,8 @@
 package net.sf.openrocket.gui;
 
 import javax.swing.JSpinner;
+import javax.swing.text.DefaultFormatter;
+import javax.swing.text.DefaultFormatterFactory;
 
 /**
  * Editable editor for a JSpinner.  Simply uses JSpinner.DefaultEditor, which has been made
@@ -9,13 +11,27 @@ import javax.swing.JSpinner;
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 
-public class SpinnerEditor extends JSpinner.NumberEditor {
-//public class SpinnerEditor extends JSpinner.DefaultEditor {
+//public class SpinnerEditor extends JSpinner.NumberEditor {
+public class SpinnerEditor extends JSpinner.DefaultEditor {
 
        public SpinnerEditor(JSpinner spinner) {
-               //super(spinner);
-               super(spinner,"0.0##");
-               //getTextField().setEditable(true);
+               super(spinner);
+               //super(spinner,"0.0##");
+               getTextField().setEditable(true);
+               
+               DefaultFormatterFactory dff = (DefaultFormatterFactory) getTextField().getFormatterFactory();
+               DefaultFormatter formatter = (DefaultFormatter) dff.getDefaultFormatter();
+               formatter.setOverwriteMode(false);
        }
 
+       /**
+        * Constructor which sets the number of columns in the editor.
+        * @param spinner
+        * @param cols
+        */
+       public SpinnerEditor(JSpinner spinner, int cols ) {
+               this(spinner);
+               getTextField().setColumns(cols);
+       }
+       
 }
index 87997c484736884ac4a2a1a76b32b26b3660bf80..9c4801a613d10953291b07e3e4cd7fc00f11bf25 100644 (file)
@@ -63,5 +63,16 @@ public abstract class Column {
         * @return              the value at the specified position.
         */
        public abstract Object getValueAt(int row);
+
+       /**
+        * Set a value in the table.
+        * 
+        * Override if the cell is editable.
+        * 
+        * @param row
+        * @param value
+        */
+       public void setValueAt(int row, Object value ) {
+       }
        
 }
index e50a8ea5b87cd2100e03320513c49d3482e431b8..b8b8d3ec3e19904981d413bc0b4e36cc28d78380 100644 (file)
@@ -52,5 +52,10 @@ public abstract class ColumnTableModel extends AbstractTableModel {
                }
                return columns[col].getValueAt(row);
        }
+
+       @Override
+       public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+               columns[columnIndex].setValueAt(rowIndex, aValue);
+       }
        
 }
index 820a54a66c4508d3f9f67ac3afd79c50106bb42c..3216f0a7d7bf7d36f6c995b2b346736e0752cd8a 100644 (file)
@@ -10,10 +10,10 @@ import java.util.EventListener;
 import java.util.EventObject;
 
 import javax.swing.AbstractAction;
+import javax.swing.AbstractSpinnerModel;
 import javax.swing.Action;
 import javax.swing.BoundedRangeModel;
 import javax.swing.SpinnerModel;
-import javax.swing.SpinnerNumberModel;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 
@@ -23,6 +23,8 @@ import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
+import net.sf.openrocket.util.ExpressionParser;
+import net.sf.openrocket.util.InvalidExpressionException;
 import net.sf.openrocket.util.Invalidatable;
 import net.sf.openrocket.util.Invalidator;
 import net.sf.openrocket.util.MathUtil;
@@ -48,20 +50,25 @@ import net.sf.openrocket.util.StateChangeListener;
 public class DoubleModel implements StateChangeListener, ChangeSource, Invalidatable {
        private static final LogHelper log = Application.getLogger();
        
-
+       
        public static final DoubleModel ZERO = new DoubleModel(0);
        
        //////////// JSpinner Model ////////////
        
        /**
-        * Model suitable for JSpinner using JSpinner.NumberEditor.  It extends SpinnerNumberModel
+        * Model suitable for JSpinner. 
+        * Note: Previously used using JSpinner.NumberEditor and extended SpinnerNumberModel
         * to be compatible with the NumberEditor, but only has the necessary methods defined.
+        * This is still the design, but now extends AbstractSpinnerModel to allow other characters
+        * to be entered so that fractional units and expressions can be used.
         */
-       private class ValueSpinnerModel extends SpinnerNumberModel implements Invalidatable {
+       public class ValueSpinnerModel extends AbstractSpinnerModel implements Invalidatable {
+               
+               private ExpressionParser parser = new ExpressionParser();
                
                @Override
                public Object getValue() {
-                       return currentUnit.toUnit(DoubleModel.this.getValue());
+                       return currentUnit.toString(DoubleModel.this.getValue());
                }
                
                @Override
@@ -72,14 +79,41 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                                                " value=" + value + ", currently firing events");
                                return;
                        }
-                       Number num = (Number) value;
-                       double newValue = num.doubleValue();
-                       double converted = currentUnit.fromUnit(newValue);
                        
-                       log.user("SpinnerModel setValue called for " + DoubleModel.this.toString() + " newValue=" + newValue +
-                                       " converted=" + converted);
-                       DoubleModel.this.setValue(converted);
+                       Number num = Double.NaN;
+                       
+                       // Set num if possible
+                       if (value instanceof Number) {
+                               num = (Number) value;
+                       }
+                       else if (value instanceof String) {
+                               try {
+                                       String newValString = (String) value;
+                                       num = parser.parse(newValString);
+                               } catch (InvalidExpressionException e) {
+                                       // Ignore
+                               }
+                       }
                        
+                       // Update the doublemodel with the new number or return to the last number if not possible
+                       if (((Double) num).isNaN()) {
+                               DoubleModel.this.setValue(lastValue);
+                               log.user("SpinnerModel could not set value for " + DoubleModel.this.toString() + ". Could not convert " + value.toString());
+                       }
+                       else {
+                               double newValue = num.doubleValue();
+                               double converted = currentUnit.fromUnit(newValue);
+                               
+                               log.user("SpinnerModel setValue called for " + DoubleModel.this.toString() + " newValue=" + newValue +
+                                               " converted=" + converted);
+                               DoubleModel.this.setValue(converted);
+                       }
+                       
+                       // Force a refresh if text doesn't match up exactly with the stored value
+                       if (!((Double) lastValue).toString().equals(this.getValue().toString())) {
+                               DoubleModel.this.fireStateChanged();
+                               log.debug("SpinnerModel " + DoubleModel.this.toString() + " refresh forced because string did not match actual value.");
+                       }
                }
                
                @Override
@@ -106,18 +140,6 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                        return d;
                }
                
-               
-               @Override
-               public Comparable<Double> getMinimum() {
-                       return currentUnit.toUnit(minValue);
-               }
-               
-               @Override
-               public Comparable<Double> getMaximum() {
-                       return currentUnit.toUnit(maxValue);
-               }
-               
-               
                @Override
                public void addChangeListener(ChangeListener l) {
                        DoubleModel.this.addChangeListener(l);
@@ -144,10 +166,6 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                return new ValueSpinnerModel();
        }
        
-       
-
-
-
        ////////////  JSlider model  ////////////
        
        private class ValueSliderModel implements BoundedRangeModel, StateChangeListener, Invalidatable {
@@ -157,7 +175,8 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                 * Use linear scale  value = linear1 * x + linear0  when x < linearPosition
                 * Use quadratic scale  value = quad2 * x^2 + quad1 * x + quad0  otherwise
                 */
-
+               private final boolean islinear;
+               
                // Linear in range x <= linearPosition
                private final double linearPosition;
                
@@ -169,11 +188,10 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                //private final double linear0;
                
                // Non-linear multiplier, exponent and constant
-               private final double quad2, quad1, quad0;
+               private double quad2, quad1, quad0;
                
-               
-
                public ValueSliderModel(DoubleModel min, DoubleModel max) {
+                       this.islinear = true;
                        linearPosition = 1.0;
                        
                        this.min = min;
@@ -187,11 +205,12 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                }
                
                
-
+               
                /**
                 * Generate a linear model from min to max.
                 */
                public ValueSliderModel(double min, double max) {
+                       this.islinear = true;
                        linearPosition = 1.0;
                        
                        this.min = new DoubleModel(min);
@@ -205,6 +224,10 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                        this(min, 0.5, mid, max);
                }
                
+               public ValueSliderModel(double min, double mid, DoubleModel max) {
+                       this(min, 0.5, mid, max);
+               }
+               
                /*
                 * v(x)  = mul * x^exp + add
                 * 
@@ -213,32 +236,46 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                 * v'(pos) = mul*exp * pos^(exp-1) = linearMul
                 */
                public ValueSliderModel(double min, double pos, double mid, double max) {
+                       this(min, pos, mid, new DoubleModel(max));
+               }
+               
+               public ValueSliderModel(double min, double pos, double mid, DoubleModel max) {
                        this.min = new DoubleModel(min);
                        this.mid = new DoubleModel(mid);
-                       this.max = new DoubleModel(max);
+                       this.max = max;
+                       
+                       this.islinear = false;
+                       
+                       max.addChangeListener(this);
                        
-
                        linearPosition = pos;
                        //linear0 = min;
                        //linear1 = (mid-min)/pos;
                        
-                       if (!(min < mid && mid <= max && 0 < pos && pos < 1)) {
+                       if (!(min < mid && mid <= max.getValue() && 0 < pos && pos < 1)) {
                                throw new IllegalArgumentException("Bad arguments for ValueSliderModel " +
                                                "min=" + min + " mid=" + mid + " max=" + max + " pos=" + pos);
                        }
                        
+                       updateExponentialParameters();
+                       
+               }
+               
+               private void updateExponentialParameters() {
+                       double pos = this.linearPosition;
+                       double minValue = this.min.getValue();
+                       double midValue = this.mid.getValue();
+                       double maxValue = this.max.getValue();
                        /*
                         * quad2..0 are calculated such that
                         *   f(pos)  = mid      - continuity
                         *   f(1)    = max      - end point
                         *   f'(pos) = linear1  - continuity of derivative
                         */
-
-                       double delta = (mid - min) / pos;
-                       quad2 = (max - mid - delta + delta * pos) / pow2(pos - 1);
-                       quad1 = (delta + 2 * (mid - max) * pos - delta * pos * pos) / pow2(pos - 1);
-                       quad0 = (mid - (2 * mid + delta) * pos + (max + delta) * pos * pos) / pow2(pos - 1);
-                       
+                       double delta = (midValue - minValue) / pos;
+                       quad2 = (maxValue - midValue - delta + delta * pos) / pow2(pos - 1);
+                       quad1 = (delta + 2 * (midValue - maxValue) * pos - delta * pos * pos) / pow2(pos - 1);
+                       quad0 = (midValue - (2 * midValue + delta) * pos + (maxValue + delta) * pos * pos) / pow2(pos - 1);
                }
                
                private double pow2(double x) {
@@ -366,6 +403,11 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                @Override
                public void stateChanged(EventObject e) {
                        // Min or max range has changed.
+                       if (!islinear) {
+                               double midValue = (max.getValue() - min.getValue()) / 3.0;
+                               mid.setValue(midValue);
+                               updateExponentialParameters();
+                       }
                        // Fire if not already firing
                        if (firing == 0)
                                fireStateChanged();
@@ -385,14 +427,18 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                return new ValueSliderModel(min, mid, max);
        }
        
+       public BoundedRangeModel getSliderModel(double min, double mid, DoubleModel max) {
+               return new ValueSliderModel(min, mid, max);
+       }
+       
        public BoundedRangeModel getSliderModel(double min, double pos, double mid, double max) {
                return new ValueSliderModel(min, pos, mid, max);
        }
        
        
-
-
-
+       
+       
+       
        ////////////  Action model  ////////////
        
        private class AutomaticActionModel extends AbstractAction implements StateChangeListener, Invalidatable {
@@ -491,15 +537,15 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
        }
        
        
-
-
-
+       
+       
+       
        ////////////  Main model  /////////////
        
        /*
         * The main model handles all values in SI units, i.e. no conversion is made within the model.
         */
-
+       
        private final ChangeSource source;
        private final String valueName;
        private final double multiplier;
@@ -516,14 +562,14 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
        private Unit currentUnit;
        
        private final double minValue;
-       private final double maxValue;
+       private double maxValue;
        
        private String toString = null;
        
-
+       
        private int firing = 0; //  >0 when model itself is sending events
        
-
+       
        // Used to differentiate changes in valueName and other changes in the component:
        private double lastValue = 0;
        private boolean lastAutomatic = false;
@@ -677,7 +723,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
        }
        
        
-
+       
        /**
         * Returns the value of the variable (in SI units).
         */
@@ -725,7 +771,6 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                }
        }
        
-       
        /**
         * Returns whether setting the value automatically is available.
         */
@@ -811,7 +856,7 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
        }
        
        
-
+       
        /**
         * Add a listener to the model.  Adds the model as a listener to the value source if this
         * is the first listener.
@@ -897,10 +942,10 @@ public class DoubleModel implements StateChangeListener, ChangeSource, Invalidat
                // Copy the list before iterating to prevent concurrent modification exceptions.
                EventListener[] ls = listeners.toArray(new EventListener[0]);
                for (EventListener l : ls) {
-                       if ( l instanceof StateChangeListener ) {
-                               ((StateChangeListener)l).stateChanged(event);
-                       } else if ( l instanceof ChangeListener ) {
-                               ((ChangeListener)l).stateChanged(cevent);
+                       if (l instanceof StateChangeListener) {
+                               ((StateChangeListener) l).stateChanged(event);
+                       } else if (l instanceof ChangeListener) {
+                               ((ChangeListener) l).stateChanged(cevent);
                        }
                }
                firing--;
index a914df00e2d49633787612108765426f354db4e9..c3ebf83596c2b57bc5465ad1898c79f7565f60cd 100644 (file)
@@ -22,7 +22,7 @@ import net.sf.openrocket.util.Reflection;
 public class MaterialModel extends AbstractListModel implements
                ComboBoxModel, ComponentChangeListener, DatabaseListener<Material> {
        
-       private static final String CUSTOM = "Custom";
+       private final String custom;
 
        
        private final Component parentComponent;
@@ -47,6 +47,7 @@ public class MaterialModel extends AbstractListModel implements
                this.parentComponent = parent;
                this.component = component;
                this.type = type;
+               this.custom = trans.get ("Material.CUSTOM");
                
                switch (type) {
                case LINE:
@@ -90,7 +91,7 @@ public class MaterialModel extends AbstractListModel implements
                        return;
                }
 
-               if (item == CUSTOM) {
+               if (item == custom) {
                        
                        // Open custom material dialog in the future, after combo box has closed
                        SwingUtilities.invokeLater(new Runnable() {
@@ -129,7 +130,7 @@ public class MaterialModel extends AbstractListModel implements
        @Override
        public Object getElementAt(int index) {
                if (index == database.size()) {
-                       return CUSTOM;
+                       return custom;
                } else if (index >= database.size()+1) {
                        return null;
                }
diff --git a/core/src/net/sf/openrocket/gui/adaptors/PresetModel.java b/core/src/net/sf/openrocket/gui/adaptors/PresetModel.java
new file mode 100644 (file)
index 0000000..474610d
--- /dev/null
@@ -0,0 +1,120 @@
+package net.sf.openrocket.gui.adaptors;
+
+import java.awt.Component;
+import java.util.List;
+
+import javax.swing.AbstractListModel;
+import javax.swing.ComboBoxModel;
+import javax.swing.SwingUtilities;
+
+import net.sf.openrocket.database.Database;
+import net.sf.openrocket.database.DatabaseListener;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.dialogs.preset.ComponentPresetChooserDialog;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.rocketcomponent.ComponentChangeEvent;
+import net.sf.openrocket.rocketcomponent.ComponentChangeListener;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.BugException;
+
+public class PresetModel extends AbstractListModel implements ComboBoxModel, ComponentChangeListener, DatabaseListener<ComponentPreset> {
+       
+       private static final LogHelper log = Application.getLogger();
+       private static final Translator trans = Application.getTranslator();
+       
+       private static final String NONE_SELECTED = trans.get("lbl.select");
+       private static final String SELECT_DATABASE = trans.get("lbl.database");
+       
+       private final Component parent;
+       private final RocketComponent component;
+       private final OpenRocketDocument document;
+       private ComponentPreset previousPreset;
+       
+       private List<ComponentPreset> presets;
+       
+       public PresetModel(Component parent, OpenRocketDocument document, RocketComponent component) {
+               this.parent = parent;
+               this.document = document;
+               presets = Application.getComponentPresetDao().listForType(component.getPresetType(), true);
+               this.component = component;
+               previousPreset = component.getPresetComponent();
+               component.addComponentChangeListener(this);
+       }
+       
+       @Override
+       public int getSize() {
+               return presets.size() + 2;
+       }
+       
+       @Override
+       public Object getElementAt(int index) {
+               if (index == 0) {
+                       return NONE_SELECTED;
+               }
+               if (index == getSize() - 1) {
+                       return SELECT_DATABASE;
+               }
+               return presets.get(index - 1);
+       }
+       
+       @Override
+       public void setSelectedItem(Object item) {
+               log.user("User selected preset item '" + item + "' for component " + component);
+               
+               if (item == null) {
+                       throw new BugException("item is null");
+               } else if (item.equals(NONE_SELECTED)) {
+                       component.clearPreset();
+               } else if (item.equals(SELECT_DATABASE)) {
+                       SwingUtilities.invokeLater(new Runnable() {
+                               @Override
+                               public void run() {
+                                       ComponentPresetChooserDialog dialog =
+                                                       new ComponentPresetChooserDialog(SwingUtilities.getWindowAncestor(parent), component);
+                                       dialog.setVisible(true);
+                                       ComponentPreset preset = dialog.getSelectedComponentPreset();
+                                       if (preset != null) {
+                                               setSelectedItem(preset);
+                                       }
+                               }
+                       });
+               } else {
+                       document.addUndoPosition("Use Preset " + component.getComponentName());
+                       component.loadPreset((ComponentPreset) item);
+               }
+       }
+       
+       @Override
+       public Object getSelectedItem() {
+               ComponentPreset preset = component.getPresetComponent();
+               if (preset == null) {
+                       return NONE_SELECTED;
+               } else {
+                       return preset;
+               }
+       }
+       
+       @Override
+       public void componentChanged(ComponentChangeEvent e) {
+               if (previousPreset != component.getPresetComponent()) {
+                       previousPreset = component.getPresetComponent();
+                       fireContentsChanged(this, 0, getSize());
+               }
+       }
+       
+       @Override
+       public void elementAdded(ComponentPreset element, Database<ComponentPreset> source) {
+               presets = Application.getComponentPresetDao().listForType(component.getPresetType(), true);
+               this.fireContentsChanged(this, 0, getSize());
+       }
+       
+       @Override
+       public void elementRemoved(ComponentPreset element, Database<ComponentPreset> source) {
+               presets = Application.getComponentPresetDao().listForType(component.getPresetType(), true);
+               this.fireContentsChanged(this, 0, getSize());
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/gui/components/StarCheckBox.java b/core/src/net/sf/openrocket/gui/components/StarCheckBox.java
new file mode 100644 (file)
index 0000000..a7bdb6d
--- /dev/null
@@ -0,0 +1,20 @@
+package net.sf.openrocket.gui.components;
+
+import java.awt.Graphics;
+
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+
+import net.sf.openrocket.gui.util.Icons;
+
+public class StarCheckBox extends JCheckBox {
+       
+       
+       
+       @Override
+       public void paint(Graphics g) {
+               JLabel l = new JLabel(Icons.FAVORITE);
+               l.paint(g);
+       }
+       
+}
index cad8a25ab69fd55813fb8a0b177b8918783a4ab4..70328411b8221c8a8eb7c548e86b8cd1bd3c098e 100644 (file)
@@ -90,8 +90,8 @@ public class StyledLabel extends JLabel {
                if (str.startsWith("<html>") && str.indexOf("<br") < 0) {
                        StyledLabel label = new StyledLabel("plaintext", size, style);
                        label.validate();
-                       System.out.println("Plain-text label: " + label.getPreferredSize());
-                       System.out.println("HTML label: " + this.getPreferredSize());
+                       //System.out.println("Plain-text label: " + label.getPreferredSize());
+                       //System.out.println("HTML label: " + this.getPreferredSize());
                }
        }
        
index af272a0d88b50a2f6836ef6874b42d12e4cac5a1..b6ff3bdd42bfdeb3e98b5c27b7df8f00ecd95d35 100644 (file)
@@ -2,15 +2,18 @@ package net.sf.openrocket.gui.configdialog;
 
 
 import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.ComponentPresetDatabase;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.SpinnerEditor;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.adaptors.PresetModel;
 import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.l10n.Translator;
@@ -21,84 +24,88 @@ import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
 
 public class BodyTubeConfig extends RocketComponentConfig {
-       
+
        private MotorConfig motorConfigPane = null;
+       private DoubleModel maxLength;
        private static final Translator trans = Application.getTranslator();
-       
+
        public BodyTubeConfig(OpenRocketDocument d, RocketComponent c) {
                super(d, c);
-               
+
                JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
-               
+
+
+
                ////  Body tube length
                panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Bodytubelength")));
-               
-               DoubleModel m = new DoubleModel(component, "Length", UnitGroup.UNITS_LENGTH, 0);
-               
-               JSpinner spin = new JSpinner(m.getSpinnerModel());
+
+               maxLength = new DoubleModel(2.0);
+               DoubleModel length = new DoubleModel(component, "Length", UnitGroup.UNITS_LENGTH, 0);
+
+               JSpinner spin = new JSpinner(length.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
                panel.add(spin, "growx");
-               
-               panel.add(new UnitSelector(m), "growx");
-               panel.add(new BasicSlider(m.getSliderModel(0, 0.5, 2.0)), "w 100lp, wrap");
-               
+
+               panel.add(new UnitSelector(length), "growx");
+               panel.add(new BasicSlider(length.getSliderModel(0, 0.5, maxLength)), "w 100lp, wrap");
+
 
                //// Body tube diameter
                panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Outerdiameter")));
-               
+
                DoubleModel od = new DoubleModel(component, "OuterRadius", 2, UnitGroup.UNITS_LENGTH, 0);
                // Diameter = 2*Radius
-               
+
                spin = new JSpinner(od.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
                panel.add(spin, "growx");
-               
+
                panel.add(new UnitSelector(od), "growx");
                panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 0px");
-               
+
                JCheckBox check = new JCheckBox(od.getAutomaticAction());
                //// Automatic
                check.setText(trans.get("BodyTubecfg.checkbox.Automatic"));
                panel.add(check, "skip, span 2, wrap");
-               
+
 
                ////  Inner diameter
                panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Innerdiameter")));
-               
+
                // Diameter = 2*Radius
-               m = new DoubleModel(component, "InnerRadius", 2, UnitGroup.UNITS_LENGTH, 0);
-               
+               DoubleModel m = new DoubleModel(component, "InnerRadius", 2, UnitGroup.UNITS_LENGTH, 0);
+
 
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
                panel.add(spin, "growx");
-               
+
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(0), od)), "w 100lp, wrap");
-               
+
 
                ////  Wall thickness
                panel.add(new JLabel(trans.get("BodyTubecfg.lbl.Wallthickness")));
-               
+
                m = new DoubleModel(component, "Thickness", UnitGroup.UNITS_LENGTH, 0);
-               
+
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
                panel.add(spin, "growx");
-               
+
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap 0px");
-               
+
                //// Filled
                check = new JCheckBox(new BooleanModel(component, "Filled"));
                check.setText(trans.get("BodyTubecfg.checkbox.Filled"));
                panel.add(check, "skip, span 2, wrap");
-               
+
 
                //// Material
                panel.add(materialPanel(new JPanel(new MigLayout()), Material.Type.BULK),
                                "cell 4 0, gapleft paragraph, aligny 0%, spany");
-               
+
                //// General and General properties
                tabbedPane.insertTab(trans.get("BodyTubecfg.tab.General"), null, panel,
                                trans.get("BodyTubecfg.tab.Generalproperties"), 0);
@@ -107,13 +114,15 @@ public class BodyTubeConfig extends RocketComponentConfig {
                tabbedPane.insertTab(trans.get("BodyTubecfg.tab.Motor"), null, motorConfigPane,
                                trans.get("BodyTubecfg.tab.Motormountconf"), 1);
                tabbedPane.setSelectedIndex(0);
+
+
        }
-       
+
        @Override
        public void updateFields() {
                super.updateFields();
                if (motorConfigPane != null)
                        motorConfigPane.updateFields();
        }
-       
+
 }
index 321ef6c42047a80050b46fdd96fab875bb4218d1..7f985725375aaff2c7887bd48a9d9d3133d2f462 100644 (file)
@@ -35,8 +35,8 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                
                JPanel mainPanel = new JPanel(new MigLayout());
                
-
-
+               
+               
                JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                
                ////  Number of fins
@@ -48,11 +48,11 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                spin.setEditor(new SpinnerEditor(spin));
                panel.add(spin, "growx, wrap");
                
-
+               
                ////  Base rotation
                panel.add(new JLabel(trans.get("EllipticalFinSetCfg.Rotation")));
                
-               m = new DoubleModel(component, "BaseRotation", UnitGroup.UNITS_ANGLE, -Math.PI, Math.PI);
+               m = new DoubleModel(component, "BaseRotation", UnitGroup.UNITS_ANGLE);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
@@ -61,7 +61,7 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)), "w 100lp, wrap");
                
-
+               
                ////  Fin cant
                JLabel label = new JLabel(trans.get("EllipticalFinSetCfg.Fincant"));
                //// "The angle that the fins are canted with respect to the rocket
@@ -79,8 +79,8 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                panel.add(new BasicSlider(m.getSliderModel(-FinSet.MAX_CANT, FinSet.MAX_CANT)),
                                "w 100lp, wrap");
                
-
-
+               
+               
                ////  Root chord
                panel.add(new JLabel(trans.get("EllipticalFinSetCfg.Rootchord")));
                
@@ -93,7 +93,7 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.05, 0.2)), "w 100lp, wrap");
                
-
+               
                ////  Height
                panel.add(new JLabel(trans.get("EllipticalFinSetCfg.Height")));
                
@@ -106,7 +106,7 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.05, 0.2)), "w 100lp, wrap");
                
-
+               
                ////  Position
                //// Position relative to:
                panel.add(new JLabel(trans.get("EllipticalFinSetCfg.Positionrelativeto")));
@@ -118,7 +118,7 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                                                                RocketComponent.Position.MIDDLE,
                                                                RocketComponent.Position.BOTTOM,
                                                                RocketComponent.Position.ABSOLUTE
-                               }));
+                                               }));
                panel.add(combo, "spanx, growx, wrap");
                
                //// plus
@@ -135,18 +135,18 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                                new DoubleModel(component.getParent(), "Length"))),
                                "w 100lp, wrap");
                
-
-
+               
+               
                //// Right portion
                mainPanel.add(panel, "aligny 20%");
                
                mainPanel.add(new JSeparator(SwingConstants.VERTICAL), "growy");
                
-
-
+               
+               
                panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                
-
+               
                ////  Cross section
                //// Fin cross section:
                panel.add(new JLabel(trans.get("EllipticalFinSetCfg.FincrossSection")), "span, split");
@@ -154,7 +154,7 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                                new EnumModel<FinSet.CrossSection>(component, "CrossSection"));
                panel.add(combo, "growx, wrap unrel");
                
-
+               
                ////  Thickness:
                panel.add(new JLabel(trans.get("EllipticalFinSetCfg.Thickness")));
                
@@ -167,15 +167,15 @@ public class EllipticalFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap 30lp");
                
-
-
+               
+               
                //// Material
                materialPanel(panel, Material.Type.BULK);
                
-
-
-
-
+               
+               
+               
+               
                mainPanel.add(panel, "aligny 20%");
                
                addFinSetButtons();
index af4c7bf4c4bb2e5572c7cffba1bca6dcf796e40e..aa82e994cc119a7430bc5165ae5d88a24d9da8a1 100644 (file)
@@ -104,7 +104,7 @@ public class FreeformFinSetConfig extends FinSetConfig {
                ////  Base rotation
                panel.add(new JLabel(trans.get("FreeformFinSetCfg.lbl.Finrotation")));
                
-               m = new DoubleModel(component, "BaseRotation", UnitGroup.UNITS_ANGLE, -Math.PI, Math.PI);
+               m = new DoubleModel(component, "BaseRotation", UnitGroup.UNITS_ANGLE);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
index 947b205aea42c3287fb370f5dd2687647ecd415c..07248d1136201bd6876fab4d9ae45c8d04a67c99 100644 (file)
@@ -29,7 +29,7 @@ public class LaunchLugConfig extends RocketComponentConfig {
                
                JPanel primary = new JPanel(new MigLayout("fill"));
                
-
+               
                JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
                
                ////  Body tube length
@@ -45,7 +45,7 @@ public class LaunchLugConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.1)), "w 100lp, wrap para");
                
-
+               
                //// Body tube diameter
                //// Outer diameter:
                panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Outerdiam")));
@@ -60,14 +60,14 @@ public class LaunchLugConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(od), "growx");
                panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap rel");
                
-
+               
                ////  Inner diameter:
                panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Innerdiam")));
                
                // Diameter = 2*Radius
                m = new DoubleModel(component, "InnerRadius", 2, UnitGroup.UNITS_LENGTH, 0);
                
-
+               
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
                panel.add(spin, "growx");
@@ -75,7 +75,7 @@ public class LaunchLugConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(new DoubleModel(0), od)), "w 100lp, wrap rel");
                
-
+               
                ////  Wall thickness
                //// Thickness:
                panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Thickness")));
@@ -89,12 +89,11 @@ public class LaunchLugConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap 20lp");
                
-
+               
                ////  Radial position:
                panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Radialpos")));
                
-               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE,
-                               -Math.PI, Math.PI);
+               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
@@ -103,14 +102,14 @@ public class LaunchLugConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)), "w 100lp, wrap");
                
-
-
-
+               
+               
+               
                primary.add(panel, "grow, gapright 20lp");
                panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
                
-
-
+               
+               
                //// Position relative to:
                panel.add(new JLabel(trans.get("LaunchLugCfg.lbl.Posrelativeto")));
                
@@ -121,7 +120,7 @@ public class LaunchLugConfig extends RocketComponentConfig {
                                                                RocketComponent.Position.MIDDLE,
                                                                RocketComponent.Position.BOTTOM,
                                                                RocketComponent.Position.ABSOLUTE
-                               }));
+                                               }));
                panel.add(combo, "spanx, growx, wrap");
                
                //// plus
@@ -138,12 +137,12 @@ public class LaunchLugConfig extends RocketComponentConfig {
                                new DoubleModel(component.getParent(), "Length"))),
                                "w 100lp, wrap para");
                
-
-
+               
+               
                //// Material
                materialPanel(panel, Material.Type.BULK);
                
-
+               
                primary.add(panel, "grow");
                
                //// General and General properties
index b199d20965e28a41adec5702a4c19c79365f22d0..cf70d463fe715244e290000cc31e566a207f1762 100644 (file)
@@ -29,11 +29,11 @@ public class MassComponentConfig extends RocketComponentConfig {
        public MassComponentConfig(OpenRocketDocument d, RocketComponent component) {
                super(d, component);
                
-
+               
                JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                
-
-
+               
+               
                ////  Mass
                panel.add(new JLabel(trans.get("MassComponentCfg.lbl.Mass")));
                
@@ -46,8 +46,20 @@ public class MassComponentConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.05, 0.5)), "w 100lp, wrap");
                
-
-
+               
+               panel.add(new JLabel(trans.get("MassComponentCfg.lbl.Density")));
+               
+               m = new DoubleModel(component, "Density", UnitGroup.UNITS_DENSITY_BULK, 0);
+               
+               spin = new JSpinner(m.getSpinnerModel());
+               spin.setEditor(new SpinnerEditor(spin));
+               panel.add(spin, "growx");
+               
+               panel.add(new UnitSelector(m), "growx");
+               panel.add(new BasicSlider(m.getSliderModel(500, 2000, 10000)), "w 100lp, wrap");
+               
+               
+               
                ////  Mass length
                //// Length
                panel.add(new JLabel(trans.get("MassComponentCfg.lbl.Length")));
@@ -61,7 +73,7 @@ public class MassComponentConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 0.5)), "w 100lp, wrap");
                
-
+               
                //// Tube diameter
                //// Diameter:
                panel.add(new JLabel(trans.get("MassComponentCfg.lbl.Diameter")));
@@ -76,7 +88,7 @@ public class MassComponentConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(od), "growx");
                panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap");
                
-
+               
                ////  Position
                //// Position relative to:
                panel.add(new JLabel(trans.get("MassComponentCfg.lbl.PosRelativeto")));
@@ -88,7 +100,7 @@ public class MassComponentConfig extends RocketComponentConfig {
                                                                RocketComponent.Position.MIDDLE,
                                                                RocketComponent.Position.BOTTOM,
                                                                RocketComponent.Position.ABSOLUTE
-                               }));
+                                               }));
                panel.add(combo, "spanx, growx, wrap");
                //// plus
                panel.add(new JLabel(trans.get("MassComponentCfg.lbl.plus")), "right");
@@ -130,11 +142,11 @@ public class MassComponentConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 1.0)), "w 100lp, wrap");
                
-
+               
                //// Radial direction:
                panel.add(new JLabel(trans.get("MassComponentCfg.lbl.Radialdirection")));
                
-               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE, 0);
+               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
@@ -143,7 +155,7 @@ public class MassComponentConfig extends RocketComponentConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)), "w 100lp, wrap");
                
-
+               
                //// Reset button
                JButton button = new JButton(trans.get("MassComponentCfg.but.Reset"));
                button.addActionListener(new ActionListener() {
index 227a475c625624582670ca0bd6dadf3dbded4622..45eca30f08dd3b13f24ebcf1d4ae13ed95aedb70 100644 (file)
@@ -131,7 +131,7 @@ public class MotorConfig extends JPanel {
                
                dm = new DoubleModel(mount, "IgnitionDelay", 0);
                spin = new JSpinner(dm.getSpinnerModel());
-               spin.setEditor(new SpinnerEditor(spin));
+               spin.setEditor(new SpinnerEditor(spin,3));
                panel.add(spin, "gap rel rel");
                
                //// seconds
index 682f6d3507b44b30229481791037bb4a0037e798..b1b8d55a2d4349418ccf9079bb966c5af97ac663 100644 (file)
@@ -12,10 +12,12 @@ import javax.swing.JSlider;
 import javax.swing.JSpinner;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.ComponentPresetDatabase;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.SpinnerEditor;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.adaptors.PresetModel;
 import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.DescriptionArea;
 import net.sf.openrocket.gui.components.UnitSelector;
@@ -47,9 +49,6 @@ public class NoseConeConfig extends RocketComponentConfig {
                DoubleModel m;
                JPanel panel = new JPanel(new MigLayout("", "[][65lp::][30lp::]"));
                
-
-
-
                ////  Shape selection
                //// Nose cone shape:
                panel.add(new JLabel(trans.get("NoseConeCfg.lbl.Noseconeshape")));
index 5e29992234a6347204616493a889b4c5874b87fa..1e767a78af67f44075584c6aab83549acb7b3638 100644 (file)
@@ -201,7 +201,7 @@ public class ParachuteConfig extends RecoveryDeviceConfig {
                
                m = new DoubleModel(component, "DeployDelay", 0);
                spin = new JSpinner(m.getSpinnerModel());
-               spin.setEditor(new SpinnerEditor(spin));
+               spin.setEditor(new SpinnerEditor(spin,3));
                panel.add(spin, "spanx, split");
                
                //// seconds
@@ -262,7 +262,7 @@ public class ParachuteConfig extends RecoveryDeviceConfig {
                //// Radial direction:
                panel.add(new JLabel(trans.get("ParachuteCfg.lbl.Radialdirection")));
                
-               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE, 0);
+               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
index 23906d6fd2970e3cce5f2897c9c36377eaeba6af..803633004abc19a13a4a29f763f7e371f77b3212 100644 (file)
@@ -41,7 +41,7 @@ public class RingComponentConfig extends RocketComponentConfig {
                JSpinner spin;
                DoubleModel od = null;
                
-
+               
                //// Outer diameter
                if (outer != null) {
                        panel.add(new JLabel(outer));
@@ -65,7 +65,7 @@ public class RingComponentConfig extends RocketComponentConfig {
                        }
                }
                
-
+               
                ////  Inner diameter
                if (inner != null) {
                        panel.add(new JLabel(inner));
@@ -92,7 +92,7 @@ public class RingComponentConfig extends RocketComponentConfig {
                        }
                }
                
-
+               
                ////  Wall thickness
                if (thickness != null) {
                        panel.add(new JLabel(thickness));
@@ -108,7 +108,7 @@ public class RingComponentConfig extends RocketComponentConfig {
                        panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap");
                }
                
-
+               
                ////  Inner tube length
                if (length != null) {
                        panel.add(new JLabel(length));
@@ -124,7 +124,7 @@ public class RingComponentConfig extends RocketComponentConfig {
                        panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 1.0)), "w 100lp, wrap");
                }
                
-
+               
                ////  Position
                
                //// Position relative to:
@@ -137,7 +137,7 @@ public class RingComponentConfig extends RocketComponentConfig {
                                                                RocketComponent.Position.MIDDLE,
                                                                RocketComponent.Position.BOTTOM,
                                                                RocketComponent.Position.ABSOLUTE
-                               }));
+                                               }));
                panel.add(combo, "spanx 3, growx, wrap");
                
                //// plus
@@ -155,7 +155,7 @@ public class RingComponentConfig extends RocketComponentConfig {
                                new DoubleModel(component.getParent(), "Length"))),
                                "w 100lp, wrap");
                
-
+               
                //// Material
                JPanel sub = materialPanel(new JPanel(new MigLayout()), Material.Type.BULK);
                
@@ -195,14 +195,14 @@ public class RingComponentConfig extends RocketComponentConfig {
                bs.setToolTipText(trans.get("ringcompcfg.Distancefrom"));
                panel.add(bs, "w 100lp, wrap");
                
-
+               
                //// Radial direction
                l = new JLabel(trans.get("ringcompcfg.Radialdirection"));
                //// The radial direction from the rocket centerline
                l.setToolTipText(trans.get("ringcompcfg.radialdirectionfrom"));
                panel.add(l);
                
-               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE, 0);
+               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
@@ -216,7 +216,7 @@ public class RingComponentConfig extends RocketComponentConfig {
                bs.setToolTipText(trans.get("ringcompcfg.radialdirectionfrom"));
                panel.add(bs, "w 100lp, wrap");
                
-
+               
                //// Reset button
                JButton button = new JButton(trans.get("ringcompcfg.but.Reset"));
                //// Reset the component to the rocket centerline
@@ -230,13 +230,13 @@ public class RingComponentConfig extends RocketComponentConfig {
                });
                panel.add(button, "spanx, right, wrap para");
                
-
+               
                DescriptionArea note = new DescriptionArea(3);
                //// Note: An inner tube will not affect the aerodynamics of the rocket even if it is located outside of the body tube.
                note.setText(trans.get("ringcompcfg.note.desc"));
                panel.add(note, "spanx, growx");
                
-
+               
                return panel;
        }
        
index 95853b0246602b28cf8708123bbd2a2711e0773c..c2fbd63ec362ca22ae2c83e5d836ae264e56c751 100644 (file)
@@ -9,6 +9,7 @@ import java.awt.event.FocusListener;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
@@ -24,12 +25,14 @@ import javax.swing.JTextArea;
 import javax.swing.JTextField;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.ComponentPresetDatabase;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.gui.SpinnerEditor;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.adaptors.EnumModel;
 import net.sf.openrocket.gui.adaptors.MaterialModel;
+import net.sf.openrocket.gui.adaptors.PresetModel;
 import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.ColorIcon;
 import net.sf.openrocket.gui.components.StyledLabel;
@@ -40,6 +43,7 @@ import net.sf.openrocket.gui.util.GUIUtil;
 import net.sf.openrocket.gui.util.SwingPreferences;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.rocketcomponent.ComponentAssembly;
 import net.sf.openrocket.rocketcomponent.ExternalComponent;
 import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
@@ -60,7 +64,9 @@ public class RocketComponentConfig extends JPanel {
        
        private final List<Invalidatable> invalidatables = new ArrayList<Invalidatable>();
        
-
+       private JComboBox presetComboBox;
+       private PresetModel presetModel;
+       
        protected final JTextField componentNameField;
        protected JTextArea commentTextArea;
        private final TextFieldListener textFieldListener;
@@ -68,11 +74,11 @@ public class RocketComponentConfig extends JPanel {
        private JCheckBox colorDefault;
        private JPanel buttonPanel;
        
-       private JLabel massLabel;
+       private JLabel infoLabel;
        
        
        public RocketComponentConfig(OpenRocketDocument document, RocketComponent component) {
-               setLayout(new MigLayout("fill", "[grow, fill]"));
+               setLayout(new MigLayout("fill", "[min,align right]:10[fill, grow]"));
                this.document = document;
                this.component = component;
                
@@ -80,7 +86,7 @@ public class RocketComponentConfig extends JPanel {
                JLabel label = new JLabel(trans.get("RocketCompCfg.lbl.Componentname"));
                //// The component name.
                label.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
-               this.add(label, "split, gapright 10");
+               this.add(label, "spanx, split");
                
                componentNameField = new JTextField(15);
                textFieldListener = new TextFieldListener();
@@ -88,11 +94,20 @@ public class RocketComponentConfig extends JPanel {
                componentNameField.addFocusListener(textFieldListener);
                //// The component name.
                componentNameField.setToolTipText(trans.get("RocketCompCfg.ttip.Thecomponentname"));
-               this.add(componentNameField, "growx, growy 0, wrap");
+               this.add(componentNameField, "growx");
+               
+               if (component.getPresetType() != null) {
+                       // If the component supports a preset, show the preset selection box.
+                       presetModel = new PresetModel(this, document, component);
+                       ((ComponentPresetDatabase) Application.getComponentPresetDao()).addDatabaseListener(presetModel);
+                       presetComboBox = new JComboBox(presetModel);
+                       presetComboBox.setEditable(false);
+                       this.add(presetComboBox, "");
+               }
+               
                
-
                tabbedPane = new JTabbedPane();
-               this.add(tabbedPane, "growx, growy 1, wrap");
+               this.add(tabbedPane, "newline, span, growx, growy 1, wrap");
                
                //// Override and Mass and CG override options
                tabbedPane.addTab(trans.get("RocketCompCfg.tab.Override"), null, overrideTab(),
@@ -119,8 +134,8 @@ public class RocketComponentConfig extends JPanel {
                buttonPanel = new JPanel(new MigLayout("fill, ins 0"));
                
                //// Mass:
-               massLabel = new StyledLabel(trans.get("RocketCompCfg.lbl.Mass") + " ", -1);
-               buttonPanel.add(massLabel, "growx");
+               infoLabel = new StyledLabel(" ", -1);
+               buttonPanel.add(infoLabel, "growx");
                
                for (JButton b : buttons) {
                        buttonPanel.add(b, "right, gap para");
@@ -158,33 +173,38 @@ public class RocketComponentConfig extends JPanel {
                                colorDefault.setSelected(component.getColor() == null);
                }
                
-               // Mass label
+               // Info label
+               StringBuilder sb = new StringBuilder();
+               
+               if (component.getPresetComponent() != null) {
+                       ComponentPreset preset = component.getPresetComponent();
+                       sb.append(preset.getManufacturer() + " " + preset.getPartNo() + "      ");
+               }
+               
                if (component.isMassive()) {
-                       //// Component mass:
-                       String text = trans.get("RocketCompCfg.lbl.Componentmass") + " ";
-                       text += UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(
-                                       component.getComponentMass());
+                       sb.append(trans.get("RocketCompCfg.lbl.Componentmass") + " ");
+                       sb.append(UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(
+                                       component.getComponentMass()));
                        
                        String overridetext = null;
                        if (component.isMassOverridden()) {
-                               //// (overridden to 
                                overridetext = trans.get("RocketCompCfg.lbl.overriddento") + " " + UnitGroup.UNITS_MASS.getDefaultUnit().
                                                toStringUnit(component.getOverrideMass()) + ")";
                        }
                        
                        for (RocketComponent c = component.getParent(); c != null; c = c.getParent()) {
                                if (c.isMassOverridden() && c.getOverrideSubcomponents()) {
-                                       ///// (overridden by
                                        overridetext = trans.get("RocketCompCfg.lbl.overriddenby") + " " + c.getName() + ")";
                                }
                        }
                        
-                       if (overridetext != null)
-                               text = text + " " + overridetext;
+                       if (overridetext != null) {
+                               sb.append(" " + overridetext);
+                       }
                        
-                       massLabel.setText(text);
+                       infoLabel.setText(sb.toString());
                } else {
-                       massLabel.setText("");
+                       infoLabel.setText("");
                }
        }
        
@@ -197,6 +217,7 @@ public class RocketComponentConfig extends JPanel {
        
        protected JPanel materialPanel(JPanel panel, Material.Type type,
                        String materialString, String finishString) {
+               
                JLabel label = new JLabel(materialString);
                //// The component material affects the weight of the component.
                label.setToolTipText(trans.get("RocketCompCfg.lbl.ttip.componentmaterialaffects"));
@@ -207,7 +228,7 @@ public class RocketComponentConfig extends JPanel {
                combo.setToolTipText(trans.get("RocketCompCfg.combo.ttip.componentmaterialaffects"));
                panel.add(combo, "spanx 4, growx, wrap paragraph");
                
-
+               
                if (component instanceof ExternalComponent) {
                        label = new JLabel(finishString);
                        ////<html>The component finish affects the aerodynamic drag of the component.<br>
@@ -286,7 +307,7 @@ public class RocketComponentConfig extends JPanel {
                bm.addEnableComponent(bs);
                panel.add(bs, "growx 5, w 100lp, wrap");
                
-
+               
                ////  CG override
                bm = new BooleanModel(component, "CGOverridden");
                check = new JCheckBox(bm);
@@ -324,7 +345,7 @@ public class RocketComponentConfig extends JPanel {
                bm.addEnableComponent(bs);
                panel.add(bs, "growx 5, w 100lp, wrap 35lp");
                
-
+               
                // Override subcomponents checkbox
                bm = new BooleanModel(component, "OverrideSubcomponents");
                check = new JCheckBox(bm);
@@ -336,7 +357,7 @@ public class RocketComponentConfig extends JPanel {
                panel.add(new StyledLabel(trans.get("RocketCompCfg.lbl.longB1") +
                                //// The center of gravity is measured from the front end of the
                                trans.get("RocketCompCfg.lbl.longB2") + " " +
-                               component.getComponentName().toLowerCase() + ".", -1),
+                               component.getComponentName().toLowerCase(Locale.getDefault()) + ".", -1),
                                "spanx, wrap, gap para, height 0::30lp");
                
                return panel;
@@ -364,7 +385,7 @@ public class RocketComponentConfig extends JPanel {
        }
        
        
-
+       
        private JPanel figureTab() {
                JPanel panel = new JPanel(new MigLayout("align 20% 20%"));
                
@@ -384,7 +405,7 @@ public class RocketComponentConfig extends JPanel {
                                }
                                
                                //// Choose color
-                               Color awtColor = ColorConversion.toAwtColor(c); 
+                               Color awtColor = ColorConversion.toAwtColor(c);
                                awtColor = JColorChooser.showDialog(tabbedPane, trans.get("RocketCompCfg.lbl.Choosecolor"), awtColor);
                                c = ColorConversion.fromAwtColor(awtColor);
                                if (c != null) {
@@ -450,7 +471,7 @@ public class RocketComponentConfig extends JPanel {
        }
        
        
-
+       
        protected JPanel shoulderTab() {
                JPanel panel = new JPanel(new MigLayout("fill"));
                JPanel sub;
@@ -460,7 +481,7 @@ public class RocketComponentConfig extends JPanel {
                JCheckBox check;
                JSpinner spin;
                
-
+               
                ////  Fore shoulder, not for NoseCone
                
                if (!(component instanceof NoseCone)) {
@@ -469,7 +490,7 @@ public class RocketComponentConfig extends JPanel {
                        //// Fore shoulder
                        sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.border.Foreshoulder")));
                        
-
+                       
                        ////  Radius
                        //// Diameter:
                        sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Diameter")));
@@ -484,7 +505,7 @@ public class RocketComponentConfig extends JPanel {
                        sub.add(new UnitSelector(m), "growx");
                        sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
                        
-
+                       
                        ////  Length:
                        sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Length")));
                        
@@ -497,7 +518,7 @@ public class RocketComponentConfig extends JPanel {
                        sub.add(new UnitSelector(m), "growx");
                        sub.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.2)), "w 100lp, wrap");
                        
-
+                       
                        ////  Thickness:
                        sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Thickness")));
                        
@@ -511,7 +532,7 @@ public class RocketComponentConfig extends JPanel {
                        sub.add(new UnitSelector(m), "growx");
                        sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
                        
-
+                       
                        ////  Capped
                        bm = new BooleanModel(component, "ForeShoulderCapped");
                        check = new JCheckBox(bm);
@@ -521,11 +542,11 @@ public class RocketComponentConfig extends JPanel {
                        check.setToolTipText(trans.get("RocketCompCfg.ttip.Endcapped"));
                        sub.add(check, "spanx");
                        
-
+                       
                        panel.add(sub);
                }
                
-
+               
                ////  Aft shoulder
                sub = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                
@@ -536,7 +557,7 @@ public class RocketComponentConfig extends JPanel {
                        //// Aft shoulder
                        sub.setBorder(BorderFactory.createTitledBorder(trans.get("RocketCompCfg.title.Aftshoulder")));
                
-
+               
                ////  Radius
                //// Diameter:
                sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Diameter")));
@@ -551,7 +572,7 @@ public class RocketComponentConfig extends JPanel {
                sub.add(new UnitSelector(m), "growx");
                sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
                
-
+               
                ////  Length:
                sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Length")));
                
@@ -564,7 +585,7 @@ public class RocketComponentConfig extends JPanel {
                sub.add(new UnitSelector(m), "growx");
                sub.add(new BasicSlider(m.getSliderModel(0, 0.02, 0.2)), "w 100lp, wrap");
                
-
+               
                ////  Thickness:
                sub.add(new JLabel(trans.get("RocketCompCfg.lbl.Thickness")));
                
@@ -578,7 +599,7 @@ public class RocketComponentConfig extends JPanel {
                sub.add(new UnitSelector(m), "growx");
                sub.add(new BasicSlider(m.getSliderModel(m0, m2)), "w 100lp, wrap");
                
-
+               
                ////  Capped
                bm = new BooleanModel(component, "AftShoulderCapped");
                check = new JCheckBox(bm);
@@ -588,16 +609,16 @@ public class RocketComponentConfig extends JPanel {
                check.setToolTipText(trans.get("RocketCompCfg.ttip.Endcapped"));
                sub.add(check, "spanx");
                
-
+               
                panel.add(sub);
                
-
+               
                return panel;
        }
        
        
-
-
+       
+       
        /*
         * Private inner class to handle events in componentNameField.
         */
@@ -635,6 +656,8 @@ public class RocketComponentConfig extends JPanel {
                for (Invalidatable i : invalidatables) {
                        i.invalidate();
                }
+               ((ComponentPresetDatabase) Application.getComponentPresetDao()).removeChangeListener(presetModel);
+               
        }
        
 }
\ No newline at end of file
index 8d7be3049e1d4ac2a9380713762174eb6580a1f6..491370454e878957ab9037aff0361f65ffec99ca 100644 (file)
@@ -39,7 +39,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                
                JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
                
-
+               
                //// Strip length:
                panel.add(new JLabel(trans.get("StreamerCfg.lbl.Striplength")));
                
@@ -62,8 +62,8 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.2)), "w 100lp, wrap 20lp");
                
-
-
+               
+               
                //// Strip area:
                panel.add(new JLabel(trans.get("StreamerCfg.lbl.Striparea")));
                
@@ -86,7 +86,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                //              panel.add(new UnitSelector(m),"growx");
                panel.add(new BasicSlider(m.getSliderModel(2, 15)), "skip, w 100lp, wrap 20lp");
                
-
+               
                //// Material:
                panel.add(new JLabel(trans.get("StreamerCfg.lbl.Material")));
                
@@ -96,8 +96,8 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                combo.setToolTipText(trans.get("StreamerCfg.combo.ttip.MaterialModel"));
                panel.add(combo, "spanx 3, growx, wrap 20lp");
                
-
-
+               
+               
                // CD
                //// <html>Drag coefficient C<sub>D</sub>:
                JLabel label = new HtmlLabel(trans.get("StreamerCfg.lbl.longA1"));
@@ -124,14 +124,14 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                panel.add(new StyledLabel(trans.get("StreamerCfg.lbl.longC1"),
                                -2), "span, wrap");
                
-
-
+               
+               
                primary.add(panel, "grow, gapright 20lp");
                panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::][]", ""));
                
-
-
-
+               
+               
+               
                //// Position
                //// Position relative to:
                panel.add(new JLabel(trans.get("StreamerCfg.lbl.Posrelativeto")));
@@ -143,7 +143,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                                                                RocketComponent.Position.MIDDLE,
                                                                RocketComponent.Position.BOTTOM,
                                                                RocketComponent.Position.ABSOLUTE
-                               }));
+                                               }));
                panel.add(combo, "spanx, growx, wrap");
                
                //// plus
@@ -160,7 +160,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                                new DoubleModel(component.getParent(), "Length"))),
                                "w 100lp, wrap");
                
-
+               
                ////  Spatial length:
                panel.add(new JLabel(trans.get("StreamerCfg.lbl.Packedlength")));
                
@@ -173,7 +173,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 0.5)), "w 100lp, wrap");
                
-
+               
                //// Tube diameter
                //// Packed diameter:
                panel.add(new JLabel(trans.get("StreamerCfg.lbl.Packeddiam")));
@@ -188,7 +188,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                panel.add(new UnitSelector(od), "growx");
                panel.add(new BasicSlider(od.getSliderModel(0, 0.04, 0.2)), "w 100lp, wrap 30lp");
                
-
+               
                //// Deployment
                //// Deploys at:
                panel.add(new JLabel(trans.get("StreamerCfg.lbl.Deploysat")), "");
@@ -202,7 +202,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                
                m = new DoubleModel(component, "DeployDelay", 0);
                spin = new JSpinner(m.getSpinnerModel());
-               spin.setEditor(new SpinnerEditor(spin));
+               spin.setEditor(new SpinnerEditor(spin,3));
                panel.add(spin, "spanx, split");
                
                //// seconds
@@ -226,7 +226,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                altitudeComponents.add(slider);
                panel.add(slider, "w 100lp, wrap");
                
-
+               
                primary.add(panel, "grow");
                
                updateFields();
@@ -241,9 +241,9 @@ public class StreamerConfig extends RecoveryDeviceConfig {
        }
        
        
-
-
-
+       
+       
+       
        protected JPanel positionTab() {
                JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                
@@ -260,12 +260,12 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.1, 1.0)), "w 100lp, wrap");
                
-
+               
                //// Radial direction
                //// Radial direction:
                panel.add(new JLabel(trans.get("StreamerCfg.lbl.Radialdirection")));
                
-               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE, 0);
+               m = new DoubleModel(component, "RadialDirection", UnitGroup.UNITS_ANGLE);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
@@ -274,7 +274,7 @@ public class StreamerConfig extends RecoveryDeviceConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)), "w 100lp, wrap");
                
-
+               
                //// Reset button
                JButton button = new JButton(trans.get("StreamerCfg.but.Reset"));
                button.addActionListener(new ActionListener() {
index 47650ffda2a5cdab29da1f982d522261283d929d..7c343fbf20bec87f0b9863938067f278ecca3421 100644 (file)
@@ -37,7 +37,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                
                JPanel mainPanel = new JPanel(new MigLayout());
                
-
+               
                JPanel panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                
                ////  Number of fins:
@@ -54,7 +54,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                spin.setToolTipText(trans.get("TrapezoidFinSetCfg.lbl.ttip.Nbroffins"));
                panel.add(spin, "growx, wrap");
                
-
+               
                ////  Base rotation
                //// Fin rotation:
                label = new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Finrotation"));
@@ -62,7 +62,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                label.setToolTipText(trans.get("TrapezoidFinSetCfg.lbl.ttip.Finrotation"));
                panel.add(label);
                
-               m = new DoubleModel(component, "BaseRotation", UnitGroup.UNITS_ANGLE, -Math.PI, Math.PI);
+               m = new DoubleModel(component, "BaseRotation", UnitGroup.UNITS_ANGLE);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
@@ -71,7 +71,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(-Math.PI, Math.PI)), "w 100lp, wrap");
                
-
+               
                ////  Fin cant:
                label = new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Fincant"));
                //// The angle that the fins are canted with respect to the rocket 
@@ -89,7 +89,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                panel.add(new BasicSlider(m.getSliderModel(-FinSet.MAX_CANT, FinSet.MAX_CANT)),
                                "w 100lp, wrap");
                
-
+               
                ////  Root chord:
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Rootchord")));
                
@@ -102,8 +102,8 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.05, 0.2)), "w 100lp, wrap");
                
-
-
+               
+               
                ////  Tip chord:
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Tipchord")));
                
@@ -116,7 +116,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.05, 0.2)), "w 100lp, wrap");
                
-
+               
                ////  Height:
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Height")));
                
@@ -129,8 +129,8 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.05, 0.2)), "w 100lp, wrap");
                
-
-
+               
+               
                ////  Sweep length:
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Sweeplength")));
                
@@ -147,7 +147,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                DoubleModel rc = new DoubleModel(component, "RootChord", 1.1, UnitGroup.UNITS_LENGTH);
                panel.add(new BasicSlider(m.getSliderModel(tc, rc)), "w 100lp, wrap");
                
-
+               
                ////  Sweep angle:
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Sweepangle")));
                
@@ -162,27 +162,27 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                panel.add(new BasicSlider(m.getSliderModel(-Math.PI / 4, Math.PI / 4)),
                                "w 100lp, wrap paragraph");
                
-
-
-
-
+               
+               
+               
+               
                mainPanel.add(panel, "aligny 20%");
                
                mainPanel.add(new JSeparator(SwingConstants.VERTICAL), "growy");
                
-
-
+               
+               
                panel = new JPanel(new MigLayout("gap rel unrel", "[][65lp::][30lp::]", ""));
                
-
-
+               
+               
                ////  Fin cross section:
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.FincrossSection")));
                combo = new JComboBox(
                                new EnumModel<FinSet.CrossSection>(component, "CrossSection"));
                panel.add(combo, "span, growx, wrap");
                
-
+               
                ////  Thickness:
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Thickness")));
                
@@ -195,7 +195,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                panel.add(new UnitSelector(m), "growx");
                panel.add(new BasicSlider(m.getSliderModel(0, 0.01)), "w 100lp, wrap para");
                
-
+               
                ////  Position
                //// Position relative to:
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.Posrelativeto")));
@@ -207,7 +207,7 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                                                                RocketComponent.Position.MIDDLE,
                                                                RocketComponent.Position.BOTTOM,
                                                                RocketComponent.Position.ABSOLUTE
-                               }));
+                                               }));
                panel.add(combo, "spanx, growx, wrap");
                //// plus
                panel.add(new JLabel(trans.get("TrapezoidFinSetCfg.lbl.plus")), "right");
@@ -223,14 +223,14 @@ public class TrapezoidFinSetConfig extends FinSetConfig {
                                new DoubleModel(component.getParent(), "Length"))),
                                "w 100lp, wrap para");
                
-
-
+               
+               
                //// Material
                materialPanel(panel, Material.Type.BULK);
                
-
-
-
+               
+               
+               
                mainPanel.add(panel, "aligny 20%");
                
                //// General and General properties
diff --git a/core/src/net/sf/openrocket/gui/customexpression/CustomExpressionDialog.java b/core/src/net/sf/openrocket/gui/customexpression/CustomExpressionDialog.java
new file mode 100644 (file)
index 0000000..b8dee9f
--- /dev/null
@@ -0,0 +1,35 @@
+package net.sf.openrocket.gui.customexpression;
+
+import java.awt.Window;
+
+import javax.swing.BorderFactory;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.startup.Application;
+
+public class CustomExpressionDialog extends JDialog {
+       private static final Translator trans = Application.getTranslator();
+       private static final LogHelper log = Application.getLogger();
+       
+       private final Window parentWindow;
+       private final OpenRocketDocument doc;
+       
+       public CustomExpressionDialog(OpenRocketDocument doc, Window parent){
+               super(parent, trans.get("customExpressionPanel.lbl.CustomExpressions"));
+               
+               this.doc = doc;
+               this.parentWindow = parent;
+               
+               JPanel panel = new CustomExpressionPanel(doc, this);
+               this.add( panel );
+               
+               GUIUtil.setDisposableDialogOptions(this, null);
+       }
+}
diff --git a/core/src/net/sf/openrocket/gui/customexpression/CustomExpressionPanel.java b/core/src/net/sf/openrocket/gui/customexpression/CustomExpressionPanel.java
new file mode 100644 (file)
index 0000000..ba92848
--- /dev/null
@@ -0,0 +1,261 @@
+package net.sf.openrocket.gui.customexpression;
+
+import java.awt.Color;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+import javax.swing.border.Border;
+import javax.swing.filechooser.FileNameExtensionFilter;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.file.DatabaseMotorFinder;
+import net.sf.openrocket.file.GeneralRocketLoader;
+import net.sf.openrocket.file.RocketLoadException;
+import net.sf.openrocket.gui.components.UnitSelector;
+import net.sf.openrocket.gui.util.Icons;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.startup.Application;
+
+public class CustomExpressionPanel extends JPanel {
+       
+       private static final LogHelper log = Application.getLogger();
+       private static final Translator trans = Application.getTranslator();
+       
+       private JPanel expressionSelectorPanel;
+       private OpenRocketDocument doc;
+       
+       public CustomExpressionPanel(final OpenRocketDocument doc, final JDialog parentDialog) {
+               super(new MigLayout("fill"));
+               this.doc = doc;
+
+               expressionSelectorPanel = new JPanel(new MigLayout("gapy rel"));
+               expressionSelectorPanel.setToolTipText(trans.get("customExpressionPanel.lbl.CalcNote"));
+               
+               JScrollPane scroll = new JScrollPane(expressionSelectorPanel);
+               
+               //Border bdr = BorderFactory.createTitledBorder(trans.get("customExpressionPanel.lbl.CustomExpressions"));
+               //scroll.setBorder(bdr);
+               //expressionSelectorPanel.add(scroll);
+               
+               //this.add(expressionSelectorPanel, "spany 1, height 10px, wmin 600lp, grow 100, gapright para");
+               this.add(scroll, "hmin 200lp, wmin 700lp, grow 100, wrap");
+               
+               //DescriptionArea desc = new DescriptionArea(trans.get("customExpressionPanel.lbl.UpdateNote")+"\n\n"+trans.get("customExpressionPanel.lbl.CalcNote"), 8, -2f);
+               //desc.setViewportBorder(BorderFactory.createEmptyBorder());
+               //this.add(desc, "width 1px, growx 1, wrap unrel, wrap");
+               
+               //// New expression
+               JButton button = new JButton(trans.get("customExpressionPanel.but.NewExpression"));
+               button.setToolTipText(trans.get("customExpressionPanel.but.ttip.NewExpression"));
+               button.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               // Open window to configure expression
+                               log.info("Opening window to configure new expression");
+                               Window parent = SwingUtilities.getWindowAncestor(CustomExpressionPanel.this);
+                               new ExpressionBuilderDialog(parent, doc).setVisible(true);
+                               updateExpressions();
+                       }
+               });
+               this.add(button, "split 4, width :100:200");
+               
+               //// Import
+               final JButton importButton = new JButton(trans.get("customExpressionPanel.but.Import"));
+               importButton.setToolTipText(trans.get("customExpressionPanel.but.ttip.Import"));
+               importButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               
+                               //Create a file chooser
+                               final JFileChooser fc = new JFileChooser();
+                               if (doc.getFile() != null){
+                                       fc.setCurrentDirectory(doc.getFile().getParentFile());
+                               }
+                               fc.setFileFilter(new FileNameExtensionFilter("Openrocket file", "ork"));
+                               fc.setAcceptAllFileFilterUsed(false);
+                               
+                               int returnVal = fc.showOpenDialog(CustomExpressionPanel.this);
+                               if (returnVal == JFileChooser.APPROVE_OPTION){
+                                       File importFile = fc.getSelectedFile();
+                                       log.info("User selected a file to import expressions from "+fc.getSelectedFile().toString());
+                                       
+                                       //TODO: This should probably be somewhere else and ideally we would use an alternative minimal rocket loader. Still, it doesn't seem particularly slow this way.
+                                       
+                                       // Load expressions from selected document
+                                       GeneralRocketLoader loader = new GeneralRocketLoader();
+                                       try {
+                                               OpenRocketDocument importedDocument = loader.load(importFile, new DatabaseMotorFinder());
+                                               for (CustomExpression exp : importedDocument.getCustomExpressions()){
+                                                       doc.addCustomExpression(exp);
+                                               }
+                                       } catch (RocketLoadException e1) {
+                                               log.user("Error opening document to import expressions from.");
+                                       }
+                                       updateExpressions();
+                               }
+                       }
+               });
+               this.add(importButton, "width :100:200");
+               
+               //// Close button
+               final JButton closeButton = new JButton(trans.get("dlg.but.close"));
+               closeButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               parentDialog.dispose();
+                       }
+               });
+               this.add(new JPanel(), "growx");
+               this.add(closeButton, "width :100:200");
+               
+               updateExpressions();
+       }
+       
+       /*
+        * Update the expressionSelectorPanel
+        */
+       private void updateExpressions(){
+               
+               expressionSelectorPanel.removeAll();
+               int totalExpressions = doc.getCustomExpressions().size();
+               for (int i=0; i<totalExpressions; i++){
+                       SingleExpression se = new SingleExpression(doc.getCustomExpressions().get(i), i != 0, i != totalExpressions-1);
+                       expressionSelectorPanel.add(se, "wrap");
+               }
+
+               expressionSelectorPanel.revalidate();
+               expressionSelectorPanel.repaint();
+       }
+       
+       private void deleteExpression(CustomExpression expression){
+               doc.getCustomExpressions().remove(expression);
+       }
+       
+       /**
+        * Moves an expression up or down in the expression list
+        * @param expression
+        * @param move integer - +1 to move down, -1 to move up
+        */
+       private void moveExpression(CustomExpression expression, int move){
+               List<CustomExpression> expressions = doc.getCustomExpressions();
+               int i = expressions.indexOf(expression);
+               if (i+move == expressions.size() || i+move < 0)
+                       return;
+               else
+                       Collections.swap(expressions, i, i+move);
+       }
+
+       
+       /*
+        * A JPanel which configures a single expression
+        */
+       private class SingleExpression extends JPanel {
+               
+               // Convenience method to make the labels consistent
+               private JLabel setLabelStyle(JLabel l){
+                       l.setBackground(Color.WHITE);
+                       l.setOpaque(true);
+                       l.setBorder(BorderFactory.createRaisedBevelBorder() );
+                       l.setText(" " + l.getText() + " ");
+                       return l;
+               }
+               
+               private SingleExpression(final CustomExpression expression, boolean showUp, boolean showDown) {
+                       super(new MigLayout("ins 0"));
+                       //                      name:    aName    symbol:  a      Unit:  m/s
+                       //super(new MigLayout("","[::100][:200:400][::100][:100:200][::100][:100:200]",""));
+                       
+                       JLabel nameLabel = new JLabel( trans.get("customExpression.Name")+ " :");
+                       JLabel name = new JLabel ( expression.getName() );
+                       name = setLabelStyle(name);
+                       JLabel symbolLabel = new JLabel( trans.get("customExpression.Symbol")+ " :" );
+                       JLabel symbol = new JLabel ( expression.getSymbol());
+                       symbol = setLabelStyle(symbol);
+                       symbol.setBackground(Color.WHITE);
+                       
+                       JLabel unitLabel = new JLabel( trans.get("customExpression.Units")+ " :");
+                       UnitSelector unitSelector = new UnitSelector(expression.getType().getUnitGroup());
+                       //JLabel unitSelector = new JLabel ( expression.getUnit() );
+                       //unitSelector = setLabelStyle(unitSelector);
+                       //unitSelector.setBackground(Color.WHITE);
+                       
+                       JButton editButton = new JButton(Icons.EDIT);
+                       editButton.setToolTipText(trans.get("customExpression.Units.but.ttip.Edit"));
+                       editButton.setBorderPainted(false);
+                       editButton.addActionListener( new ActionListener() {
+                               @Override
+                               public void actionPerformed(ActionEvent e){
+                                       Window parent = SwingUtilities.getWindowAncestor(CustomExpressionPanel.this);
+                                       new ExpressionBuilderDialog(parent, doc, expression).setVisible(true);
+                                       updateExpressions();
+                               }
+                       });
+                       
+                       JButton upButton = new JButton(Icons.UP);
+                       upButton.setToolTipText(trans.get("customExpression.Units.but.ttip.MoveUp"));
+                       upButton.setBorderPainted(false);
+                       upButton.setVisible(showUp);
+                       upButton.addActionListener( new ActionListener() {
+                               @Override
+                               public void actionPerformed(ActionEvent e) {
+                                       moveExpression(expression, -1);
+                                       updateExpressions();
+                               }
+                       });
+                       
+                       JButton downButton = new JButton(Icons.DOWN);
+                       downButton.setToolTipText(trans.get("customExpression.Units.but.ttip.MoveDown"));
+                       downButton.setBorderPainted(false);
+                       downButton.setVisible(showDown);
+                       downButton.addActionListener( new ActionListener() {
+                               @Override
+                               public void actionPerformed(ActionEvent e) {
+                                       moveExpression(expression, 1);
+                                       updateExpressions();
+                               }
+                       });
+                       
+                       
+                       JButton deleteButton = new JButton(Icons.DELETE);
+                       //// Remove this expression
+                       deleteButton.setToolTipText(trans.get("customExpression.Units.but.ttip.Remove"));
+                       deleteButton.setBorderPainted(false);
+                       deleteButton.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(ActionEvent e) {
+                                       deleteExpression(expression);
+                                       updateExpressions();
+                               }
+                       });
+                       
+                       this.add(nameLabel);
+                       this.add(name, "width 200:200:400, growx");
+                       this.add(new JPanel());
+                       this.add(symbolLabel);
+                       this.add(symbol, "width :50:200");
+                       this.add(new JPanel());
+                       this.add(unitLabel);
+                       this.add(unitSelector, "width :50:100");
+                       this.add(new JPanel(), "growx");
+                       this.add(upButton, "right");
+                       this.add(downButton, "right");
+                       this.add(editButton, "right");
+                       this.add(deleteButton, "right");
+               }
+       }
+}
diff --git a/core/src/net/sf/openrocket/gui/customexpression/ExpressionBuilderDialog.java b/core/src/net/sf/openrocket/gui/customexpression/ExpressionBuilderDialog.java
new file mode 100644 (file)
index 0000000..615fdc1
--- /dev/null
@@ -0,0 +1,272 @@
+package net.sf.openrocket.gui.customexpression;
+
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+import javax.swing.SwingUtilities;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.gui.util.Icons;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.startup.Application;
+
+/**
+ * Dialog box for making a custom expression
+ * @author Richard Graham
+ *
+ */
+
+public class ExpressionBuilderDialog extends JDialog {
+
+       private static final Translator trans = Application.getTranslator();
+       private static final LogHelper log = Application.getLogger();
+       
+       private static final ImageIcon GreenIcon = Icons.loadImageIcon("pix/spheres/green-16x16.png", "OK");
+       private static final ImageIcon RedIcon = Icons.loadImageIcon("pix/spheres/red-16x16.png", "Bad");
+       
+       private CustomExpression expression;
+       private CustomExpression previousExpressionCopy;
+       
+       private final Window parentWindow;
+       private final OpenRocketDocument doc;
+       
+       // Define these check indicators to show if fields are OK
+       private final JLabel nameCheck = new JLabel(RedIcon);
+       private final JLabel expressionCheck = new JLabel(RedIcon);
+       private final JLabel unitCheck = new JLabel(RedIcon);
+       private final JButton okButton = new JButton(trans.get("dlg.but.ok"));
+       private final JTextField expressionField = new JTextField(20);
+       
+       public ExpressionBuilderDialog(Window parent, OpenRocketDocument doc){
+               this(parent, doc, new CustomExpression(doc));
+       }
+       
+       public ExpressionBuilderDialog(Window parent, final OpenRocketDocument doc, final CustomExpression previousExpression){
+               
+               super(parent, trans.get("ExpressionBuilderDialog.title"), JDialog.ModalityType.DOCUMENT_MODAL);
+               
+               this.doc = doc;
+               this.parentWindow = parent;
+               this.previousExpressionCopy = (CustomExpression) previousExpression.clone();
+               this.expression = previousExpression;
+                                       
+               //// Name box -- Check input when focus changes and transfer focus to next box on enter key
+               JLabel nameLabel = new JLabel(trans.get("customExpression.Name"));
+               final JTextField nameField = new JTextField(20); 
+               nameField.setText(expression.getName());
+               nameField.setFocusTraversalKeysEnabled(true);
+               nameField.addFocusListener(new FocusListener() {
+                       @Override
+                       public void focusGained(FocusEvent e) { }
+
+                       @Override
+                       public void focusLost(FocusEvent e) {
+                               expression.setName(nameField.getText());
+                               ExpressionBuilderDialog.this.updateOK();                                
+                       }
+               });
+               nameField.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               nameField.transferFocus();
+                       }
+               });
+               
+               //// Expression box -- for this one we check after each keypress using a keyListener. Enter transfers to next field
+               JLabel expressionLabel = new JLabel(trans.get("customExpression.Expression"));
+               expressionField.setText(expression.getExpressionString());
+               expressionField.addKeyListener(new KeyListener() {
+                       @Override
+                       public void keyReleased(KeyEvent arg0) {
+                               expression.setExpression(  expressionField.getText() );
+                               ExpressionBuilderDialog.this.updateOK();
+                       }
+
+                       @Override
+                       public void keyPressed(KeyEvent e) {}
+
+                       @Override
+                       public void keyTyped(KeyEvent e) {}
+               });
+               expressionField.addActionListener(new ActionListener(){
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               expressionField.transferFocus();
+                       }
+               });
+               
+               //// Units box -- with action listeners checking input after change in focus or enter press
+               JLabel unitLabel = new JLabel(trans.get("customExpression.Units"));
+               final JTextField unitField = new JTextField(5);
+               unitField.setText(expression.getUnit());
+               unitField.addFocusListener(new FocusListener(){
+                       @Override
+                       public void focusLost(FocusEvent arg0) { 
+                               expression.setUnit(unitField.getText()) ;
+                               ExpressionBuilderDialog.this.updateOK();
+                       }
+                       @Override
+                       public void focusGained(FocusEvent arg0) {}                     
+               });
+               unitField.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               unitField.transferFocus();
+                       }
+               });
+               
+               //// Symbol box
+               JLabel symbolLabel = new JLabel(trans.get("customExpression.Symbol"));
+               final JTextField symbolField = new JTextField(5);
+               symbolField.setText(expression.getSymbol());
+               symbolField.addFocusListener(new FocusListener(){
+                       @Override
+                       public void focusLost(FocusEvent arg0) { 
+                               expression.setSymbol(symbolField.getText()) ;
+                               ExpressionBuilderDialog.this.updateOK();
+                       }
+                       @Override
+                       public void focusGained(FocusEvent arg0) {}                     
+               });
+               symbolField.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               symbolField.transferFocus();
+                       }
+               });
+               
+               
+               //// Insert variable button
+               final JButton insertVariableButton = new JButton(trans.get("ExpressionBuilderDialog.InsertVariable"));
+               insertVariableButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               log.debug("Opening insert variable window");
+                               Window parentWindow = SwingUtilities.getWindowAncestor(ExpressionBuilderDialog.this);
+                               new VariableSelector(parentWindow, ExpressionBuilderDialog.this, doc).setVisible(true);
+                       }
+               });
+               
+               //// Insert operator button
+               final JButton insertOperatorButton = new JButton(trans.get("ExpressionBuilderDialog.InsertOperator"));
+               insertOperatorButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               log.debug("Opening insert operator window");
+                               Window parentWindow = SwingUtilities.getWindowAncestor(ExpressionBuilderDialog.this);
+                               new OperatorSelector(parentWindow, ExpressionBuilderDialog.this).setVisible(true);
+                       }
+               });
+               
+               //// OK Button
+               okButton.setEnabled(false);
+               okButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               // add to this simulation
+                               expression.addToDocument();
+                               
+                               // close window
+                               ExpressionBuilderDialog.this.dispose();
+                       }
+               });
+
+               //// Cancel button
+               final JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               expression.overwrite(previousExpressionCopy);
+                               ExpressionBuilderDialog.this.dispose();
+                       }
+               });
+                       
+               //// Set to tips
+               nameCheck.setToolTipText(trans.get("ExpressionBuilderDialog.led.ttip.Name"));
+               unitCheck.setToolTipText(trans.get("ExpressionBuilderDialog.led.ttip.Symbol"));
+               expressionCheck.setToolTipText(trans.get("ExpressionBuilderDialog.led.ttip.Expression"));
+               
+               //// Do the layout
+               JPanel mainPanel = new JPanel(new MigLayout());
+               mainPanel.add(nameLabel);
+               mainPanel.add(nameField);
+               mainPanel.add(nameCheck, "wrap, center");
+               mainPanel.add(symbolLabel);
+               mainPanel.add(symbolField, "split 4, growx");
+               mainPanel.add(new JPanel());
+               mainPanel.add(unitLabel, "right");
+               mainPanel.add(unitField, "right, growx");
+               mainPanel.add(unitCheck, "wrap, center");
+               mainPanel.add(expressionLabel);
+               mainPanel.add(expressionField);
+               mainPanel.add(expressionCheck, "wrap, center");
+               mainPanel.add(insertOperatorButton, "span 2, right, split 2");
+               mainPanel.add(insertVariableButton, "right, wrap");
+               mainPanel.add(cancelButton, "span 2, right, width :50:100");
+               mainPanel.add(okButton, "right, width :50:100, wrap");
+
+               this.add(mainPanel);
+               this.validate();
+               this.pack();
+               this.setLocationByPlatform(true);
+               this.updateOK();
+               
+       }
+
+       /**
+        * Enable OK button only if all the fields are ok
+        * @param okButton
+        */
+       protected void updateOK() {
+               
+               boolean nameOK = expression.checkName();
+               boolean unitOK = expression.checkUnit();
+               boolean symbolOK = expression.checkSymbol();
+               boolean expressionOK = expression.checkExpression();
+               
+               if (nameOK)                             { nameCheck.setIcon(GreenIcon);                 } else { nameCheck.setIcon(RedIcon); }
+               if (unitOK && symbolOK) { unitCheck.setIcon(GreenIcon);                 } else { unitCheck.setIcon(RedIcon); }
+               if (expressionOK)               { expressionCheck.setIcon(GreenIcon);   } else { expressionCheck.setIcon(RedIcon); }
+               
+               okButton.setEnabled( nameOK && unitOK && symbolOK && expressionOK );
+       }
+       
+       /**
+        * Inserts a string into the expression box at the position of the cursor.
+        * String will be padded with spaces either side
+        * Expression box will be focused after this is called.
+        * For strings containing an ( , cursor will be moved to the point after that, otherwise, cursor will move to the end of the inserted string.
+        * @param str
+        */
+       public void pasteIntoExpression(String str) {
+           int pos = expressionField.getCaretPosition();
+           String current = expressionField.getText();
+           expressionField.setText(current.subSequence(0, pos) + " " + str + " " + current.subSequence(pos, current.length()));
+           expressionField.requestFocus();
+           int bracketPos = str.indexOf("(");
+           if (bracketPos != -1){
+               expressionField.setCaretPosition(pos+2+bracketPos);
+           }
+           else {
+               expressionField.setCaretPosition(pos+2+str.length());
+           }
+       }
+}
diff --git a/core/src/net/sf/openrocket/gui/customexpression/OperatorSelector.java b/core/src/net/sf/openrocket/gui/customexpression/OperatorSelector.java
new file mode 100644 (file)
index 0000000..d51af30
--- /dev/null
@@ -0,0 +1,157 @@
+package net.sf.openrocket.gui.customexpression;
+
+import java.awt.Point;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionAdapter;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.KeyStroke;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.TextUtil;
+
+public class OperatorSelector extends JDialog {
+       
+       private static final Translator trans = Application.getTranslator();
+       private static final LogHelper log = Application.getLogger();
+
+       private final Window parentWindow;
+       
+       private final JTable table;
+       private final OperatorTableModel tableModel;
+       private final ExpressionBuilderDialog parentBuilder;
+       
+       public OperatorSelector(Window parent, final ExpressionBuilderDialog parentBuilder){
+               
+               super(parent, trans.get("CustomOperatorSelector.title"), JDialog.ModalityType.DOCUMENT_MODAL);
+               
+               this.parentWindow = parent;
+               this.parentBuilder = parentBuilder;
+               
+               final JButton insertButton = new JButton(trans.get("ExpressionBuilderDialog.InsertOperator"));
+               
+               JPanel mainPanel = new JPanel(new MigLayout());
+               
+               //// Table of variables and model
+               tableModel = new OperatorTableModel();
+               table = new JTable(tableModel);
+               
+               table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+               int width = table.getColumnModel().getTotalColumnWidth();
+               table.getColumnModel().getColumn(0).setPreferredWidth( (int) (.1 * width));
+               table.getColumnModel().getColumn(1).setPreferredWidth( (int) (.9 * width));
+               table.setAutoCreateRowSorter(true);
+               
+               table.addMouseMotionListener(new MouseMotionAdapter(){
+                       @Override
+                       public void mouseMoved(MouseEvent e){
+                               Point p = e.getPoint();
+                               int row = table.rowAtPoint(p);
+                               int col = table.columnAtPoint(p);
+                               if (col == 1 && row > -1){
+                                       String description = String.valueOf(table.getValueAt(row, 1));
+                                       description = TextUtil.wrap(description, 60);
+                                       table.setToolTipText(description);
+                               } else {
+                                       table.setToolTipText(null);
+                               }
+                       }
+               });
+               
+               table.addMouseListener(new MouseListener(){
+                       @Override
+                       public void mouseClicked(MouseEvent e){
+                               if (e.getClickCount() == 2){
+                                       log.debug("Selected operator by double clicking.");
+                                       selectOperator();
+                               }
+                       }
+                       @Override
+                       public void mouseEntered(MouseEvent e) {}
+                       @Override
+                       public void mouseExited(MouseEvent e) {}
+                       @Override
+                       public void mousePressed(MouseEvent e) {}
+                       @Override
+                       public void mouseReleased(MouseEvent e) {}
+               } );
+               
+               InputMap inputMap = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+               ActionMap actionMap = table.getActionMap();
+               KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+               inputMap.put(enter, "select");
+               actionMap.put("select", new AbstractAction(){
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               log.debug("Selected operator by enter key");
+                               selectOperator();
+                       }
+               });
+               
+               JScrollPane scrollPane = new JScrollPane(table);
+               table.setFillsViewportHeight(true);
+               table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+                               @Override
+                               public void valueChanged(ListSelectionEvent e){
+                                       if (table.getSelectedRowCount() == 1){
+                                               insertButton.setEnabled(true);
+                                       }
+                                       else {
+                                               insertButton.setEnabled(false);
+                                       }
+                               }
+                       });
+               
+               mainPanel.add(scrollPane, "wrap, push, grow");
+               
+               //// Cancel button
+               final JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               OperatorSelector.this.dispose();
+                       }
+               });
+               mainPanel.add(cancelButton, "right, width :100:200, split 2");
+               
+               //// Insert button
+               insertButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               selectOperator();
+                       }
+               });
+               insertButton.setEnabled(false); // disabled by default, only enable when a variable selected
+               mainPanel.add(insertButton, "right, width :100:200, wrap");
+
+               this.add(mainPanel);
+               this.validate();
+               this.pack();
+               this.setLocationByPlatform(true);       
+       }
+       
+       private void selectOperator(){
+               int row = table.getSelectedRow();
+               String str = table.getValueAt(row, 0).toString();
+               parentBuilder.pasteIntoExpression(str);
+               OperatorSelector.this.dispose();
+       }
+}
diff --git a/core/src/net/sf/openrocket/gui/customexpression/OperatorTableModel.java b/core/src/net/sf/openrocket/gui/customexpression/OperatorTableModel.java
new file mode 100644 (file)
index 0000000..3b084da
--- /dev/null
@@ -0,0 +1,52 @@
+package net.sf.openrocket.gui.customexpression;
+
+import javax.swing.table.AbstractTableModel;
+
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.simulation.customexpression.Functions;
+import net.sf.openrocket.startup.Application;
+
+public class OperatorTableModel extends AbstractTableModel {
+
+       private static final Translator trans = Application.getTranslator();
+       
+       private static final String[] columnNames = {trans.get("customExpression.Operator"), trans.get("customExpression.Description")};
+       
+       private final Object[] operators = Functions.AVAILABLE_OPERATORS.keySet().toArray();
+       private final Object[] descriptions = Functions.AVAILABLE_OPERATORS.values().toArray();
+       
+       public OperatorTableModel(){
+               
+       }
+       
+       @Override
+       public int getColumnCount() {
+               return 2;
+       }
+
+       @Override
+       public int getRowCount() {
+               return Functions.AVAILABLE_OPERATORS.size();
+       }
+
+       @Override
+       public Object getValueAt(int row, int col) {
+               if (col == 0){
+                       return operators[row].toString();
+               }
+               else if (col == 1){
+                       return descriptions[row].toString();
+               }
+               return null;
+       }
+       
+       @Override
+       public String getColumnName(int col) {
+        return columnNames[col];
+    }
+       
+       public String getOperatorAt(int row) {
+               return operators[row].toString();
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/gui/customexpression/VariableSelector.java b/core/src/net/sf/openrocket/gui/customexpression/VariableSelector.java
new file mode 100644 (file)
index 0000000..90130e6
--- /dev/null
@@ -0,0 +1,149 @@
+package net.sf.openrocket.gui.customexpression;
+
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+import javax.swing.AbstractAction;
+import javax.swing.ActionMap;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.KeyStroke;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.table.JTableHeader;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.document.Simulation;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.startup.Application;
+
+/**
+ * Dialog to select from available custom variables
+ * @author Richard Graham
+ *
+ */
+
+public class VariableSelector extends JDialog {
+
+       private static final Translator trans = Application.getTranslator();
+       private static final LogHelper log = Application.getLogger();
+       
+       private final JTable table;
+       private final VariableTableModel tableModel;
+       private final ExpressionBuilderDialog parentBuilder;
+
+       public VariableSelector(Window parent, final ExpressionBuilderDialog parentBuilder, final OpenRocketDocument doc){
+
+               super(parent, trans.get("CustomVariableSelector.title"), JDialog.ModalityType.DOCUMENT_MODAL);
+
+               this.parentBuilder = parentBuilder;
+               final JButton insertButton = new JButton(trans.get("ExpressionBuilderDialog.InsertVariable"));
+
+               JPanel mainPanel = new JPanel(new MigLayout());
+
+               //// Table of variables and model
+               tableModel = new VariableTableModel(doc);
+               table = new JTable(tableModel);
+               
+               table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
+               table.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+               int width = table.getColumnModel().getTotalColumnWidth();
+               table.getColumnModel().getColumn(0).setPreferredWidth( (int) (.7 * width));
+               table.getColumnModel().getColumn(1).setPreferredWidth( (int) (.15 * width));
+               table.getColumnModel().getColumn(2).setPreferredWidth( (int) (.15 * width));
+               table.setAutoCreateRowSorter(true);
+
+               table.addMouseListener(new MouseListener(){
+                       @Override
+                       public void mouseClicked(MouseEvent e){
+                               if (e.getClickCount() == 2){
+                                       log.debug("Selected variable by double clicking.");
+                                       selectVariable();
+                               }
+                       }
+                       @Override
+                       public void mouseEntered(MouseEvent e) {}
+                       @Override
+                       public void mouseExited(MouseEvent e) {}
+                       @Override
+                       public void mousePressed(MouseEvent e) {}
+                       @Override
+                       public void mouseReleased(MouseEvent e) {}
+               } );
+               
+               InputMap inputMap = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+               ActionMap actionMap = table.getActionMap();
+               KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
+               inputMap.put(enter, "select");
+               actionMap.put("select", new AbstractAction(){
+                       @Override
+                       public void actionPerformed(ActionEvent arg0) {
+                               log.debug("Selected variable by enter key");
+                               selectVariable();
+                       }
+               });
+               
+
+               JScrollPane scrollPane = new JScrollPane(table);
+               table.setFillsViewportHeight(true);
+               table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+                       @Override
+                       public void valueChanged(ListSelectionEvent e){
+                               if (table.getSelectedRowCount() == 1){
+                                       insertButton.setEnabled(true);
+                               }
+                               else {
+                                       insertButton.setEnabled(false);
+                               }
+                       }
+               });
+
+               mainPanel.add(scrollPane, "wrap, push, grow");
+
+               //// Cancel button
+               final JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               VariableSelector.this.dispose();
+                       }
+               });
+               mainPanel.add(cancelButton, "right, width :100:200, split 2");
+
+               //// Insert button
+               insertButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               selectVariable();
+                       }
+               });
+               insertButton.setEnabled(false); // disabled by default, only enable when a variable selected
+               mainPanel.add(insertButton, "right, width :100:200, wrap");
+
+               this.add(mainPanel);
+               this.validate();
+               this.pack();
+               this.setLocationByPlatform(true);       
+       }
+       
+       private void selectVariable(){
+               int row = table.getSelectedRow();
+               String str = table.getValueAt(row, 1).toString();
+               parentBuilder.pasteIntoExpression(str);
+               VariableSelector.this.dispose();
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/gui/customexpression/VariableTableModel.java b/core/src/net/sf/openrocket/gui/customexpression/VariableTableModel.java
new file mode 100644 (file)
index 0000000..f9d6497
--- /dev/null
@@ -0,0 +1,84 @@
+/**
+ * 
+ */
+package net.sf.openrocket.gui.customexpression;
+
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.swing.JTable;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableColumnModel;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.startup.Application;
+
+/**
+ * @author Richard Graham
+ *
+ */
+public class VariableTableModel extends AbstractTableModel {
+
+       private static final Translator trans = Application.getTranslator();
+
+       private List<FlightDataType> types; // = new ArrayList<FlightDataType>();
+       private static final String[] columnNames = {trans.get("customExpression.Name"), trans.get("customExpression.Symbol"), trans.get("customExpression.Units")};
+       
+       /*
+        * Table model will be constructed with all the built in variables and any custom variables defined
+        */
+       public VariableTableModel(OpenRocketDocument doc){
+               
+               types = new ArrayList<FlightDataType>( doc.getFlightDataTypes() );
+               
+               //Collections.addAll(types, FlightDataType.ALL_TYPES);
+               //for (CustomExpression expression : doc.getCustomExpressions()){
+               //      types.add(expression.getType());
+               //}
+       }
+       
+       @Override
+       public int getColumnCount() {
+               return 3;
+       }
+
+       @Override
+       public int getRowCount() {
+               return types.size();
+       }
+
+       @Override
+       public Object getValueAt(int row, int col) {
+               if (col == 0)
+                       return types.get(row).getName();
+               else if (col == 1)
+                       return types.get(row).getSymbol();
+               else if (col == 2)
+                       return types.get(row).getUnitGroup().getSIUnit().toString();
+               
+               return null;
+       }
+       
+       @Override
+       public String getColumnName(int col) {
+        return columnNames[col];
+    }
+       
+       public String getSymbolAt(int row) {
+               if (row < 0 || row > types.size()){
+                       return "";
+               }
+               else { 
+                       return types.get(row).getSymbol();
+               }
+       }
+}
index 1bad92f0dff7bc815b51eec4c2e77029683e7274..5b7d6cc93f3bee1e84cd436aea8a9a0bbb871e7a 100644 (file)
@@ -31,6 +31,7 @@ public class AboutDialog extends JDialog {
                        "Sampo Niskanen (main developer)<br>" +
                        "Doug Pedrick (RockSim file format, printing)<br>" +
                        "Kevin Ruland (Android version)<br>" +
+                       "Bill Kuker (3D visualization)<br>" +
                        "Boris du Reau (internationalization, translation lead)<br>" +
                        "Richard Graham (geodetic computations)<br>" +
                        "Jason Blood (finset import)<br><br>" +
@@ -40,10 +41,14 @@ public class AboutDialog extends JDialog {
                        "Tripoli Spain (Spanish)<br>" +
                        "Sky Dart Team (Russian)<br>" +
                        "Mauro Biasutti (Italian)<br><br>" +
+                       "Vladimir Beran  (Czech)<br><br>" +
+                       "Polish Rocketry Society / \u0141ukasz & Alex kazanski  (Polish)<br><br>" +
                        "<b>OpenRocket utilizes the following libraries:</b><br><br>" +
                        "MiG Layout (http://www.miglayout.com/)<br>" +
                        "JFreeChart (http://www.jfree.org/jfreechart/)<br>" +
-                       "iText (http://www.itextpdf.com/)";
+                       "iText (http://www.itextpdf.com/)<br>" +
+                       "exp4j (http://projects.congrace.de/exp4j/index.html)<br>" +
+                       "JOGL (http://jogamp.org/jogl/www/)";
        
        
        public AboutDialog(JFrame parent) {
index 635e6468ecfe5a8b5901ca186a1595ffa0f385a6..9f5064ed8a0f12153b26439b1d773effcc9c435e 100644 (file)
@@ -119,7 +119,7 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                roll = new DoubleModel(rocketPanel, "CPRoll", UnitGroup.UNITS_ROLL);
                
                //// Wind direction:
-               panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.winddir")), "width 100lp!");
+               panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.winddir")), "width 120lp!");
                panel.add(new UnitSelector(theta, true), "width 50lp!");
                BasicSlider slider = new BasicSlider(theta.getSliderModel(0, 2 * Math.PI));
                panel.add(slider, "growx, split 2");
@@ -149,17 +149,17 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                panel.add(scrollPane, "gap paragraph, spany 4, width 300lp!, growy 1, height :100lp:, wrap");
                
                ////Angle of attack:
-               panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.angleofattack")), "width 100lp!");
+               panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.angleofattack")), "width 120lp!");
                panel.add(new UnitSelector(aoa, true), "width 50lp!");
                panel.add(new BasicSlider(aoa.getSliderModel(0, Math.PI)), "growx, wrap");
                
                //// Mach number:
-               panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.machnumber")), "width 100lp!");
+               panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.machnumber")), "width 120lp!");
                panel.add(new UnitSelector(mach, true), "width 50lp!");
                panel.add(new BasicSlider(mach.getSliderModel(0, 3)), "growx, wrap");
                
                //// Roll rate:
-               panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.rollrate")), "width 100lp!");
+               panel.add(new JLabel(trans.get("componentanalysisdlg.lbl.rollrate")), "width 120lp!");
                panel.add(new UnitSelector(roll, true), "width 50lp!");
                panel.add(new BasicSlider(roll.getSliderModel(-20 * 2 * Math.PI, 20 * 2 * Math.PI)),
                                "growx, wrap paragraph");
@@ -193,7 +193,7 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                        public Object getValueAt(int row) {
                                RocketComponent c = cpData.get(row).getComponent();
                                if (c instanceof Rocket) {
-                                       return "Total";
+                                       return trans.get("componentanalysisdlg.TOTAL");
                                }
                                return c.toString();
                        }
@@ -203,7 +203,7 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                                return 200;
                        }
                },
-                               new Column("CG / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
+                               new Column(trans.get("componentanalysisdlg.TabStability.Col.CG") + " / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
                                        private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
                                        
                                        @Override
@@ -211,7 +211,7 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                                                return unit.toString(cgData.get(row).x);
                                        }
                                },
-                               new Column("Mass / " + UnitGroup.UNITS_MASS.getDefaultUnit().getUnit()) {
+                               new Column(trans.get("componentanalysisdlg.TabStability.Col.Mass") + " / " + UnitGroup.UNITS_MASS.getDefaultUnit().getUnit()) {
                                        private Unit unit = UnitGroup.UNITS_MASS.getDefaultUnit();
                                        
                                        @Override
@@ -219,7 +219,7 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                                                return unit.toString(cgData.get(row).weight);
                                        }
                                },
-                               new Column("CP / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
+                               new Column(trans.get("componentanalysisdlg.TabStability.Col.CP") + " / " + UnitGroup.UNITS_LENGTH.getDefaultUnit().getUnit()) {
                                        private Unit unit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
                                        
                                        @Override
@@ -268,7 +268,7 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                                        public Object getValueAt(int row) {
                                                RocketComponent c = dragData.get(row).getComponent();
                                                if (c instanceof Rocket) {
-                                                       return "Total";
+                                                       return trans.get("componentanalysisdlg.TOTAL");
                                                }
                                                return c.toString();
                                        }
@@ -342,7 +342,7 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                                        public Object getValueAt(int row) {
                                                RocketComponent c = rollData.get(row).getComponent();
                                                if (c instanceof Rocket) {
-                                                       return "Total";
+                                                       return trans.get("componentanalysisdlg.TOTAL");
                                                }
                                                return c.toString();
                                        }
@@ -407,13 +407,13 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                this.addWindowListener(new WindowAdapter() {
                        @Override
                        public void windowClosed(WindowEvent e) {
-                               System.out.println("Closing method called: " + this);
+                               //System.out.println("Closing method called: " + this);
                                theta.removeChangeListener(ComponentAnalysisDialog.this);
                                aoa.removeChangeListener(ComponentAnalysisDialog.this);
                                mach.removeChangeListener(ComponentAnalysisDialog.this);
                                roll.removeChangeListener(ComponentAnalysisDialog.this);
                                configuration.removeChangeListener(ComponentAnalysisDialog.this);
-                               System.out.println("SETTING NAN VALUES");
+                               //System.out.println("SETTING NAN VALUES");
                                rocketPanel.setCPAOA(Double.NaN);
                                rocketPanel.setCPTheta(Double.NaN);
                                rocketPanel.setCPMach(Double.NaN);
@@ -541,7 +541,7 @@ public class ComponentAnalysisDialog extends JDialog implements ChangeListener {
                // Set warnings
                if (set.isEmpty()) {
                        warningList.setListData(new String[] {
-                                       "<html><i><font color=\"gray\">No warnings.</font></i>"
+                                       trans.get("componentanalysisdlg.noWarnings")
                        });
                } else {
                        warningList.setListData(new Vector<Warning>(set));
index 5e5aece88236278b28b4e56ea451daa372f006f0..9ef95a9b6c38c4f505fb69638303f2358159e75b 100644 (file)
@@ -15,6 +15,7 @@ import javax.swing.JSpinner;
 import javax.swing.JTextField;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.database.Databases;
 import net.sf.openrocket.gui.adaptors.DoubleModel;
 import net.sf.openrocket.gui.components.StyledLabel;
 import net.sf.openrocket.gui.components.UnitSelector;
@@ -24,7 +25,8 @@ import net.sf.openrocket.material.Material;
 import net.sf.openrocket.startup.Application;
 
 public class CustomMaterialDialog extends JDialog {
-
+       private static final Translator trans = Application.getTranslator();
+       
        private final Material originalMaterial;
        
        private boolean okClicked = false;
@@ -34,14 +36,13 @@ public class CustomMaterialDialog extends JDialog {
        private JSpinner densitySpinner;
        private UnitSelector densityUnit;
        private JCheckBox addBox;
-       private static final Translator trans = Application.getTranslator();
-
+       
        public CustomMaterialDialog(Window parent, Material material, boolean saveOption,
                        String title) {
                this(parent, material, saveOption, title, null);
        }
        
-               
+       
        public CustomMaterialDialog(Window parent, Material material, boolean saveOption,
                        String title, String note) {
                //// Custom material
@@ -54,14 +55,14 @@ public class CustomMaterialDialog extends JDialog {
                
                // Add title and note
                if (title != null) {
-                       panel.add(new JLabel("<html><b>" + title + ":"), 
-                                       "gapleft para, span, wrap" + (note == null ? " para":""));
+                       panel.add(new JLabel("<html><b>" + title + ":"),
+                                       "gapleft para, span, wrap" + (note == null ? " para" : ""));
                }
                if (note != null) {
                        panel.add(new StyledLabel(note, -1), "span, wrap para");
                }
                
-
+               
                //// Material name
                panel.add(new JLabel(trans.get("custmatdlg.lbl.Materialname")));
                nameField = new JTextField(15);
@@ -93,7 +94,7 @@ public class CustomMaterialDialog extends JDialog {
                panel.add(new JLabel(trans.get("custmatdlg.lbl.Materialdensity")));
                densitySpinner = new JSpinner();
                panel.add(densitySpinner, "w 70lp");
-               densityUnit = new UnitSelector((DoubleModel)null);
+               densityUnit = new UnitSelector((DoubleModel) null);
                panel.add(densityUnit, "w 30lp");
                panel.add(new JPanel(), "growx, wrap");
                updateDensityModel();
@@ -103,9 +104,9 @@ public class CustomMaterialDialog extends JDialog {
                if (saveOption) {
                        //// Add material to database
                        addBox = new JCheckBox(trans.get("custmatdlg.checkbox.Addmaterial"));
-                       panel.add(addBox,"span, wrap");
+                       panel.add(addBox, "span, wrap");
                }
-                       
+               
                //// OK button
                JButton okButton = new JButton(trans.get("dlg.but.ok"));
                
@@ -116,7 +117,7 @@ public class CustomMaterialDialog extends JDialog {
                                CustomMaterialDialog.this.setVisible(false);
                        }
                });
-               panel.add(okButton,"span, split, tag ok");
+               panel.add(okButton, "span, split, tag ok");
                
                ////  Cancel
                JButton closeButton = new JButton(trans.get("dlg.but.cancel"));
@@ -127,7 +128,7 @@ public class CustomMaterialDialog extends JDialog {
                                CustomMaterialDialog.this.setVisible(false);
                        }
                });
-               panel.add(closeButton,"tag cancel");
+               panel.add(closeButton, "tag cancel");
                
                this.setContentPane(panel);
                this.pack();
@@ -149,7 +150,7 @@ public class CustomMaterialDialog extends JDialog {
        public Material getMaterial() {
                Material.Type type;
                String name;
-               double density;
+               double materialDensity;
                
                if (typeBox != null) {
                        type = (Material.Type) typeBox.getSelectedItem();
@@ -159,9 +160,9 @@ public class CustomMaterialDialog extends JDialog {
                
                name = nameField.getText().trim();
                
-               density = this.density.getValue();
+               materialDensity = this.density.getValue();
                
-               return Material.newMaterial(type, name, density, true);
+               return Databases.findMaterial(type, name, materialDensity);
        }
        
        
index 0a41ce66546fa079efaac3223ba6b30d15baf01e..6735e0d3a45d2ba17a791bc48dc526ce22bedb03 100644 (file)
@@ -70,15 +70,7 @@ public class EditMotorConfigurationDialog extends JDialog {
                
                this.rocket = rocket;
                
-               ArrayList<MotorMount> mountList = new ArrayList<MotorMount>();
-               Iterator<RocketComponent> iterator = rocket.iterator();
-               while (iterator.hasNext()) {
-                       RocketComponent c = iterator.next();
-                       if (c instanceof MotorMount) {
-                               mountList.add((MotorMount) c);
-                       }
-               }
-               mounts = mountList.toArray(new MotorMount[0]);
+               mounts = rocket.getMotorMounts().toArray( new MotorMount[0]) ;
                
 
 
index 729586d3455e70e69423fbbc5200ab2942051360..bf2249ced76e5e22aeb491e1ec5af0d631720b8e 100644 (file)
@@ -61,22 +61,25 @@ public class PrintDialog extends JDialog implements TreeSelectionListener {
        private JButton previewButton;
        private JButton saveAsPDF;
        private JButton cancel;
-       
+
+    private double rotation = 0d;
        
        private final static SwingPreferences prefs = (SwingPreferences) Application.getPreferences();
        
        /**
         * Constructor.
         *
+     * @param parent     the parent awt component
         * @param orDocument the OR rocket container
+     * @param theRotation the angle of rocket figure rotation
         */
-       public PrintDialog(Window parent, OpenRocketDocument orDocument) {
+       public PrintDialog(Window parent, OpenRocketDocument orDocument, double theRotation) {
                super(parent, trans.get("title"), ModalityType.APPLICATION_MODAL);
                
 
                JPanel panel = new JPanel(new MigLayout("fill, gap rel unrel"));
                this.add(panel);
-               
+               rotation = theRotation;
 
                // before any Desktop APIs are used, first check whether the API is
                // supported by this particular VM on this particular host
@@ -257,7 +260,7 @@ public class PrintDialog extends JDialog implements TreeSelectionListener {
        /**
         * Generate a report using a temporary file.  The file will be deleted upon JVM exit.
         *
-        * @param paper the name of the paper size
+     * @param settings  the container of different print settings
         *
         * @return a file, populated with the "printed" output (the rocket info)
         *
@@ -273,7 +276,7 @@ public class PrintDialog extends JDialog implements TreeSelectionListener {
         * Generate a report to a specified file.
         *
         * @param f     the file to which rocket data will be written
-        * @param paper the name of the paper size
+        * @param settings  the container of different print settings
         *
         * @return a file, populated with the "printed" output (the rocket info)
         *
@@ -281,7 +284,7 @@ public class PrintDialog extends JDialog implements TreeSelectionListener {
         */
        private File generateReport(File f, PrintSettings settings) throws IOException {
                Iterator<PrintableContext> toBePrinted = currentTree.getToBePrinted();
-               new PrintController().print(document, toBePrinted, new FileOutputStream(f), settings);
+               new PrintController().print(document, toBePrinted, new FileOutputStream(f), settings, rotation);
                return f;
        }
        
index eeb939c7aa09e50ec6efa37bfaa921a9f99d85c7..ca4205d2dc220b1f7b04fcd4d1be184d93021ff8 100644 (file)
@@ -29,7 +29,7 @@ public class MotorChooserDialog extends JDialog implements CloseableDialog {
 
        
        public MotorChooserDialog(Motor current, double delay, double diameter, Window owner) {
-               super(owner, "Select a rocket motor", Dialog.ModalityType.APPLICATION_MODAL);
+               super(owner, trans.get ("MotorChooserDialog.title"), Dialog.ModalityType.APPLICATION_MODAL);
                
                // Check that the motor database has been loaded properly
                MotorDatabaseLoadingDialog.check(null);
index d4cefca2b51275587b1ad8a9add6220b1648f842..7520a01bc1e0ba84277a8215579d06eb6e6c323e 100644 (file)
@@ -116,28 +116,28 @@ enum ThrustCurveMotorColumns {
                        tip += "<i>" + desc.replace("\n", "<br>") + "</i><br><hr>";
                }
                
-               tip += ("Diameter: " +
+               tip += (trans.get("TCurveMotor.ttip.diameter") + " " +
                                UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(m.getDiameter()) +
                                "<br>");
-               tip += ("Length: " +
+               tip += (trans.get("TCurveMotor.ttip.length") + " " +
                                UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit().toStringUnit(m.getLength()) +
                                "<br>");
-               tip += ("Maximum thrust: " +
+               tip += (trans.get("TCurveMotor.ttip.maxThrust") + " " +
                                UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(m.getMaxThrustEstimate()) +
                                "<br>");
-               tip += ("Average thrust: " +
+               tip += (trans.get("TCurveMotor.ttip.avgThrust") + " " +
                                UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(m.getAverageThrustEstimate()) +
                                "<br>");
-               tip += ("Burn time: " +
+               tip += (trans.get("TCurveMotor.ttip.burnTime") + " " +
                                UnitGroup.UNITS_SHORT_TIME.getDefaultUnit()
                                                .toStringUnit(m.getBurnTimeEstimate()) + "<br>");
-               tip += ("Total impulse: " +
+               tip += (trans.get("TCurveMotor.ttip.totalImpulse") + " " +
                                UnitGroup.UNITS_IMPULSE.getDefaultUnit()
                                                .toStringUnit(m.getTotalImpulseEstimate()) + "<br>");
-               tip += ("Launch mass: " +
+               tip += (trans.get("TCurveMotor.ttip.launchMass") + " " +
                                UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(m.getLaunchCG().weight) +
                                "<br>");
-               tip += ("Empty mass: " +
+               tip += (trans.get("TCurveMotor.ttip.emptyMass") + " " +
                                UnitGroup.UNITS_MASS.getDefaultUnit()
                                                .toStringUnit(m.getEmptyCG().weight));
                return tip;
index 8e6fe5d6d71955114aec1eb5f156fe7440e02c06..7deaaa8f1e5e7e5922e98c74cf1e18f237f98b9c 100644 (file)
@@ -14,6 +14,7 @@ import java.awt.event.MouseEvent;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Locale;
 import java.util.prefs.Preferences;
 
 import javax.swing.BorderFactory;
@@ -333,7 +334,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec
                                String[] split = text.split("\\s+");
                                ArrayList<String> list = new ArrayList<String>();
                                for (String s : split) {
-                                       s = s.trim().toLowerCase();
+                                       s = s.trim().toLowerCase(Locale.getDefault());
                                        if (s.length() > 0) {
                                                list.add(s);
                                        }
@@ -762,7 +763,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec
                s = s.trim();
                if (s.length() == 0) {
                        //// No description available.
-                       comment.setText("No description available.");
+                       comment.setText(trans.get("TCMotorSelPan.noDescription"));
                        comment.setFont(noCommentFont);
                        comment.setForeground(NO_COMMENT_COLOR);
                } else {
@@ -776,7 +777,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec
        private void scrollSelectionVisible() {
                if (selectedMotorSet != null) {
                        int index = table.convertRowIndexToView(model.getIndex(selectedMotorSet));
-                       System.out.println("index=" + index);
+                       //System.out.println("index=" + index);
                        table.getSelectionModel().setSelectionInterval(index, index);
                        Rectangle rect = table.getCellRect(index, 0, true);
                        rect = new Rectangle(rect.x, rect.y - 100, rect.width, rect.height + 200);
@@ -943,7 +944,7 @@ public class ThrustCurveMotorSelectionPanel extends JPanel implements MotorSelec
                public boolean filterByString(ThrustCurveMotorSet m) {
                        main: for (String s : searchTerms) {
                                for (ThrustCurveMotorColumns col : ThrustCurveMotorColumns.values()) {
-                                       String str = col.getValue(m).toString().toLowerCase();
+                                       String str = col.getValue(m).toString().toLowerCase(Locale.getDefault());
                                        if (str.indexOf(s) >= 0)
                                                continue main;
                                }
index 033da286717b9c5a8f485c52c00241831a75a003..7a0ecc5fc95e5b12dedc6140995150390789eca1 100644 (file)
@@ -108,7 +108,7 @@ public class GeneralOptimizationDialog extends JDialog {
        
        private static final Collator collator = Collator.getInstance();
        
-
+       
        private static final String GOAL_MAXIMIZE = trans.get("goal.maximize");
        private static final String GOAL_MINIMIZE = trans.get("goal.minimize");
        private static final String GOAL_SEEK = trans.get("goal.seek");
@@ -116,17 +116,17 @@ public class GeneralOptimizationDialog extends JDialog {
        private static final String START_TEXT = trans.get("btn.start");
        private static final String STOP_TEXT = trans.get("btn.stop");
        
-
-
+       
+       
        private final List<OptimizableParameter> optimizationParameters = new ArrayList<OptimizableParameter>();
        private final Map<Object, List<SimulationModifier>> simulationModifiers =
                        new HashMap<Object, List<SimulationModifier>>();
        
-
+       
        private final OpenRocketDocument baseDocument;
        private OpenRocketDocument documentCopy;
        
-
+       
        private final JButton addButton;
        private final JButton removeButton;
        private final JButton removeAllButton;
@@ -177,7 +177,7 @@ public class GeneralOptimizationDialog extends JDialog {
        /** The optimization worker that is running */
        private OptimizationWorker worker = null;
        
-
+       
        private double bestValue = Double.NaN;
        private Unit bestValueUnit = Unit.NOUNIT2;
        private int stepCount = 0;
@@ -187,7 +187,7 @@ public class GeneralOptimizationDialog extends JDialog {
        private final Map<Point, FunctionEvaluationData> evaluationHistory = new LinkedHashMap<Point, FunctionEvaluationData>();
        private final List<Point> optimizationPath = new LinkedList<Point>();
        
-
+       
        private boolean updating = false;
        
        
@@ -213,7 +213,7 @@ public class GeneralOptimizationDialog extends JDialog {
                
                JPanel panel = new JPanel(new MigLayout("fill"));
                
-
+               
                ChangeListener clearHistoryChangeListener = new ChangeListener() {
                        @Override
                        public void stateChanged(ChangeEvent e) {
@@ -227,8 +227,8 @@ public class GeneralOptimizationDialog extends JDialog {
                        }
                };
                
-
-
+               
+               
                //// Selected modifiers table
                
                selectedModifierTableModel = new ParameterSelectionTableModel();
@@ -275,8 +275,8 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(selectedModifierDescription);
                panel.add(selectedModifierDescription, "growx");
                
-
-
+               
+               
                //// Add/remove buttons
                sub = new JPanel(new MigLayout("fill"));
                
@@ -331,8 +331,8 @@ public class GeneralOptimizationDialog extends JDialog {
                
                panel.add(sub);
                
-
-
+               
+               
                //// Available modifier tree
                availableModifierTree = new SimulationModifierTree(documentCopy.getRocket(), simulationModifiers, selectedModifiers);
                availableModifierTree.getSelectionModel().addTreeSelectionListener(new TreeSelectionListener() {
@@ -365,9 +365,9 @@ public class GeneralOptimizationDialog extends JDialog {
                panel.add(label, "split 2, flowy");
                panel.add(scroll, "width 300lp, height 200lp, grow, wrap para*2");
                
-
-
-
+               
+               
+               
                ////  Optimization options sub-panel
                
                sub = new JPanel(new MigLayout("fill"));
@@ -376,7 +376,7 @@ public class GeneralOptimizationDialog extends JDialog {
                sub.setBorder(border);
                disableComponents.add(sub);
                
-
+               
                //// Simulation to optimize
                
                label = new JLabel(trans.get("lbl.optimizeSim"));
@@ -392,8 +392,8 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(simulationSelectionCombo);
                sub.add(simulationSelectionCombo, "growx, wrap unrel");
                
-
-
+               
+               
                //// Value to optimize
                label = new JLabel(trans.get("lbl.optimizeValue"));
                tip = trans.get("lbl.optimizeValue.ttip");
@@ -408,8 +408,8 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(optimizationParameterCombo);
                sub.add(optimizationParameterCombo, "growx, wrap unrel");
                
-
-
+               
+               
                //// Optimization goal
                label = new JLabel(trans.get("lbl.optimizeGoal"));
                tip = trans.get("lbl.optimizeGoal");
@@ -424,7 +424,7 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(optimizationGoalCombo);
                sub.add(optimizationGoalCombo, "growx");
                
-
+               
                //// Optimization custom value
                optimizationSeekValue = new DoubleModel(0, UnitGroup.UNITS_NONE);
                optimizationSeekValue.addChangeListener(clearHistoryChangeListener);
@@ -441,11 +441,11 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(optimizationGoalUnitSelector);
                sub.add(optimizationGoalUnitSelector, "width 20lp, wrap unrel");
                
-
+               
                panel.add(sub, "grow");
                
-
-
+               
+               
                ////  Required stability sub-panel
                
                sub = new JPanel(new MigLayout("fill"));
@@ -454,15 +454,15 @@ public class GeneralOptimizationDialog extends JDialog {
                sub.setBorder(border);
                disableComponents.add(sub);
                
-
-
+               
+               
                double ref = CaliberUnit.calculateCaliber(baseDocument.getRocket());
                minimumStability = new DoubleModel(ref, UnitGroup.stabilityUnits(ref));
                maximumStability = new DoubleModel(5 * ref, UnitGroup.stabilityUnits(ref));
                minimumStability.addChangeListener(clearHistoryChangeListener);
                maximumStability.addChangeListener(clearHistoryChangeListener);
                
-
+               
                //// Minimum stability
                tip = trans.get("lbl.requireMinStability.ttip");
                minimumStabilitySelected = new JCheckBox(trans.get("lbl.requireMinStability"));
@@ -488,7 +488,7 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(minimumStabilityUnitSelector);
                sub.add(minimumStabilityUnitSelector, "growx, wrap unrel");
                
-
+               
                //// Maximum stability
                tip = trans.get("lbl.requireMaxStability.ttip");
                maximumStabilitySelected = new JCheckBox(trans.get("lbl.requireMaxStability"));
@@ -513,20 +513,20 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(maximumStabilityUnitSelector);
                sub.add(maximumStabilityUnitSelector, "growx, wrap para");
                
-
-
+               
+               
                //              DescriptionArea desc = new DescriptionArea("Stability requirements are verified during each time step of the simulation.",
                //                              2, -2, false);
                //              desc.setViewportBorder(null);
                //              disableComponents.add(desc);
                //              sub.add(desc, "span, growx");
                
-
+               
                panel.add(sub, "span 2, grow, wrap para*2");
                
-
-
-
+               
+               
+               
                ////  Rocket figure
                figure = new RocketFigure(getSelectedSimulation().getConfiguration());
                figure.setBorderPixels(1, 1);
@@ -534,10 +534,10 @@ public class GeneralOptimizationDialog extends JDialog {
                figureScrollPane.setFitting(true);
                panel.add(figureScrollPane, "span, split, height 200lp, grow");
                
-
+               
                sub = new JPanel(new MigLayout("fill"));
                
-
+               
                label = new JLabel(trans.get("status.bestValue"));
                tip = trans.get("status.bestValue.ttip");
                label.setToolTipText(tip);
@@ -547,7 +547,7 @@ public class GeneralOptimizationDialog extends JDialog {
                bestValueLabel.setToolTipText(tip);
                sub.add(bestValueLabel, "wmin 60lp, wrap rel");
                
-
+               
                label = new JLabel(trans.get("status.stepCount"));
                tip = trans.get("status.stepCount.ttip");
                label.setToolTipText(tip);
@@ -557,7 +557,7 @@ public class GeneralOptimizationDialog extends JDialog {
                stepCountLabel.setToolTipText(tip);
                sub.add(stepCountLabel, "wrap rel");
                
-
+               
                label = new JLabel(trans.get("status.evalCount"));
                tip = trans.get("status.evalCount.ttip");
                label.setToolTipText(tip);
@@ -567,7 +567,7 @@ public class GeneralOptimizationDialog extends JDialog {
                evaluationCountLabel.setToolTipText(tip);
                sub.add(evaluationCountLabel, "wrap rel");
                
-
+               
                label = new JLabel(trans.get("status.stepSize"));
                tip = trans.get("status.stepSize.ttip");
                label.setToolTipText(tip);
@@ -577,7 +577,7 @@ public class GeneralOptimizationDialog extends JDialog {
                stepSizeLabel.setToolTipText(tip);
                sub.add(stepSizeLabel, "wrap para");
                
-
+               
                //// Start/Stop button
                
                startButton = new JToggleButton(START_TEXT);
@@ -599,7 +599,7 @@ public class GeneralOptimizationDialog extends JDialog {
                });
                sub.add(startButton, "span, growx, wrap para*2");
                
-
+               
                plotButton = new JButton(trans.get("btn.plotPath"));
                plotButton.setToolTipText(trans.get("btn.plotPath.ttip"));
                plotButton.addActionListener(new ActionListener() {
@@ -619,7 +619,7 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(plotButton);
                sub.add(plotButton, "span, growx, wrap");
                
-
+               
                saveButton = new JButton(trans.get("btn.save"));
                saveButton.setToolTipText(trans.get("btn.save.ttip"));
                saveButton.addActionListener(new ActionListener() {
@@ -632,13 +632,13 @@ public class GeneralOptimizationDialog extends JDialog {
                disableComponents.add(saveButton);
                sub.add(saveButton, "span, growx");
                
-
-
+               
+               
                panel.add(sub, "wrap para*2");
                
-
-
-
+               
+               
+               
                ////  Bottom buttons
                
                applyButton = new JButton(trans.get("btn.apply"));
@@ -677,7 +677,7 @@ public class GeneralOptimizationDialog extends JDialog {
                });
                panel.add(closeButton, "right");
                
-
+               
                this.add(panel);
                clearHistory();
                updateComponents();
@@ -691,7 +691,7 @@ public class GeneralOptimizationDialog extends JDialog {
                        return;
                }
                
-
+               
                if (selectedModifiers.isEmpty()) {
                        JOptionPane.showMessageDialog(this, trans.get("error.selectParams.text"),
                                        trans.get("error.selectParams.title"), JOptionPane.ERROR_MESSAGE);
@@ -702,7 +702,7 @@ public class GeneralOptimizationDialog extends JDialog {
                        return;
                }
                
-
+               
                running = true;
                
                // Update the button status
@@ -711,7 +711,7 @@ public class GeneralOptimizationDialog extends JDialog {
                startButton.setText(STOP_TEXT);
                updating = false;
                
-
+               
                // Create a copy of the simulation (we're going to modify the original in the current thread)
                Simulation simulation = getSelectedSimulation();
                Rocket rocketCopy = simulation.getRocket().copyWithOriginalID();
@@ -740,7 +740,7 @@ public class GeneralOptimizationDialog extends JDialog {
                         * Make minAbsolute/maxAbsolute consistent with each other to produce reasonable
                         * result in plot tool tips.  Yes, this is a bit ugly.
                         */
-
+                       
                        // Min stability
                        Unit unit = minimumStability.getCurrentUnit();
                        if (unit instanceof CaliberUnit) {
@@ -761,7 +761,7 @@ public class GeneralOptimizationDialog extends JDialog {
                                maxAbsolute = true;
                        }
                        
-
+                       
                        if (!minimumStabilitySelected.isSelected()) {
                                min = Double.NaN;
                                minAbsolute = maxAbsolute;
@@ -789,7 +789,7 @@ public class GeneralOptimizationDialog extends JDialog {
                                                        new Object[] {
                                                                        trans.get("error.optimizationFailure.text"),
                                                                        exception.getLocalizedMessage()
-                                       }, trans.get("error.optimizationFailure.title"), JOptionPane.ERROR_MESSAGE);
+                                                       }, trans.get("error.optimizationFailure.title"), JOptionPane.ERROR_MESSAGE);
                                }
                                
                                worker = null;
@@ -862,7 +862,7 @@ public class GeneralOptimizationDialog extends JDialog {
                };
                worker.start();
                
-
+               
                clearHistory();
                
                updateComponents();
@@ -889,13 +889,13 @@ public class GeneralOptimizationDialog extends JDialog {
                startButton.setText(START_TEXT);
                updating = false;
                
-
+               
                updateComponents();
        }
        
        
-
-
+       
+       
        /**
         * Reset the current optimization history and values.  This does not reset the design.
         */
@@ -969,7 +969,7 @@ public class GeneralOptimizationDialog extends JDialog {
                availableModifierTree.populateTree(documentCopy.getRocket(), simulationModifiers);
                availableModifierTree.expandComponents();
                
-
+               
                // Update selectable simulations
                populateSimulations();
                
@@ -986,7 +986,7 @@ public class GeneralOptimizationDialog extends JDialog {
                        current = selection.toString();
                }
                
-
+               
                List<Named<Simulation>> simulations = new ArrayList<Named<Simulation>>();
                Rocket rocket = documentCopy.getRocket();
                
@@ -1006,15 +1006,15 @@ public class GeneralOptimizationDialog extends JDialog {
                        simulations.add(new Named<Simulation>(sim, name));
                }
                
-
+               
                Simulation sim = new Simulation(rocket);
                sim.getConfiguration().setMotorConfigurationID(null);
                String name = createSimulationName(trans.get("noSimulationName"), rocket.getMotorConfigurationNameOrDescription(null));
                simulations.add(new Named<Simulation>(sim, name));
                
-
-               simulationSelectionCombo.setModel(new DefaultComboBoxModel(simulations.toArray()));
                
+               simulationSelectionCombo.setModel(new DefaultComboBoxModel(simulations.toArray()));
+               simulationSelectionCombo.setSelectedIndex(0);
                if (current != null) {
                        for (int i = 0; i < simulations.size(); i++) {
                                if (simulations.get(i).toString().equals(current)) {
@@ -1102,7 +1102,7 @@ public class GeneralOptimizationDialog extends JDialog {
        }
        
        
-
+       
        private void addModifier(SimulationModifier mod) {
                if (!selectedModifiers.contains(mod)) {
                        log.user(1, "Adding simulation modifier " + mod);
@@ -1124,7 +1124,7 @@ public class GeneralOptimizationDialog extends JDialog {
        }
        
        
-
+       
        /**
         * Update the enabled status of all components in the dialog.
         */
@@ -1140,7 +1140,7 @@ public class GeneralOptimizationDialog extends JDialog {
                
                updating = true;
                
-
+               
                // First enable all components if optimization not running
                if (!running) {
                        log.debug("Initially enabling all components");
@@ -1149,7 +1149,7 @@ public class GeneralOptimizationDialog extends JDialog {
                        }
                }
                
-
+               
                // "Add" button
                SimulationModifier mod = getSelectedAvailableModifier();
                state = (mod != null && !selectedModifiers.contains(mod));
@@ -1166,7 +1166,7 @@ public class GeneralOptimizationDialog extends JDialog {
                log.debug("removeAllButton enabled: " + state);
                removeAllButton.setEnabled(state);
                
-
+               
                // Optimization goal
                String selected = (String) optimizationGoalCombo.getSelectedItem();
                state = GOAL_SEEK.equals(selected);
@@ -1174,7 +1174,7 @@ public class GeneralOptimizationDialog extends JDialog {
                optimizationGoalSpinner.setVisible(state);
                optimizationGoalUnitSelector.setVisible(state);
                
-
+               
                // Minimum/maximum stability options
                state = minimumStabilitySelected.isSelected();
                log.debug("minimumStabilitySpinner & UnitSelector enabled: " + state);
@@ -1186,7 +1186,7 @@ public class GeneralOptimizationDialog extends JDialog {
                maximumStabilitySpinner.setEnabled(state);
                maximumStabilityUnitSelector.setEnabled(state);
                
-
+               
                // Plot button (enabled if path exists and dimensionality is 1 or 2)
                state = (!optimizationPath.isEmpty() && (selectedModifiers.size() == 1 || selectedModifiers.size() == 2));
                log.debug("plotButton enabled: " + state + " optimizationPath.isEmpty=" + optimizationPath.isEmpty() +
@@ -1198,7 +1198,7 @@ public class GeneralOptimizationDialog extends JDialog {
                log.debug("saveButton enabled: " + state);
                saveButton.setEnabled(state);
                
-
+               
                // Last disable all components if optimization is running
                if (running) {
                        log.debug("Disabling all components because optimization is running");
@@ -1207,7 +1207,7 @@ public class GeneralOptimizationDialog extends JDialog {
                        }
                }
                
-
+               
                // Update description text
                mod = getSelectedModifier();
                if (mod != null) {
@@ -1216,7 +1216,7 @@ public class GeneralOptimizationDialog extends JDialog {
                        selectedModifierDescription.setText("");
                }
                
-
+               
                // Update the figure
                figure.setConfiguration(getSelectedSimulation().getConfiguration());
                
@@ -1233,7 +1233,7 @@ public class GeneralOptimizationDialog extends JDialog {
                CsvOptionPanel csvOptions = new CsvOptionPanel(GeneralOptimizationDialog.class,
                                trans.get("export.header"), trans.get("export.header.ttip"));
                
-
+               
                JFileChooser chooser = new JFileChooser();
                chooser.setFileFilter(FileHelper.CSV_FILE_FILTER);
                chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
@@ -1282,7 +1282,7 @@ public class GeneralOptimizationDialog extends JDialog {
                                writer.write("\n");
                        }
                        
-
+                       
                        for (FunctionEvaluationData data : evaluationHistory.values()) {
                                Value[] state = data.getState();
                                
@@ -1334,7 +1334,17 @@ public class GeneralOptimizationDialog extends JDialog {
         */
        @SuppressWarnings("unchecked")
        private Simulation getSelectedSimulation() {
-               return ((Named<Simulation>) simulationSelectionCombo.getSelectedItem()).get();
+               /* This is to debug a NPE where the returned selected item is null. */
+               Object item = simulationSelectionCombo.getSelectedItem();
+               if (item == null) {
+                       String s = "Selected simulation is null:";
+                       s = s + " item count=" + simulationSelectionCombo.getItemCount();
+                       for (int i = 0; i < simulationSelectionCombo.getItemCount(); i++) {
+                               s = s + " [" + i + "]=" + simulationSelectionCombo.getItemAt(i);
+                       }
+                       throw new BugException(s);
+               }
+               return ((Named<Simulation>) item).get();
        }
        
        
@@ -1580,6 +1590,6 @@ public class GeneralOptimizationDialog extends JDialog {
                }
        }
        
-
-
+       
+       
 }
index 1e7e47f0318fecf0c52cb52cd2cdf9fbf133552c..663c79b8333157d29223b8511a41b7de936effcb 100644 (file)
@@ -16,9 +16,11 @@ import javax.swing.tree.TreePath;
 
 import net.sf.openrocket.gui.components.BasicTree;
 import net.sf.openrocket.gui.main.ComponentIcons;
+import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.TextUtil;
 
 /**
@@ -32,6 +34,7 @@ import net.sf.openrocket.util.TextUtil;
 public class SimulationModifierTree extends BasicTree {
        
        private final List<SimulationModifier> selectedModifiers;
+       private static final Translator trans = Application.getTranslator();
        
        /**
         * Sole constructor.
@@ -76,7 +79,7 @@ public class SimulationModifierTree extends BasicTree {
                        DefaultMutableTreeNode modifierNode;
                        
                        if (component.getChildCount() > 0) {
-                               modifierNode = new DefaultMutableTreeNode("Optimization parameters");
+                               modifierNode = new DefaultMutableTreeNode(trans.get("SimulationModifierTree.OptimizationParameters"));
                                node.add(modifierNode);
                        } else {
                                modifierNode = node;
index 986c4a40e42e7253d971ca05e73658e6bee636a8..a3d963ee9a864a5f57075216ad0a627fb7ca6688 100644 (file)
@@ -388,7 +388,6 @@ public class PreferencesDialog extends JDialog {
                combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_TEMPERATURE));
                panel.add(combo, "sizegroup boxes, wrap");
                
-
                //// Moment of inertia:
                panel.add(new JLabel(trans.get("pref.dlg.lbl.Momentofinertia")));
                combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_INERTIA));
@@ -403,10 +402,16 @@ public class PreferencesDialog extends JDialog {
                //// Stability:
                panel.add(new JLabel(trans.get("pref.dlg.lbl.Stability")));
                combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_STABILITY));
+               panel.add(combo, "sizegroup boxes");
+               
+               //// Windspeed:
+               panel.add(new JLabel(trans.get("pref.dlg.lbl.Windspeed")));
+               combo = new JComboBox(new DefaultUnitSelector(UnitGroup.UNITS_WINDSPEED));
                panel.add(combo, "sizegroup boxes, wrap para");
                
 
 
+
                //// Default metric button
                JButton button = new JButton(trans.get("pref.dlg.but.defaultmetric"));
                button.addActionListener(new ActionListener() {
diff --git a/core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetChooserDialog.java b/core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetChooserDialog.java
new file mode 100644 (file)
index 0000000..9efa367
--- /dev/null
@@ -0,0 +1,298 @@
+package net.sf.openrocket.gui.dialogs.preset;
+
+
+import java.awt.Dialog;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.RowFilter;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.util.GUIUtil;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.SymmetricComponent;
+import net.sf.openrocket.startup.Application;
+
+/**
+ * Dialog shown for selecting a preset component.
+ */
+public class ComponentPresetChooserDialog extends JDialog {
+       
+       private static final Translator trans = Application.getTranslator();
+       
+       private final RocketComponent component;
+       
+       private ComponentPresetTable componentSelectionTable;
+       private JTextField filterText;
+       private JCheckBox foreDiameterFilterCheckBox;
+       private JCheckBox aftDiameterFilterCheckBox;
+       
+       private ComponentPresetRowFilter foreDiameterFilter;
+       private ComponentPresetRowFilter aftDiameterFilter;
+       
+       
+       /*
+        * outerDiamtereColumnIndex is the index of the column associated with the OUTER_DIAMETER
+        * field.  This index is needed by the matchOuterDiameterCheckBox to implement filtering.
+        */
+       int aftDiameterColumnIndex = -1;
+       int foreDiameterColumnIndex = -1;
+       
+       private List<ComponentPreset> presets;
+       private ComponentPreset.Type presetType;
+       
+       private boolean okClicked = false;
+       
+       
+       public ComponentPresetChooserDialog(Window owner, RocketComponent component) {
+               super(owner, trans.get("title"), Dialog.ModalityType.APPLICATION_MODAL);
+               this.component = component;
+               this.presetType = component.getPresetType();
+               this.presets = Application.getComponentPresetDao().listForType(component.getPresetType());
+               
+               List<TypedKey<?>> displayedColumnKeys = Arrays.asList(component.getPresetType().getDisplayedColumns());
+               
+               {
+                       final List<TypedKey<?>> columnKeys = ComponentPreset.ORDERED_KEY_LIST;
+                       int i = 0; // We start at 0 but use preincrement because the first column is favorite.
+                       for (final TypedKey<?> key : columnKeys) {
+                               // Note the increment early in the loop.  This really means that initial loop i=1
+                               // we do it here so the continue below doesn't mess up the counting.
+                               i++;
+                               // Don't allow the matching filters if the column is not part of the default set for
+                               // this kind of preset.
+                               if (!displayedColumnKeys.contains(key)) {
+                                       continue;
+                               }
+                               if (key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.AFT_OUTER_DIAMETER) {
+                                       aftDiameterColumnIndex = i;
+                               }
+                               if (key == ComponentPreset.OUTER_DIAMETER || key == ComponentPreset.FORE_OUTER_DIAMETER) {
+                                       foreDiameterColumnIndex = i;
+                               }
+                       }
+               }
+               
+               
+               JPanel panel = new JPanel(new MigLayout("fill, ins para"));
+               
+               /*
+                * Add filter by text.
+                */
+               JPanel sub = new JPanel(new MigLayout("fill, ins 0"));
+               JLabel filterLabel = new JLabel(trans.get("ComponentPresetChooserDialog.filter.label"));
+               sub.add(filterLabel, "gapright para");
+               
+               filterText = new JTextField();
+               sub.add(filterText, "growx");
+               filterText.getDocument().addDocumentListener(new DocumentListener() {
+                       @Override
+                       public void changedUpdate(DocumentEvent e) {
+                               updateFilters();
+                       }
+                       
+                       @Override
+                       public void insertUpdate(DocumentEvent e) {
+                               updateFilters();
+                       }
+                       
+                       @Override
+                       public void removeUpdate(DocumentEvent e) {
+                               updateFilters();
+                       }
+               });
+               
+               panel.add(sub, "growx, ay 0, gapright para");
+               
+               
+               panel.add(getFilterCheckboxes(), "wrap para");
+               
+               componentSelectionTable = new ComponentPresetTable(presetType, presets, displayedColumnKeys);
+               //              GUIUtil.setAutomaticColumnTableWidths(componentSelectionTable, 20);
+               int w = componentSelectionTable.getRowHeight() + 4;
+               TableColumn tc = componentSelectionTable.getColumnModel().getColumn(0);
+               tc.setPreferredWidth(w);
+               tc.setMaxWidth(w);
+               tc.setMinWidth(w);
+               
+               JScrollPane scrollpane = new JScrollPane();
+               scrollpane.setViewportView(componentSelectionTable);
+               panel.add(scrollpane, "grow, width 700lp, height 300lp, spanx, wrap para");
+               
+               
+               // OK / Cancel buttons
+               JButton okButton = new JButton(trans.get("dlg.but.ok"));
+               okButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               close(true);
+                       }
+               });
+               panel.add(okButton, "tag ok, spanx, split");
+               
+               //// Cancel button
+               JButton cancelButton = new JButton(trans.get("dlg.but.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               close(false);
+                       }
+               });
+               panel.add(cancelButton, "tag cancel");
+               
+               this.add(panel);
+               
+               GUIUtil.rememberWindowSize(this);
+               GUIUtil.setDisposableDialogOptions(this, okButton);
+       }
+       
+       
+       private JPanel getFilterCheckboxes() {
+               SymmetricComponent sc;
+               
+               JPanel panel = new JPanel(new MigLayout("fill, ins 0"));
+               
+               /*
+                * Add show all compatible check box.
+                */
+               final List<ComponentPreset.Type> compatibleTypes = component.getPresetType().getCompatibleTypes();
+               final ComponentPreset.Type nativeType = component.getPresetType();
+               if (compatibleTypes != null && compatibleTypes.size() > 0) {
+                       JCheckBox showAll = new JCheckBox();
+                       showAll.setText(trans.get("ComponentPresetChooserDialog.checkbox.showAllCompatible"));
+                       panel.add(showAll, "wrap");
+                       showAll.addItemListener(new ItemListener() {
+                               @Override
+                               public void itemStateChanged(ItemEvent e) {
+                                       if (((JCheckBox) e.getItem()).isSelected()) {
+                                               presets = Application.getComponentPresetDao().listForTypes(compatibleTypes);
+                                       } else {
+                                               presets = Application.getComponentPresetDao().listForType(nativeType);
+                                       }
+                                       componentSelectionTable.updateData(presets);
+                               }
+                       });
+               }
+               
+               /*
+                * Add filter by fore diameter
+                */
+               foreDiameterFilterCheckBox = new JCheckBox(trans.get("ComponentPresetChooserDialog.checkbox.filterForeDiameter"));
+               sc = getPreviousSymmetricComponent();
+               if (sc != null && foreDiameterColumnIndex >= 0) {
+                       foreDiameterFilter = new ComponentPresetRowFilter(sc.getAftRadius() * 2.0, foreDiameterColumnIndex);
+                       panel.add(foreDiameterFilterCheckBox, "wrap");
+                       foreDiameterFilterCheckBox.addItemListener(new ItemListener() {
+                               @Override
+                               public void itemStateChanged(ItemEvent e) {
+                                       updateFilters();
+                               }
+                       });
+               }
+               
+               /*
+                * Add filter by aft diameter
+                */
+               aftDiameterFilterCheckBox = new JCheckBox(trans.get("ComponentPresetChooserDialog.checkbox.filterAftDiameter"));
+               sc = getNextSymmetricComponent();
+               if (sc != null && aftDiameterColumnIndex >= 0) {
+                       aftDiameterFilter = new ComponentPresetRowFilter(sc.getForeRadius() * 2.0, aftDiameterColumnIndex);
+                       panel.add(aftDiameterFilterCheckBox, "wrap");
+                       aftDiameterFilterCheckBox.addItemListener(new ItemListener() {
+                               @Override
+                               public void itemStateChanged(ItemEvent e) {
+                                       updateFilters();
+                               }
+                       });
+               }
+               
+               return panel;
+       }
+       
+       /**
+        * Return the motor selected by this chooser dialog, or <code>null</code> if the selection has been aborted.
+        * 
+        * @return      the selected motor, or <code>null</code> if no motor has been selected or the selection was canceled.
+        */
+       public ComponentPreset getSelectedComponentPreset() {
+               if (!okClicked)
+                       return null;
+               int row = componentSelectionTable.getSelectedRow();
+               if ( row < 0 ) {
+                       // Nothing selected.
+                       return null;
+               }
+               row = componentSelectionTable.convertRowIndexToModel(row);
+               return presets.get(row);
+       }
+       
+       public void close(boolean ok) {
+               okClicked = ok;
+               this.setVisible(false);
+       }
+       
+       private void updateFilters() {
+               List<RowFilter<TableModel, Object>> filters = new ArrayList<RowFilter<TableModel, Object>>(2);
+               String filterTextRegex = filterText.getText();
+               if (filterTextRegex != null) {
+                       try {
+                               // The "(?iu)" magic turns on case insensitivity with unicode chars
+                               RowFilter<TableModel, Object> regexFilter = RowFilter.regexFilter("(?iu)" + filterTextRegex);
+                               filters.add(regexFilter);
+                       } catch (java.util.regex.PatternSyntaxException e) {
+                       }
+               }
+               if (aftDiameterFilterCheckBox.isSelected()) {
+                       filters.add(aftDiameterFilter);
+               }
+               if (foreDiameterFilterCheckBox.isSelected()) {
+                       filters.add(foreDiameterFilter);
+               }
+               
+               componentSelectionTable.setRowFilter(RowFilter.andFilter(filters));
+       }
+       
+       
+       private SymmetricComponent getPreviousSymmetricComponent() {
+               RocketComponent c = component;
+               while (c != null) {
+                       c = c.getPreviousComponent();
+                       if (c instanceof SymmetricComponent) {
+                               return (SymmetricComponent) c;
+                       }
+               }
+               return null;
+       }
+       
+       
+       private SymmetricComponent getNextSymmetricComponent() {
+               RocketComponent c = component;
+               while (c != null) {
+                       c = c.getNextComponent();
+                       if (c instanceof SymmetricComponent) {
+                               return (SymmetricComponent) c;
+                       }
+               }
+               return null;
+       }
+}
diff --git a/core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetRowFilter.java b/core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetRowFilter.java
new file mode 100644 (file)
index 0000000..7c66aa1
--- /dev/null
@@ -0,0 +1,38 @@
+package net.sf.openrocket.gui.dialogs.preset;
+
+import javax.swing.RowFilter;
+import javax.swing.table.TableModel;
+
+import net.sf.openrocket.unit.Value;
+import net.sf.openrocket.util.MathUtil;
+
+public class ComponentPresetRowFilter extends RowFilter<TableModel, Object> {
+       
+       private final double value;
+       private final int column;
+       private final double epsilon;
+       
+       ComponentPresetRowFilter(double value, int column) {
+               this.value = value;
+               this.column = column;
+               /*
+                * Accept 5% difference, but at least 1mm.
+                */
+               this.epsilon = MathUtil.max(value * 0.05, 0.001);
+       }
+       
+       @Override
+       public boolean include(RowFilter.Entry<? extends TableModel, ? extends Object> entry) {
+               Object o = entry.getValue(column);
+               if (o instanceof Value) {
+                       Value v = (Value) o;
+                       return Math.abs(value - v.getValue()) < epsilon;
+               }
+               if (o instanceof Double) {
+                       Double d = (Double) o;
+                       return Math.abs(value - d) < epsilon;
+               }
+               return true;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetTable.java b/core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetTable.java
new file mode 100644 (file)
index 0000000..cad447f
--- /dev/null
@@ -0,0 +1,283 @@
+package net.sf.openrocket.gui.dialogs.preset;
+
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JMenu;
+import javax.swing.JPopupMenu;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.RowFilter;
+import javax.swing.RowSorter.SortKey;
+import javax.swing.SortOrder;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableColumn;
+import javax.swing.table.TableModel;
+import javax.swing.table.TableRowSorter;
+
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.unit.Value;
+import net.sf.openrocket.util.AlphanumComparator;
+
+public class ComponentPresetTable extends JTable {
+
+       private static final Translator trans = Application.getTranslator();
+
+       private final TableRowSorter<TableModel> sorter;
+       private List<ComponentPreset> presets;
+       private final ComponentPreset.Type presetType;
+       private Set<String> favorites;
+       private final AbstractTableModel tableModel;
+       private final XTableColumnModel tableColumnModel;
+       private final ComponentPresetTableColumn[] columns;
+
+       public ComponentPresetTable(final ComponentPreset.Type presetType, List<ComponentPreset> presets, List<TypedKey<?>> visibleColumnKeys) {
+               super();
+               this.presets = presets;
+               this.presetType = presetType;
+               this.favorites = Application.getPreferences().getComponentFavorites(presetType);
+               this.columns = new ComponentPresetTableColumn[ComponentPreset.ORDERED_KEY_LIST.size()+1];
+
+
+               tableModel = new AbstractTableModel() {
+                       final ComponentPresetTableColumn[] myColumns = columns;
+                       @Override
+                       public int getRowCount() {
+                               return ComponentPresetTable.this.presets.size();
+                       }
+
+                       @Override
+                       public int getColumnCount() {
+                               return myColumns.length;
+                       }
+
+                       @Override
+                       public Object getValueAt(int rowIndex, int columnIndex) {
+                               return myColumns[columnIndex].getValueFromPreset(favorites,ComponentPresetTable.this.presets.get(rowIndex));
+                       }
+
+                       @Override
+                       public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
+                               // Only support favorite
+                               if ( columnIndex != 0 ) {
+                                       return;
+                               }
+                               ComponentPreset preset = ComponentPresetTable.this.presets.get(rowIndex);
+                               Application.getComponentPresetDao().setFavorite(preset, presetType, (Boolean) aValue);
+                               ComponentPresetTable.this.updateFavorites();
+                       }
+
+                       @Override
+                       public boolean isCellEditable(int rowIndex, int columnIndex) {
+                               return columnIndex == 0;
+                       }
+
+                       @Override
+                       public Class<?> getColumnClass(int columnIndex) {
+                               return columnIndex == 0 ? Boolean.class : Object.class;
+                       }
+
+               };
+
+
+               sorter = new TableRowSorter<TableModel>(tableModel);
+
+               tableColumnModel = new XTableColumnModel();
+
+               /*
+                * Set up the Column Table model, and customize the sorting.
+                */
+               columns[0] = new ComponentPresetTableColumn.Favorite(0);
+               tableColumnModel.addColumn(columns[0]);
+
+               List<TableColumn> hiddenColumns = new ArrayList<TableColumn>();
+               {
+                       int index = 1;
+                       for (final TypedKey<?> key: ComponentPreset.ORDERED_KEY_LIST ) {
+                               if ( key.getType() == Double.class && key.getUnitGroup() != null ) {
+                                       columns[index] = new ComponentPresetTableColumn.DoubleWithUnit((TypedKey<Double>)key,index);
+                               } else {
+                                       columns[index] = new ComponentPresetTableColumn.Parameter(key,index);
+                               }
+                               tableColumnModel.addColumn(columns[index]);
+                               if ( key == ComponentPreset.MANUFACTURER || key == ComponentPreset.PARTNO ) {
+                                       sorter.setComparator(index, new AlphanumComparator());
+                               } else if ( key.getType() == Double.class ) {
+                                       sorter.setComparator(index,  new Comparator<Value>() {
+
+                                               @Override
+                                               public int compare(Value o1, Value o2) {
+                                                       return Double.compare(o1.getValue(), o2.getValue());
+                                               }
+                                               
+                                       });
+                               }
+                               if ( visibleColumnKeys.indexOf(key) < 0 ) {
+                                       hiddenColumns.add(columns[index]);
+                               }
+                               index ++;
+                       }
+               }
+
+               this.setAutoCreateColumnsFromModel(false);
+               this.setColumnModel( tableColumnModel );
+               this.setModel(tableModel);
+               this.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+               this.setRowSorter(sorter);
+
+               for ( TableColumn hiddenColumn : hiddenColumns ) {
+                       tableColumnModel.setColumnVisible(hiddenColumn, false);
+               }
+
+               JTableHeader header = this.getTableHeader();
+               
+               header.setReorderingAllowed(true);
+
+               header.addMouseListener( new MouseAdapter() {
+
+                       @Override
+                       public void mousePressed(MouseEvent e) {
+                               if ( e.isPopupTrigger() ) {
+                                       doPopup(e);
+                               }
+                       }
+                       @Override
+                       public void mouseReleased(MouseEvent e) {
+                               if ( e.isPopupTrigger() ) {
+                                       doPopup(e);
+                               }
+                       }
+               });
+       }
+
+       public void setRowFilter( RowFilter<? super TableModel ,? super Integer> filter ) {
+               sorter.setRowFilter( filter );
+       }
+
+       public void updateData( List<ComponentPreset> presets ) {
+               this.presets = presets;
+               this.favorites = Application.getPreferences().getComponentFavorites(presetType);
+               this.tableModel.fireTableDataChanged();
+       }
+       
+       public void updateFavorites() {
+               this.favorites = Application.getPreferences().getComponentFavorites(presetType);
+               this.tableModel.fireTableDataChanged();
+       }
+
+       private void doPopup(MouseEvent evt ) {
+               
+               // Figure out what column header was clicked on.
+               int colIndex = tableColumnModel.getColumnIndexAtX( evt.getX() );
+               ComponentPresetTableColumn colClicked = null;
+               if ( colIndex >=0 ) {
+                       colClicked = (ComponentPresetTableColumn) tableColumnModel.getColumn(colIndex);
+               }
+               
+               JPopupMenu columnMenu = new ColumnPopupMenu(colClicked, colIndex);
+               columnMenu.show(evt.getComponent(),evt.getX(),evt.getY());
+       }
+
+       private class ColumnPopupMenu extends JPopupMenu {
+
+               ColumnPopupMenu(ComponentPresetTableColumn colClicked, int colClickedIndex) {
+                       if ( colClickedIndex >= 0 ) {
+                               JCheckBoxMenuItem item = new SortAscColumnMenuItem(colClickedIndex);
+                               this.add(item);
+                               item = new SortDescColumnMenuItem(colClickedIndex);
+                               this.add(item);
+                               this.addSeparator();
+                               if ( colClicked instanceof ComponentPresetTableColumn.DoubleWithUnit ) {
+                                       this.add( new UnitSelectorMenuItem( (ComponentPresetTableColumn.DoubleWithUnit) colClicked ));
+                                       this.addSeparator();
+                               }
+                       }
+                       for( TableColumn c: columns ) {
+                               JCheckBoxMenuItem item = new ToggleColumnMenuItem(c);
+                               this.add(item);
+                       }
+               }
+
+
+               private class SortAscColumnMenuItem extends JCheckBoxMenuItem implements ItemListener {
+                       private int columnClicked;
+                       SortAscColumnMenuItem(int columnClicked) {
+                               super( trans.get("ComponentPresetChooserDialog.menu.sortAsc") );
+                               this.addItemListener(this);
+                               this.columnClicked = columnClicked;
+                       }
+                       @Override
+                       public void itemStateChanged(ItemEvent e) {
+                               sorter.setSortKeys( Collections.singletonList( new SortKey(columnClicked, SortOrder.ASCENDING)));
+                       }
+               }
+               
+               private class SortDescColumnMenuItem extends JCheckBoxMenuItem implements ItemListener {
+                       private int columnClicked;
+                       SortDescColumnMenuItem(int columnClicked) {
+                               super( trans.get("ComponentPresetChooserDialog.menu.sortDesc") );
+                               this.addItemListener(this);
+                               this.columnClicked = columnClicked;
+                       }
+                       @Override
+                       public void itemStateChanged(ItemEvent e) {
+                               sorter.setSortKeys( Collections.singletonList( new SortKey(columnClicked, SortOrder.DESCENDING)));
+                       }
+               }
+               
+               private class ToggleColumnMenuItem extends JCheckBoxMenuItem implements ItemListener {
+                       TableColumn col;
+                       ToggleColumnMenuItem( TableColumn col ) {
+                               super( String.valueOf(col.getHeaderValue()), tableColumnModel.isColumnVisible(col));
+                               this.addItemListener(this);
+                               this.col = col;
+                       }
+                       @Override
+                       public void itemStateChanged(ItemEvent e) {
+                               tableColumnModel.setColumnVisible(col, !tableColumnModel.isColumnVisible(col));
+                       }
+               }
+               
+               private class UnitSelectorMenuItem extends JMenu implements ItemListener {
+                       ComponentPresetTableColumn.DoubleWithUnit col;
+                       UnitSelectorMenuItem( ComponentPresetTableColumn.DoubleWithUnit col ) {
+                               super(trans.get("ComponentPresetChooserDialog.menu.units"));
+                               this.col = col;
+                               UnitGroup group = col.unitGroup;
+                               Unit selectedUnit = col.selectedUnit;
+                               for( Unit u : group.getUnits() ) {
+                                       JCheckBoxMenuItem item = new JCheckBoxMenuItem( u.toString() );
+                                       if ( u == selectedUnit ) {
+                                               item.setSelected(true);
+                                       }
+                                       item.addItemListener(this);
+                                       this.add(item);
+                               }
+                               
+                       }
+                       @Override
+                       public void itemStateChanged(ItemEvent e) {
+                               JCheckBoxMenuItem item = (JCheckBoxMenuItem) e.getItem();
+                               String val = item.getText();
+                               col.selectedUnit = col.unitGroup.findApproximate(val);
+                               ComponentPresetTable.this.tableModel.fireTableDataChanged();
+                               return;
+                       }
+
+               }
+       }
+}
diff --git a/core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetTableColumn.java b/core/src/net/sf/openrocket/gui/dialogs/preset/ComponentPresetTableColumn.java
new file mode 100644 (file)
index 0000000..5d5d12d
--- /dev/null
@@ -0,0 +1,84 @@
+package net.sf.openrocket.gui.dialogs.preset;
+
+import java.util.Set;
+
+import javax.swing.table.TableColumn;
+
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.unit.Value;
+
+public abstract class ComponentPresetTableColumn extends TableColumn {
+
+       private static final Translator trans = Application.getTranslator();
+
+       protected ComponentPresetTableColumn( String header, int modelIndex ) {
+               this.setHeaderValue(header);
+               this.setModelIndex(modelIndex);
+       
+       }
+       
+       public abstract Object getValueFromPreset( Set<String> favorites, ComponentPreset preset );
+       
+       public static class Favorite extends ComponentPresetTableColumn {
+
+               public Favorite(int modelIndex) {
+                       super(trans.get("table.column.Favorite"), modelIndex);
+               }
+               
+               @Override
+               public Object getValueFromPreset( Set<String> favorites, ComponentPreset preset ) {
+                       return Boolean.valueOf(favorites.contains(preset.preferenceKey()));
+               }
+
+       }
+
+       public static class Parameter extends ComponentPresetTableColumn {
+
+               protected final TypedKey<?> key;
+               
+               public Parameter( TypedKey<?> key, int modelIndex ) {
+                       super( trans.get("table.column." + key.getName()), modelIndex );
+                       this.key = key;
+               }
+
+               @Override
+               public Object getValueFromPreset(Set<String> favorites, ComponentPreset preset) {
+                       return preset.has(key) ? preset.get(key) : null;
+               }
+               
+       }
+
+
+       public static class DoubleWithUnit extends Parameter {
+
+               UnitGroup unitGroup;
+               Unit selectedUnit;
+               
+               public DoubleWithUnit( TypedKey<Double> key, int modelIndex ) {
+                       super(key,modelIndex);
+                       this.unitGroup = key.getUnitGroup();
+                       this.selectedUnit = unitGroup.getDefaultUnit();
+               }
+
+               @Override
+               public Object getValueFromPreset(Set<String> favorites, ComponentPreset preset) {
+                       Double value = (Double) super.getValueFromPreset(favorites, preset);
+                       if ( value != null ) {
+                               return new Value((Double)super.getValueFromPreset(favorites, preset),selectedUnit);
+                       } else {
+                               return null;
+                       }
+               }
+               
+               
+       }
+
+}
+
+
+
diff --git a/core/src/net/sf/openrocket/gui/dialogs/preset/XTableColumnModel.java b/core/src/net/sf/openrocket/gui/dialogs/preset/XTableColumnModel.java
new file mode 100644 (file)
index 0000000..ac05c78
--- /dev/null
@@ -0,0 +1,242 @@
+package net.sf.openrocket.gui.dialogs.preset;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.table.TableColumn;
+
+public class XTableColumnModel extends DefaultTableColumnModel {
+       
+       /** Array of TableColumn objects in this model.
+        *  Holds all column objects, regardless of their visibility
+        */
+       protected Vector<TableColumn> allTableColumns = new Vector<TableColumn>();
+       
+       /**
+        * Creates an extended table column model.
+        */
+       XTableColumnModel() {
+               super();
+       }
+       
+       /**
+        * Sets the visibility of the specified TableColumn.
+        * The call is ignored if the TableColumn is not found in this column model
+        * or its visibility status did not change.
+        * <p>
+        *
+        * @param aColumn        the column to show/hide
+        * @param visible its new visibility status
+        */
+       // listeners will receive columnAdded()/columnRemoved() event
+       public void setColumnVisible(TableColumn column, boolean visible) {
+               if (!visible) {
+                       super.removeColumn(column);
+               }
+               else {
+                       // find the visible index of the column:
+                       // iterate through both collections of visible and all columns, counting
+                       // visible columns up to the one that's about to be shown again
+                       int noVisibleColumns = tableColumns.size();
+                       int noInvisibleColumns = allTableColumns.size();
+                       int visibleIndex = 0;
+                       
+                       for (int invisibleIndex = 0; invisibleIndex < noInvisibleColumns; ++invisibleIndex) {
+                               TableColumn visibleColumn = (visibleIndex < noVisibleColumns ? (TableColumn) tableColumns.get(visibleIndex) : null);
+                               TableColumn testColumn = allTableColumns.get(invisibleIndex);
+                               
+                               if (testColumn == column) {
+                                       if (visibleColumn != column) {
+                                               super.addColumn(column);
+                                               super.moveColumn(tableColumns.size() - 1, visibleIndex);
+                                       }
+                                       return; // ####################
+                               }
+                               if (testColumn == visibleColumn) {
+                                       ++visibleIndex;
+                               }
+                       }
+               }
+       }
+       
+       /**
+        * Makes all columns in this model visible
+        */
+       public void setAllColumnsVisible(boolean visible) {
+               int noColumns = allTableColumns.size();
+               
+               for (int columnIndex = 0; columnIndex < noColumns; ++columnIndex) {
+                       TableColumn visibleColumn = (columnIndex < tableColumns.size() ? (TableColumn) tableColumns.get(columnIndex) : null);
+                       TableColumn invisibleColumn = allTableColumns.get(columnIndex);
+                       if (visible) {
+                               
+                               if (visibleColumn != invisibleColumn) {
+                                       super.addColumn(invisibleColumn);
+                                       super.moveColumn(tableColumns.size() - 1, columnIndex);
+                               }
+                       } else {
+                               super.removeColumn(invisibleColumn);
+                       }
+               }
+       }
+       
+       /**
+        * Maps the index of the column in the table model at
+        * <code>modelColumnIndex</code> to the TableColumn object.
+        * There may me multiple TableColumn objects showing the same model column, though this is uncommon.
+        * This method will always return the first visible or else the first invisible column with the specified index.
+        * @param modelColumnIndex index of column in table model
+        * @return table column object or null if no such column in this column model
+        */
+       public TableColumn getColumnByModelIndex(int modelColumnIndex) {
+               for (int columnIndex = 0; columnIndex < allTableColumns.size(); ++columnIndex) {
+                       TableColumn column = allTableColumns.get(columnIndex);
+                       if (column.getModelIndex() == modelColumnIndex) {
+                               return column;
+                       }
+               }
+               return null;
+       }
+       
+       /** Checks wether the specified column is currently visible.
+        * @param aColumn column to check
+        * @return visibility of specified column (false if there is no such column at all. [It's not visible, right?])
+        */
+       public boolean isColumnVisible(TableColumn aColumn) {
+               return (tableColumns.indexOf(aColumn) >= 0);
+       }
+       
+       /** Append <code>column</code> to the right of exisiting columns.
+        * Posts <code>columnAdded</code> event.
+        * @param column The column to be added
+        * @see #removeColumn
+        * @exception IllegalArgumentException if <code>column</code> is <code>null</code>
+        */
+       @Override
+       public void addColumn(TableColumn column) {
+               allTableColumns.add(column);
+               super.addColumn(column);
+       }
+       
+       /** Removes <code>column</code> from this column model.
+        * Posts <code>columnRemoved</code> event.
+        * Will do nothing if the column is not in this model.
+        * @param column the column to be added
+        * @see #addColumn
+        */
+       @Override
+       public void removeColumn(TableColumn column) {
+               int allColumnsIndex = allTableColumns.indexOf(column);
+               if (allColumnsIndex != -1) {
+                       allTableColumns.remove(allColumnsIndex);
+               }
+               super.removeColumn(column);
+       }
+       
+       /** 
+        * Moves the column from <code>oldIndex</code> to <code>newIndex</code>.
+        * Posts  <code>columnMoved</code> event.
+        * Will not move any columns if <code>oldIndex</code> equals <code>newIndex</code>.
+        *
+        * @param       oldIndex                        index of column to be moved
+        * @param       newIndex                        new index of the column
+        * @exception IllegalArgumentException  if either <code>oldIndex</code> or
+        *                                              <code>newIndex</code>
+        *                                              are not in [0, getColumnCount() - 1]
+        */
+       @Override
+       public void moveColumn(int oldIndex, int newIndex) {
+               if ((oldIndex < 0) || (oldIndex >= getColumnCount()) ||
+                               (newIndex < 0) || (newIndex >= getColumnCount()))
+                       throw new IllegalArgumentException("moveColumn() - Index out of range");
+               
+               TableColumn fromColumn = tableColumns.get(oldIndex);
+               TableColumn toColumn = tableColumns.get(newIndex);
+               
+               int allColumnsOldIndex = allTableColumns.indexOf(fromColumn);
+               int allColumnsNewIndex = allTableColumns.indexOf(toColumn);
+               
+               if (oldIndex != newIndex) {
+                       allTableColumns.remove(allColumnsOldIndex);
+                       allTableColumns.add(allColumnsNewIndex, fromColumn);
+               }
+               
+               super.moveColumn(oldIndex, newIndex);
+       }
+       
+       /**
+        * Returns the total number of columns in this model.
+        *
+        * @param   onlyVisible   if set only visible columns will be counted
+        * @return      the number of columns in the <code>tableColumns</code> array
+        * @see #getColumns
+        */
+       public int getColumnCount(boolean onlyVisible) {
+               Vector<TableColumn> columns = (onlyVisible ? tableColumns : allTableColumns);
+               return columns.size();
+       }
+       
+       /**
+        * Returns an <code>Enumeration</code> of all the columns in the model.
+        *
+        * @param   onlyVisible   if set all invisible columns will be missing from the enumeration.
+        * @return an <code>Enumeration</code> of the columns in the model
+        */
+       public Enumeration<TableColumn> getColumns(boolean onlyVisible) {
+               Vector<TableColumn> columns = (onlyVisible ? tableColumns : allTableColumns);
+               
+               return columns.elements();
+       }
+       
+       /**
+        * Returns the position of the first column whose identifier equals <code>identifier</code>.
+        * Position is the the index in all visible columns if <code>onlyVisible</code> is true or
+        * else the index in all columns.
+        *
+        * @param       identifier   the identifier object to search for
+        * @param       onlyVisible  if set searches only visible columns
+        *
+        * @return              the index of the first column whose identifier
+        *                      equals <code>identifier</code>
+        *
+        * @exception       IllegalArgumentException  if <code>identifier</code>
+        *                              is <code>null</code>, or if no
+        *                              <code>TableColumn</code> has this
+        *                              <code>identifier</code>
+        * @see         #getColumn
+        */
+       public int getColumnIndex(Object identifier, boolean onlyVisible) {
+               if (identifier == null) {
+                       throw new IllegalArgumentException("Identifier is null");
+               }
+               
+               Vector<TableColumn> columns = (onlyVisible ? tableColumns : allTableColumns);
+               int noColumns = columns.size();
+               TableColumn column;
+               
+               for (int columnIndex = 0; columnIndex < noColumns; ++columnIndex) {
+                       column = columns.get(columnIndex);
+                       
+                       if (identifier.equals(column.getIdentifier()))
+                               return columnIndex;
+               }
+               
+               throw new IllegalArgumentException("Identifier not found");
+       }
+       
+       /**
+        * Returns the <code>TableColumn</code> object for the column
+        * at <code>columnIndex</code>.
+        *
+        * @param       columnIndex     the index of the column desired
+        * @param       onlyVisible     if set columnIndex is meant to be relative to all visible columns only
+        *                          else it is the index in all columns
+        *
+        * @return      the <code>TableColumn</code> object for the column
+        *                              at <code>columnIndex</code>
+        */
+       public TableColumn getColumn(int columnIndex, boolean onlyVisible) {
+               return tableColumns.elementAt(columnIndex);
+       }
+}
diff --git a/core/src/net/sf/openrocket/gui/figure3d/ComponentRenderer.java b/core/src/net/sf/openrocket/gui/figure3d/ComponentRenderer.java
new file mode 100644 (file)
index 0000000..80cdbfc
--- /dev/null
@@ -0,0 +1,340 @@
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+import javax.media.opengl.GLAutoDrawable;\r
+import javax.media.opengl.fixedfunc.GLLightingFunc;\r
+import javax.media.opengl.fixedfunc.GLMatrixFunc;\r
+import javax.media.opengl.glu.GLU;\r
+import javax.media.opengl.glu.GLUquadric;\r
+import javax.media.opengl.glu.GLUtessellator;\r
+import javax.media.opengl.glu.GLUtessellatorCallback;\r
+import javax.media.opengl.glu.GLUtessellatorCallbackAdapter;\r
+\r
+import net.sf.openrocket.logging.LogHelper;\r
+import net.sf.openrocket.rocketcomponent.BodyTube;\r
+import net.sf.openrocket.rocketcomponent.EllipticalFinSet;\r
+import net.sf.openrocket.rocketcomponent.FinSet;\r
+import net.sf.openrocket.rocketcomponent.LaunchLug;\r
+import net.sf.openrocket.rocketcomponent.MassObject;\r
+import net.sf.openrocket.rocketcomponent.RingComponent;\r
+import net.sf.openrocket.rocketcomponent.RocketComponent;\r
+import net.sf.openrocket.rocketcomponent.Transition;\r
+import net.sf.openrocket.startup.Application;\r
+import net.sf.openrocket.util.Coordinate;\r
+\r
+/*\r
+ * @author Bill Kuker <bkuker@billkuker.com>\r
+ */\r
+public class ComponentRenderer {\r
+       private static final LogHelper log = Application.getLogger();\r
+       \r
+       private int LOD = 80;\r
+\r
+       GLU glu;\r
+       GLUquadric q;\r
+       GLUtessellator tobj;\r
+\r
+       public ComponentRenderer() {\r
+\r
+       }\r
+\r
+       public void init(GLAutoDrawable drawable) {\r
+               glu = new GLU();\r
+               q = glu.gluNewQuadric();\r
+               tobj = GLU.gluNewTess();\r
+               glu.gluQuadricTexture(q, true);\r
+       }\r
+\r
+       private Map<RocketComponent, Integer> lists = new HashMap<RocketComponent, Integer>();\r
+       private boolean clearDisplayLists = false;\r
+       public void updateFigure() {\r
+               clearDisplayLists = true;\r
+       }\r
+       \r
+       public void renderGeometry(GL2 gl, RocketComponent c) {\r
+               if (glu == null)\r
+                       throw new IllegalStateException(this + " Not Initialized");\r
+\r
+               glu.gluQuadricNormals(q, GLU.GLU_SMOOTH);\r
+               \r
+               if ( clearDisplayLists ){\r
+                       log.debug("Clearing Display Lists");\r
+                       for ( int i : lists.values() ){\r
+                               gl.glDeleteLists(i,1);\r
+                       }\r
+                       lists.clear();\r
+                       clearDisplayLists = false;\r
+               }\r
+               if ( lists.containsKey(c) ){\r
+                       gl.glCallList(lists.get(c));\r
+               } else {\r
+                       int list = gl.glGenLists(1);\r
+                       gl.glNewList(list, GL2.GL_COMPILE_AND_EXECUTE);\r
+\r
+                       Coordinate[] oo = c.toAbsolute(new Coordinate(0, 0, 0));\r
+\r
+                       for (Coordinate o : oo) {\r
+                               gl.glPushMatrix();\r
+\r
+                               gl.glTranslated(o.x, o.y, o.z);\r
+\r
+                               if (c instanceof BodyTube) {\r
+                                       renderTube(gl, (BodyTube) c);\r
+                               } else if (c instanceof LaunchLug) {\r
+                                       renderLug(gl, (LaunchLug) c);\r
+                               } else if (c instanceof RingComponent) {\r
+                                       renderRing(gl, (RingComponent) c);\r
+                               } else if (c instanceof Transition) {\r
+                                       renderTransition(gl, (Transition) c);\r
+                               } else if (c instanceof MassObject) {\r
+                                       renderMassObject(gl, (MassObject) c);\r
+                               } else if (c instanceof FinSet) {\r
+                                       renderFinSet(gl, (FinSet) c);\r
+                               } else {\r
+                                       renderOther(gl, c);\r
+                               }\r
+                               gl.glPopMatrix();\r
+                       }\r
+                       \r
+                       gl.glEndList();\r
+                       lists.put(c, list);\r
+               }\r
+       }\r
+\r
+       private void renderOther(GL2 gl, RocketComponent c) {\r
+               gl.glBegin(GL.GL_LINES);\r
+               for (Coordinate cc : c.getComponentBounds()) {\r
+                       for (Coordinate ccc : c.getComponentBounds()) {\r
+                               gl.glVertex3d(cc.x, cc.y, cc.z);\r
+                               gl.glVertex3d(ccc.x, ccc.y, ccc.z);\r
+                       }\r
+               }\r
+               gl.glEnd();\r
+       }\r
+\r
+       private void renderTransition(GL2 gl, Transition t) {\r
+               gl.glRotated(90, 0, 1.0, 0);\r
+\r
+               if (t.getType() == Transition.Shape.CONICAL) {\r
+                       glu.gluCylinder(q, t.getForeRadius(), t.getAftRadius(),\r
+                                       t.getLength(), LOD, 1);\r
+               } else {\r
+                       TransitionRenderer.drawTransition(gl, t, LOD, LOD);\r
+               }\r
+\r
+               // Render AFT shoulder\r
+               gl.glPushMatrix();\r
+               gl.glTranslated(0, 0, t.getLength());\r
+\r
+               glu.gluCylinder(q, t.getAftShoulderRadius(), t.getAftShoulderRadius(),\r
+                               t.getAftShoulderLength(), LOD, 1);\r
+\r
+               gl.glRotated(180, 0, 1.0, 0);\r
+\r
+               glu.gluDisk(q, t.getAftRadius(), t.getAftShoulderRadius(), LOD, 2);\r
+\r
+               gl.glTranslated(0, 0, -t.getAftShoulderLength());\r
+\r
+               if (t.isFilled() || t.isAftShoulderCapped()) {\r
+                       glu.gluDisk(q, t.getAftShoulderRadius(), 0, LOD, 2);\r
+               }\r
+               gl.glPopMatrix();\r
+\r
+               // Render Fore Shoulder\r
+               gl.glPushMatrix();\r
+               gl.glRotated(180, 0, 1.0, 0);\r
+\r
+               glu.gluCylinder(q, t.getForeShoulderRadius(),\r
+                               t.getForeShoulderRadius(), t.getForeShoulderLength(), LOD, 1);\r
+\r
+               gl.glRotated(180, 0, 1.0, 0);\r
+\r
+               glu.gluDisk(q, t.getForeRadius(), t.getForeShoulderRadius(), LOD, 2);\r
+\r
+               gl.glTranslated(0, 0, -t.getForeShoulderLength());\r
+\r
+               if (t.isFilled() || t.isForeShoulderCapped()) {\r
+                       glu.gluDisk(q, t.getForeShoulderRadius(), 0, LOD, 2);\r
+               }\r
+               gl.glPopMatrix();\r
+\r
+       }\r
+\r
+       private void renderTube(GL2 gl, BodyTube t) {\r
+               gl.glRotated(90, 0, 1.0, 0);\r
+               glu.gluCylinder(q, t.getOuterRadius(), t.getOuterRadius(),\r
+                               t.getLength(), LOD, 1);\r
+       }\r
+\r
+       private void renderRing(GL2 gl, RingComponent r) {\r
+               gl.glRotated(90, 0, 1.0, 0);\r
+               glu.gluCylinder(q, r.getOuterRadius(), r.getOuterRadius(),\r
+                               r.getLength(), LOD, 1);\r
+\r
+               gl.glRotated(180, 0, 1.0, 0);\r
+               glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);\r
+\r
+               gl.glRotated(180, 0, 1.0, 0);\r
+               gl.glTranslated(0, 0, r.getLength());\r
+               glu.gluDisk(q, r.getInnerRadius(), r.getOuterRadius(), LOD, 2);\r
+\r
+               gl.glTranslated(0, 0, -r.getLength());\r
+               glu.gluCylinder(q, r.getInnerRadius(), r.getInnerRadius(),\r
+                               r.getLength(), LOD, 1);\r
+\r
+       }\r
+\r
+       private void renderLug(GL2 gl, LaunchLug t) {\r
+\r
+               gl.glRotated(90, 0, 1.0, 0);\r
+               glu.gluCylinder(q, t.getOuterRadius(), t.getOuterRadius(),\r
+                               t.getLength(), LOD, 1);\r
+       }\r
+\r
+       private void renderMassObject(GL2 gl, MassObject o) {\r
+               gl.glRotated(90, 0, 1.0, 0);\r
+\r
+               MassObjectRenderer.drawMassObject(gl, o, LOD, LOD);\r
+       }\r
+\r
+       private void renderFinSet(final GL2 gl, FinSet fs) {\r
+               \r
+               Coordinate finPoints[] = fs.getFinPointsWithTab();\r
+               \r
+               double minX = Double.MAX_VALUE;\r
+               double minY = Double.MAX_VALUE;\r
+               double maxX = Double.MIN_VALUE;\r
+               double maxY = Double.MIN_VALUE;\r
+       \r
+               for (int i = 0; i < finPoints.length; i++) {\r
+                       Coordinate c = finPoints[i];\r
+                       minX = Math.min(c.x, minX);     \r
+                       minY = Math.min(c.y, minY);\r
+                       maxX = Math.max(c.x, maxX);\r
+                       maxY = Math.max(c.y, maxY);     \r
+               }\r
+               \r
+               gl.glMatrixMode(GL.GL_TEXTURE);\r
+               gl.glPushMatrix();\r
+               gl.glScaled(1/(maxX-minX), 1/(maxY-minY), 0);\r
+               gl.glTranslated(-minX, -minY - fs.getBodyRadius(), 0);\r
+               gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
+               \r
+               gl.glRotated(fs.getBaseRotation() * (180.0 / Math.PI), 1, 0, 0);\r
+               \r
+               for (int fin = 0; fin < fs.getFinCount(); fin++) {\r
+\r
+                       gl.glPushMatrix();\r
+\r
+                       gl.glTranslated(fs.getLength() / 2, 0, 0);\r
+                       gl.glRotated(fs.getCantAngle() * (180.0 / Math.PI), 0, 1, 0);\r
+                       gl.glTranslated(-fs.getLength() / 2, 0, 0);\r
+\r
+                       GLUtessellatorCallback cb = new GLUtessellatorCallbackAdapter() {\r
+                               @Override\r
+                               public void vertex(Object vertexData) {\r
+                                       double d[] = (double[]) vertexData;\r
+                                       gl.glTexCoord2d(d[0], d[1]);\r
+                                       gl.glVertex3dv(d, 0);\r
+                               }\r
+\r
+                               @Override\r
+                               public void begin(int type) {\r
+                                       gl.glBegin(type);\r
+                               }\r
+\r
+                               @Override\r
+                               public void end() {\r
+                                       gl.glEnd();\r
+                               }\r
+                       };\r
+\r
+                       GLU.gluTessCallback(tobj, GLU.GLU_TESS_VERTEX, cb);\r
+                       GLU.gluTessCallback(tobj, GLU.GLU_TESS_BEGIN, cb);\r
+                       GLU.gluTessCallback(tobj, GLU.GLU_TESS_END, cb);\r
+\r
+                       GLU.gluTessBeginPolygon(tobj, null);\r
+                       GLU.gluTessBeginContour(tobj);\r
+                       gl.glNormal3f(0, 0, 1);\r
+                       for (int i = finPoints.length - 1; i >= 0; i--) {\r
+                               Coordinate c = finPoints[i];\r
+                               double[] p = new double[] { c.x, c.y + fs.getBodyRadius(),\r
+                                               c.z + fs.getThickness() / 2.0 };\r
+                               GLU.gluTessVertex(tobj, p, 0, p);\r
+\r
+                       }\r
+                       GLU.gluTessEndContour(tobj);\r
+                       GLU.gluTessEndPolygon(tobj);\r
+\r
+                       GLU.gluTessBeginPolygon(tobj, null);\r
+                       GLU.gluTessBeginContour(tobj);\r
+                       gl.glNormal3f(0, 0, -1);\r
+                       for (int i = 0; i < finPoints.length; i++) {\r
+                               Coordinate c = finPoints[i];\r
+                               double[] p = new double[] { c.x, c.y + fs.getBodyRadius(),\r
+                                               c.z - fs.getThickness() / 2.0 };\r
+                               GLU.gluTessVertex(tobj, p, 0, p);\r
+\r
+                       }\r
+                       GLU.gluTessEndContour(tobj);\r
+                       GLU.gluTessEndPolygon(tobj);\r
+\r
+                       // Strip around the edge\r
+                       if (!(fs instanceof EllipticalFinSet))\r
+                               gl.glShadeModel(GLLightingFunc.GL_FLAT);\r
+                       gl.glBegin(GL.GL_TRIANGLE_STRIP);\r
+                       for (int i = 0; i <= finPoints.length; i++) {\r
+                               Coordinate c = finPoints[i % finPoints.length];\r
+                               // if ( i > 1 ){\r
+                               Coordinate c2 = finPoints[(i - 1 + finPoints.length)\r
+                                               % finPoints.length];\r
+                               gl.glNormal3d(c2.y - c.y, c.x - c2.x, 0);\r
+                               // }\r
+                               gl.glTexCoord2d(c.x, c.y + fs.getBodyRadius());\r
+                               gl.glVertex3d(c.x, c.y + fs.getBodyRadius(),\r
+                                               c.z - fs.getThickness() / 2.0);\r
+                               gl.glVertex3d(c.x, c.y + fs.getBodyRadius(),\r
+                                               c.z + fs.getThickness() / 2.0);\r
+                       }\r
+                       gl.glEnd();\r
+                       if (!(fs instanceof EllipticalFinSet))\r
+                               gl.glShadeModel(GLLightingFunc.GL_SMOOTH);\r
+\r
+                       gl.glPopMatrix();\r
+\r
+                       gl.glRotated(360.0 / fs.getFinCount(), 1, 0, 0);\r
+               }\r
+               \r
+               gl.glMatrixMode(GL.GL_TEXTURE);\r
+               gl.glPopMatrix();\r
+               gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
+               \r
+       }\r
+\r
+       public void renderMotor(final GL2 gl, final Coordinate c, double l, double r) {\r
+               final float outside[] = { 0.2f, 0.2f, 0.2f, 1.0f };\r
+               gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, outside, 0);\r
+               gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, outside, 0);\r
+\r
+               gl.glPushMatrix();\r
+\r
+               gl.glTranslated(c.x, c.y, c.z);\r
+\r
+               gl.glRotated(90, 0, 1.0, 0);\r
+\r
+               glu.gluCylinder(q, r, r, l, LOD, 1);\r
+\r
+               glu.gluDisk(q, r, 0, LOD, 2);\r
+\r
+               gl.glTranslated(0, 0, l);\r
+               gl.glRotated(180, 0, 1.0, 0);\r
+\r
+               glu.gluDisk(q, r, 0, LOD, 2);\r
+\r
+               gl.glPopMatrix();\r
+       }\r
+}\r
diff --git a/core/src/net/sf/openrocket/gui/figure3d/MassObjectRenderer.java b/core/src/net/sf/openrocket/gui/figure3d/MassObjectRenderer.java
new file mode 100644 (file)
index 0000000..4c1d934
--- /dev/null
@@ -0,0 +1,263 @@
+/*\r
+ ** License Applicability. Except to the extent portions of this file are\r
+ ** made subject to an alternative license as permitted in the SGI Free\r
+ ** Software License B, Version 2.0 (the "License"), the contents of this\r
+ ** file are subject only to the provisions of the License. You may not use\r
+ ** this file except in compliance with the License. You may obtain a copy\r
+ ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600\r
+ ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:\r
+ ** \r
+ ** http://oss.sgi.com/projects/FreeB\r
+ ** \r
+ ** Note that, as provided in the License, the Software is distributed on an\r
+ ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS\r
+ ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND\r
+ ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A\r
+ ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.\r
+ ** \r
+ ** NOTE:  The Original Code (as defined below) has been licensed to Sun\r
+ ** Microsystems, Inc. ("Sun") under the SGI Free Software License B\r
+ ** (Version 1.1), shown above ("SGI License").   Pursuant to Section\r
+ ** 3.2(3) of the SGI License, Sun is distributing the Covered Code to\r
+ ** you under an alternative license ("Alternative License").  This\r
+ ** Alternative License includes all of the provisions of the SGI License\r
+ ** except that Section 2.2 and 11 are omitted.  Any differences between\r
+ ** the Alternative License and the SGI License are offered solely by Sun\r
+ ** and not by SGI.\r
+ **\r
+ ** Original Code. The Original Code is: OpenGL Sample Implementation,\r
+ ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,\r
+ ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.\r
+ ** Copyright in any portions created by third parties is as indicated\r
+ ** elsewhere herein. All Rights Reserved.\r
+ ** \r
+ ** Additional Notice Provisions: The application programming interfaces\r
+ ** established by SGI in conjunction with the Original Code are The\r
+ ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released\r
+ ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version\r
+ ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X\r
+ ** Window System(R) (Version 1.3), released October 19, 1998. This software\r
+ ** was created using the OpenGL(R) version 1.2.1 Sample Implementation\r
+ ** published by SGI, but has not been independently verified as being\r
+ ** compliant with the OpenGL(R) version 1.2.1 Specification.\r
+ **\r
+ ** $Date: 2009-03-04 17:23:34 -0800 (Wed, 04 Mar 2009) $ $Revision: 1856 $\r
+ ** $Header$\r
+ */\r
+\r
+/* \r
+ * Copyright (c) 2002-2004 LWJGL Project\r
+ * All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are \r
+ * met:\r
+ * \r
+ * * Redistributions of source code must retain the above copyright \r
+ *   notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ *   notice, this list of conditions and the following disclaimer in the\r
+ *   documentation and/or other materials provided with the distribution.\r
+ *\r
+ * * Neither the name of 'LWJGL' nor the names of \r
+ *   its contributors may be used to endorse or promote products derived \r
+ *   from this software without specific prior written permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR \r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, \r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR \r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING \r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are\r
+ * met:\r
+ * \r
+ * - Redistribution of source code must retain the above copyright\r
+ *   notice, this list of conditions and the following disclaimer.\r
+ * \r
+ * - Redistribution in binary form must reproduce the above copyright\r
+ *   notice, this list of conditions and the following disclaimer in the\r
+ *   documentation and/or other materials provided with the distribution.\r
+ * \r
+ * Neither the name of Sun Microsystems, Inc. or the names of\r
+ * contributors may be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ * \r
+ * This software is provided "AS IS," without a warranty of any kind. ALL\r
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,\r
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A\r
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN\r
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR\r
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR\r
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR\r
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR\r
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE\r
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,\r
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF\r
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\r
+ * \r
+ * You acknowledge that this software is not designed or intended for use\r
+ * in the design, construction, operation or maintenance of any nuclear\r
+ * facility.\r
+ */\r
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+\r
+import net.sf.openrocket.rocketcomponent.MassObject;\r
+\r
+public final class MassObjectRenderer {\r
+       private static final boolean textureFlag = true;\r
+\r
+       private MassObjectRenderer() {\r
+       }\r
+\r
+       public static final void drawMassObject(final GL2 gl, final MassObject o,\r
+                       final int slices, final int stacks) {\r
+\r
+               double da, r, dz;\r
+               double x, y, z, nz, nsign;\r
+               int i, j;\r
+\r
+               nsign = 1.0f;\r
+\r
+               da = 2.0f * PI / slices;\r
+               dz = o.getLength() / stacks;\r
+\r
+               double ds = 1.0f / slices;\r
+               double dt = 1.0f / stacks;\r
+               double t = 0.0f;\r
+               z = 0.0f;\r
+               for (j = 0; j < stacks; j++) {\r
+                       r = getRadius(o, z);\r
+                       double rNext = getRadius(o, z + dz);\r
+                       if (j == stacks - 1)\r
+                               rNext = 0;\r
+\r
+                       if (j == stacks - 1)\r
+                               rNext = 0;\r
+\r
+                       // Z component of normal vectors\r
+                       nz = -(rNext - r) / dz;\r
+\r
+                       double s = 0.0f;\r
+                       glBegin(gl, GL2.GL_QUAD_STRIP);\r
+                       for (i = 0; i <= slices; i++) {\r
+                               if (i == slices) {\r
+                                       x = sin(0.0f);\r
+                                       y = cos(0.0f);\r
+                               } else {\r
+                                       x = sin((i * da));\r
+                                       y = cos((i * da));\r
+                               }\r
+                               if (nsign == 1.0f) {\r
+                                       normal3d(gl, (x * nsign), (y * nsign), (nz * nsign));\r
+                                       TXTR_COORD(gl, s, t);\r
+                                       glVertex3d(gl, (x * r), (y * r), z);\r
+                                       normal3d(gl, (x * nsign), (y * nsign), (nz * nsign));\r
+                                       TXTR_COORD(gl, s, t + dt);\r
+                                       glVertex3d(gl, (x * rNext), (y * rNext), (z + dz));\r
+                               } else {\r
+                                       normal3d(gl, x * nsign, y * nsign, nz * nsign);\r
+                                       TXTR_COORD(gl, s, t);\r
+                                       glVertex3d(gl, (x * r), (y * r), z);\r
+                                       normal3d(gl, x * nsign, y * nsign, nz * nsign);\r
+                                       TXTR_COORD(gl, s, t + dt);\r
+                                       glVertex3d(gl, (x * rNext), (y * rNext), (z + dz));\r
+                               }\r
+                               s += ds;\r
+                       } // for slices\r
+                       glEnd(gl);\r
+                       // r += dr;\r
+                       t += dt;\r
+                       z += dz;\r
+               } // for stacks\r
+       }\r
+\r
+       private static final double getRadius(MassObject o, double z) {\r
+               double arc = Math.min(o.getLength(), 2 * o.getRadius()) * 0.35f;\r
+               double r = o.getRadius();\r
+               if (z == 0 || z == o.getLength())\r
+                       return 0;\r
+               if (z < arc) {\r
+                       double zz = z - arc;\r
+                       return (r - arc) + Math.sqrt(arc * arc - zz * zz);\r
+               }\r
+               if (z > o.getLength() - arc) {\r
+                       double zz = (z - o.getLength() + arc);\r
+                       return (r - arc) + Math.sqrt(arc * arc - zz * zz);\r
+               }\r
+               return o.getRadius();\r
+       }\r
+\r
+       // ----------------------------------------------------------------------\r
+       // Internals only below this point\r
+       //\r
+\r
+       private static final double PI = Math.PI;\r
+\r
+       private static final void glBegin(GL gl, int mode) {\r
+               gl.getGL2().glBegin(mode);\r
+       }\r
+\r
+       private static final void glEnd(GL gl) {\r
+               gl.getGL2().glEnd();\r
+       }\r
+\r
+       private static final void glVertex3d(GL gl, double x, double y, double z) {\r
+               gl.getGL2().glVertex3d(x, y, z);\r
+       }\r
+\r
+       private static final void glNormal3d(GL gl, double x, double y, double z) {\r
+               gl.getGL2().glNormal3d(x, y, z);\r
+       }\r
+\r
+       private static final void glTexCoord2d(GL gl, double x, double y) {\r
+               gl.getGL2().glTexCoord2d(x, y);\r
+       }\r
+\r
+       /**\r
+        * Call glNormal3f after scaling normal to unit length.\r
+        * \r
+        * @param x\r
+        * @param y\r
+        * @param z\r
+        */\r
+       private static final void normal3d(GL gl, double x, double y, double z) {\r
+               double mag;\r
+\r
+               mag = Math.sqrt(x * x + y * y + z * z);\r
+               if (mag > 0.00001F) {\r
+                       x /= mag;\r
+                       y /= mag;\r
+                       z /= mag;\r
+               }\r
+               glNormal3d(gl, x, y, z);\r
+       }\r
+\r
+       private static final void TXTR_COORD(GL gl, double x, double y) {\r
+               if (textureFlag)\r
+                       glTexCoord2d(gl, x, y);\r
+       }\r
+\r
+       private static final double sin(double r) {\r
+               return Math.sin(r);\r
+       }\r
+\r
+       private static final double cos(double r) {\r
+               return Math.cos(r);\r
+       }\r
+}\r
diff --git a/core/src/net/sf/openrocket/gui/figure3d/Quick3dMain.java b/core/src/net/sf/openrocket/gui/figure3d/Quick3dMain.java
new file mode 100644 (file)
index 0000000..d7c2e84
--- /dev/null
@@ -0,0 +1,76 @@
+package net.sf.openrocket.gui.figure3d;\r
+import java.awt.BorderLayout;\r
+\r
+import javax.swing.JFrame;\r
+import javax.swing.JPanel;\r
+\r
+import net.sf.openrocket.database.ComponentPresetDatabase;\r
+import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;\r
+import net.sf.openrocket.document.OpenRocketDocument;\r
+import net.sf.openrocket.file.DatabaseMotorFinder;\r
+import net.sf.openrocket.file.openrocket.importt.OpenRocketLoader;\r
+import net.sf.openrocket.gui.main.componenttree.ComponentTree;\r
+import net.sf.openrocket.gui.scalefigure.RocketPanel;\r
+import net.sf.openrocket.gui.util.SwingPreferences;\r
+import net.sf.openrocket.l10n.ResourceBundleTranslator;\r
+import net.sf.openrocket.startup.Application;\r
+\r
+/**\r
+ * An application for quickly testing 3d figure witout all the OpenRocket user interface\r
+ * \r
+ * @author bkuker\r
+ *\r
+ */\r
+public class Quick3dMain {\r
+\r
+       /**\r
+        * @param args\r
+        */\r
+       public static void main(String[] args) throws Exception {\r
+               Application.setBaseTranslator(new ResourceBundleTranslator(\r
+                               "l10n.messages"));\r
+               Application.setMotorSetDatabase(new ThrustCurveMotorSetDatabase(false) {\r
+                       {\r
+                               startLoading();\r
+                       }\r
+\r
+                       @Override\r
+                       protected void loadMotors() {\r
+                       }\r
+               });\r
+               Application.setPreferences(new SwingPreferences());\r
+               \r
+               // Must be done after localization is initialized\r
+               ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase() {\r
+\r
+                       @Override\r
+                       protected void load() {\r
+                               // This test app doesn't need any presets loaded - just an empty database.\r
+                       }\r
+                       \r
+               };\r
+               Application.setComponentPresetDao( componentPresetDao );\r
+\r
+               OpenRocketDocument doc = new OpenRocketLoader().loadFromStream(\r
+                               Quick3dMain.class.getResourceAsStream("/datafiles/examples/Clustered rocket design.ork"),\r
+                               new DatabaseMotorFinder());\r
+\r
+               JFrame ff = new JFrame();\r
+               ff.setSize(1200, 400);\r
+               ff.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\r
+\r
+               RocketPanel panel;\r
+\r
+               panel = new RocketPanel(doc);\r
+\r
+               ComponentTree ct = new ComponentTree(doc);\r
+               panel.setSelectionModel(ct.getSelectionModel());\r
+\r
+               JPanel p = new JPanel();\r
+               p.setLayout(new BorderLayout());\r
+               p.add(ct, BorderLayout.WEST);\r
+               p.add(panel, BorderLayout.CENTER);\r
+               ff.setContentPane(p);\r
+               ff.setVisible(true);\r
+       }\r
+}\r
diff --git a/core/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java b/core/src/net/sf/openrocket/gui/figure3d/RocketFigure3d.java
new file mode 100644 (file)
index 0000000..8df1e85
--- /dev/null
@@ -0,0 +1,628 @@
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import java.awt.BorderLayout;\r
+import java.awt.Color;\r
+import java.awt.Graphics2D;\r
+import java.awt.Point;\r
+import java.awt.Rectangle;\r
+import java.awt.RenderingHints;\r
+import java.awt.SplashScreen;\r
+import java.awt.event.MouseEvent;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.image.BufferedImage;\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+import javax.media.opengl.GLAutoDrawable;\r
+import javax.media.opengl.GLCapabilities;\r
+import javax.media.opengl.GLEventListener;\r
+import javax.media.opengl.GLProfile;\r
+import javax.media.opengl.awt.GLCanvas;\r
+import javax.media.opengl.fixedfunc.GLLightingFunc;\r
+import javax.media.opengl.fixedfunc.GLMatrixFunc;\r
+import javax.media.opengl.glu.GLU;\r
+import javax.swing.JLabel;\r
+import javax.swing.JPanel;\r
+import javax.swing.JPopupMenu;\r
+import javax.swing.SwingUtilities;\r
+import javax.swing.event.MouseInputAdapter;\r
+\r
+import net.sf.openrocket.gui.figureelements.CGCaret;\r
+import net.sf.openrocket.gui.figureelements.CPCaret;\r
+import net.sf.openrocket.gui.figureelements.FigureElement;\r
+import net.sf.openrocket.logging.LogHelper;\r
+import net.sf.openrocket.rocketcomponent.Configuration;\r
+import net.sf.openrocket.rocketcomponent.RocketComponent;\r
+import net.sf.openrocket.startup.Application;\r
+import net.sf.openrocket.util.Coordinate;\r
+import net.sf.openrocket.util.MathUtil;\r
+\r
+import com.jogamp.opengl.util.awt.Overlay;\r
+\r
+/*\r
+ * @author Bill Kuker <bkuker@billkuker.com>\r
+ */\r
+public class RocketFigure3d extends JPanel implements GLEventListener {\r
+       private static final long serialVersionUID = 1L;\r
+       private static final LogHelper log = Application.getLogger();\r
+       \r
+       static {\r
+               //this allows the GL canvas and things like the motor selection\r
+               //drop down to z-order themselves.\r
+               JPopupMenu.setDefaultLightWeightPopupEnabled(false);\r
+       }\r
+\r
+       private static final double fovY = 15.0;\r
+       private static double fovX = Double.NaN;\r
+       private static final int CARET_SIZE = 20;\r
+       \r
+       private Configuration configuration;\r
+       private GLCanvas canvas;\r
+\r
+\r
+       \r
+       private Overlay extrasOverlay, caretOverlay;\r
+       private BufferedImage cgCaretRaster, cpCaretRaster;\r
+       private volatile boolean redrawExtras = true;\r
+\r
+       private final ArrayList<FigureElement> relativeExtra = new ArrayList<FigureElement>();\r
+       private final ArrayList<FigureElement> absoluteExtra = new ArrayList<FigureElement>();\r
+\r
+       private double roll = 0;\r
+       private double yaw = 0;\r
+\r
+       Point pickPoint = null;\r
+       MouseEvent pickEvent;\r
+\r
+       float[] lightPosition = new float[] { 1, 4, 1, 0 };\r
+\r
+       RocketRenderer rr = new RocketRenderer();\r
+\r
+       public RocketFigure3d(Configuration config) {\r
+               this.configuration = config;\r
+               this.setLayout(new BorderLayout());\r
+               \r
+               //Only initizlize GL if 3d is enabled.\r
+               if ( is3dEnabled() ){\r
+                       //Fixes a linux / X bug: Splash must be closed before GL Init\r
+                       SplashScreen splash = SplashScreen.getSplashScreen();\r
+                       if ( splash != null )\r
+                               splash.close();\r
+                       \r
+                       initGLCanvas();\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Return true if 3d view is enabled. This may be toggled by the user at\r
+        * launch time.\r
+        * @return\r
+        */\r
+       public static boolean is3dEnabled(){\r
+               return System.getProperty("openrocket.3d.disable") == null;\r
+       }\r
+       \r
+       private void initGLCanvas(){\r
+               log.debug("Initializing RocketFigure3D OpenGL Canvas");\r
+               try {\r
+                       log.debug("Setting up GL capabilities...");\r
+                       \r
+                       log.verbose("GL - Getting Default Profile");\r
+                       GLProfile glp = GLProfile.getDefault();\r
+                       \r
+                       log.verbose("GL - creating GLCapabilities");\r
+                       GLCapabilities caps = new GLCapabilities(glp);\r
+                       \r
+                       log.verbose("GL - setSampleBuffers");\r
+                       caps.setSampleBuffers(true);\r
+                       \r
+                       log.verbose("GL - setNumSamples");\r
+                       caps.setNumSamples(6);\r
+                       \r
+                       log.verbose("GL - setStencilBits");\r
+                       caps.setStencilBits(1);\r
+\r
+                       log.verbose("GL - Creating Canvas");\r
+                       canvas = new GLCanvas(caps);\r
+\r
+                       log.verbose("GL - Registering as GLEventListener on canvas");\r
+                       canvas.addGLEventListener(this);\r
+                       \r
+                       log.verbose("GL - Adding canvas to this JPanel");\r
+                       this.add(canvas, BorderLayout.CENTER);\r
+\r
+                       log.verbose("GL - Setting up mouse listeners");\r
+                       setupMouseListeners();\r
+                       \r
+                       log.verbose("GL - Rasterizine Carets"); //reticulating splines?\r
+                       rasterizeCarets();\r
+                       \r
+               } catch (Throwable t) {\r
+                       log.error("An error occurred creating 3d View", t);\r
+                       canvas = null;\r
+                       this.add(new JLabel("Unable to load 3d Libraries: "\r
+                                       + t.getMessage()));\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Set up the standard rendering hints on the Graphics2D\r
+        */\r
+       private static void setRenderingHints(Graphics2D g){\r
+               g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,\r
+                               RenderingHints.VALUE_STROKE_NORMALIZE);\r
+               g.setRenderingHint(RenderingHints.KEY_RENDERING,\r
+                               RenderingHints.VALUE_RENDER_QUALITY);\r
+               g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
+                               RenderingHints.VALUE_ANTIALIAS_ON);\r
+       }\r
+       \r
+       /**\r
+        * Rasterize the carets into 2 buffered images that I can blit onto the\r
+        * 3d display every redraw without all of the caret shape rendering overhead\r
+        */\r
+       private void rasterizeCarets(){\r
+               Graphics2D g2d;\r
+               \r
+               //Rasterize a CG Caret\r
+               cgCaretRaster = new BufferedImage(CARET_SIZE, CARET_SIZE, BufferedImage.TYPE_4BYTE_ABGR);\r
+               g2d = cgCaretRaster.createGraphics();\r
+               setRenderingHints(g2d);\r
+               \r
+               g2d.setBackground(new Color(0, 0, 0, 0));\r
+               g2d.clearRect(0, 0, CARET_SIZE, CARET_SIZE);\r
+               \r
+               new CGCaret(CARET_SIZE/2,CARET_SIZE/2).paint(g2d, 1.0);\r
+               \r
+               g2d.dispose();\r
+\r
+               //Rasterize a CP Caret\r
+               cpCaretRaster = new BufferedImage(CARET_SIZE, CARET_SIZE, BufferedImage.TYPE_4BYTE_ABGR);\r
+               g2d = cpCaretRaster.createGraphics();\r
+               setRenderingHints(g2d);\r
+               \r
+               g2d.setBackground(new Color(0, 0, 0, 0));\r
+               g2d.clearRect(0, 0, CARET_SIZE, CARET_SIZE);\r
+               \r
+               new CPCaret(CARET_SIZE/2,CARET_SIZE/2).paint(g2d, 1.0);\r
+               \r
+               g2d.dispose();\r
+               \r
+       }\r
+\r
+       private void setupMouseListeners() {\r
+               MouseInputAdapter a = new MouseInputAdapter() {\r
+                       int lastX;\r
+                       int lastY;\r
+                       MouseEvent pressEvent;\r
+\r
+                       @Override\r
+                       public void mousePressed(MouseEvent e) {\r
+                               lastX = e.getX();\r
+                               lastY = e.getY();\r
+                               pressEvent = e;\r
+                       }\r
+\r
+                       @Override\r
+                       public void mouseClicked(MouseEvent e) {\r
+                               pickPoint = new Point(lastX, canvas.getHeight() - lastY);\r
+                               pickEvent = e;\r
+                               internalRepaint();\r
+                       }\r
+\r
+                       @Override\r
+                       public void mouseDragged(MouseEvent e) {\r
+                               int dx = lastX - e.getX();\r
+                               int dy = lastY - e.getY();\r
+                               lastX = e.getX();\r
+                               lastY = e.getY();\r
+\r
+                               if (pressEvent.getButton() == MouseEvent.BUTTON1) {\r
+                                       if (Math.abs(dx) > Math.abs(dy)) {\r
+                                               setYaw(yaw - (float) dx / 100.0);\r
+                                       } else {\r
+                                               if ( yaw > Math.PI/2.0 && yaw < 3.0*Math.PI/2.0 ){\r
+                                                       dy = -dy;\r
+                                               }\r
+                                               setRoll(roll - (float) dy / 100.0);\r
+                                       }\r
+                               } else {\r
+                                       lightPosition[0] -= 0.1f * dx;\r
+                                       lightPosition[1] += 0.1f * dy;\r
+                                       internalRepaint();\r
+                               }\r
+                       }\r
+               };\r
+               canvas.addMouseMotionListener(a);\r
+               canvas.addMouseListener(a);\r
+       }\r
+\r
+       public void setConfiguration(Configuration configuration) {\r
+               this.configuration = configuration;\r
+               updateFigure();\r
+       }\r
+\r
+       @Override\r
+       public void display(GLAutoDrawable drawable) {\r
+               GL2 gl = drawable.getGL().getGL2();\r
+               GLU glu = new GLU();\r
+\r
+               gl.glEnable(GL.GL_MULTISAMPLE);\r
+\r
+               gl.glClearColor(1, 1, 1, 1);\r
+               gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);\r
+\r
+               setupView(gl, glu);\r
+\r
+               if (pickPoint != null) {\r
+                       gl.glDisable(GLLightingFunc.GL_LIGHTING);\r
+                       final RocketComponent picked = rr.pick(drawable, configuration,\r
+                                       pickPoint, pickEvent.isShiftDown()?selection:null );\r
+                       if (csl != null && picked != null) {\r
+                               final MouseEvent e = pickEvent;\r
+                               SwingUtilities.invokeLater(new Runnable() {\r
+                                       @Override\r
+                                       public void run() {\r
+                                               csl.componentClicked(new RocketComponent[] { picked },\r
+                                                               e);\r
+                                       }\r
+                               });\r
+\r
+                       }\r
+                       pickPoint = null;\r
+\r
+                       gl.glClearColor(1, 1, 1, 1);\r
+                       gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);\r
+\r
+                       gl.glEnable(GLLightingFunc.GL_LIGHTING);\r
+               }\r
+               rr.render(drawable, configuration, selection);\r
+               \r
+               drawExtras(gl, glu);\r
+               drawCarets(gl, glu);\r
+       }\r
+\r
+       \r
+       private void drawCarets(GL2 gl, GLU glu) {\r
+               final Graphics2D og2d = caretOverlay.createGraphics();\r
+               setRenderingHints(og2d);\r
+               \r
+               og2d.setBackground(new Color(0, 0, 0, 0));\r
+               og2d.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());\r
+               caretOverlay.markDirty(0, 0, canvas.getWidth(), canvas.getHeight());\r
+\r
+               // The existing relative Extras don't really work right for 3d.\r
+               Coordinate pCP = project(cp, gl, glu);\r
+               Coordinate pCG = project(cg, gl, glu);\r
+\r
+               final int d = CARET_SIZE/2;\r
+               \r
+               //z order the carets \r
+               if (pCG.z < pCP.z) {\r
+                       //Subtract half of the caret size, so they are centered ( The +/- d in each translate)\r
+                       //Flip the sense of the Y coordinate from GL to normal (Y+ up/down)\r
+                       og2d.drawRenderedImage(\r
+                                       cpCaretRaster,\r
+                                       AffineTransform.getTranslateInstance((pCP.x - d),\r
+                                                       canvas.getHeight() - (pCP.y + d)));\r
+                       og2d.drawRenderedImage(\r
+                                       cgCaretRaster,\r
+                                       AffineTransform.getTranslateInstance((pCG.x - d),\r
+                                                       canvas.getHeight() - (pCG.y + d)));\r
+               } else {\r
+                       og2d.drawRenderedImage(\r
+                                       cgCaretRaster,\r
+                                       AffineTransform.getTranslateInstance((pCG.x - d),\r
+                                                       canvas.getHeight() - (pCG.y + d)));\r
+                       og2d.drawRenderedImage(\r
+                                       cpCaretRaster,\r
+                                       AffineTransform.getTranslateInstance((pCP.x - d),\r
+                                                       canvas.getHeight() - (pCP.y + d)));\r
+               }\r
+               og2d.dispose();\r
+               \r
+               gl.glEnable(GL.GL_BLEND);\r
+               caretOverlay.drawAll();\r
+               gl.glDisable(GL.GL_BLEND);\r
+       }\r
+       \r
+       /**\r
+        * Draw the extras overlay to the gl canvas.\r
+        * Re-blits the overlay every frame. Only re-renders the overlay\r
+        * when needed.\r
+        */\r
+       private void drawExtras(GL2 gl, GLU glu){\r
+               //Only re-render if needed\r
+               //      redrawExtras: Some external change (new simulation data) means\r
+               //              the data is out of date.\r
+               //      extrasOverlay.contentsLost(): For some reason the buffer with this\r
+               //              data is lost.\r
+               if ( redrawExtras || extrasOverlay.contentsLost() ){\r
+                       log.debug("Redrawing Overlay");\r
+                       \r
+                       final Graphics2D og2d = extrasOverlay.createGraphics(); \r
+                       setRenderingHints(og2d);\r
+\r
+                       og2d.setBackground(new Color(0, 0, 0, 0));\r
+                       og2d.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());\r
+                       extrasOverlay.markDirty(0, 0, canvas.getWidth(), canvas.getHeight());\r
+                       \r
+                       for (FigureElement e : relativeExtra) {\r
+                               e.paint(og2d, 1);\r
+                       }\r
+                       Rectangle rect = this.getVisibleRect();\r
+       \r
+                       for (FigureElement e : absoluteExtra) {\r
+                               e.paint(og2d, 1.0, rect);\r
+                       }\r
+                       og2d.dispose();\r
+                       \r
+                       redrawExtras = false;\r
+               }\r
+\r
+               //Re-blit to gl canvas every time\r
+               gl.glEnable(GL.GL_BLEND);\r
+               extrasOverlay.drawAll();\r
+               gl.glDisable(GL.GL_BLEND);\r
+       }\r
+\r
+       @Override\r
+       public void dispose(GLAutoDrawable drawable) {\r
+               log.verbose("GL - dispose() called");\r
+       }\r
+\r
+       @Override\r
+       public void init(GLAutoDrawable drawable) {\r
+               log.verbose("GL - init() called");\r
+               rr.init(drawable);\r
+\r
+               GL2 gl = drawable.getGL().getGL2();\r
+               gl.glClearDepth(1.0f); // clear z-buffer to the farthest\r
+\r
+               gl.glDepthFunc(GL.GL_LEQUAL); // the type of depth test to do\r
+\r
+               float amb = 0.5f;\r
+               float dif = 1.0f;\r
+               gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_AMBIENT,\r
+                               new float[] { amb, amb, amb, 1 }, 0);\r
+               gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_DIFFUSE,\r
+                               new float[] { dif, dif, dif, 1 }, 0);\r
+               gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_SPECULAR,\r
+                               new float[] { dif, dif, dif, 1 }, 0);\r
+\r
+               gl.glEnable(GLLightingFunc.GL_LIGHT1);\r
+               gl.glEnable(GLLightingFunc.GL_LIGHTING);\r
+               gl.glShadeModel(GLLightingFunc.GL_SMOOTH);\r
+\r
+               gl.glEnable(GLLightingFunc.GL_NORMALIZE);\r
+\r
+               extrasOverlay = new Overlay(drawable);\r
+               caretOverlay = new Overlay(drawable);\r
+               \r
+               log.verbose("GL - init() complete");\r
+       }\r
+\r
+       @Override\r
+       public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {\r
+               log.verbose("GL - reshape() called");\r
+               GL2 gl = drawable.getGL().getGL2();\r
+               GLU glu = new GLU();\r
+\r
+               double ratio = (double) w / (double) h;\r
+               fovX = fovY * ratio;\r
+\r
+               gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);\r
+               gl.glLoadIdentity();\r
+               glu.gluPerspective(fovY, ratio, 0.05f, 100f);\r
+               gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
+               \r
+               redrawExtras = true;\r
+               log.verbose("GL - reshape() complete");\r
+       }\r
+\r
+       @SuppressWarnings("unused")\r
+       private static class Bounds {\r
+               double xMin, xMax, xSize;\r
+               double yMin, yMax, ySize;\r
+               double zMin, zMax, zSize;\r
+               double rMax;\r
+       }\r
+\r
+       /**\r
+        * Calculates the bounds for the current configuration\r
+        * \r
+        * @return\r
+        */\r
+       private Bounds calculateBounds() {\r
+               Bounds ret = new Bounds();\r
+               Collection<Coordinate> bounds = configuration.getBounds();\r
+               for (Coordinate c : bounds) {\r
+                       ret.xMax = Math.max(ret.xMax, c.x);\r
+                       ret.xMin = Math.min(ret.xMin, c.x);\r
+\r
+                       ret.yMax = Math.max(ret.yMax, c.y);\r
+                       ret.yMin = Math.min(ret.yMin, c.y);\r
+\r
+                       ret.zMax = Math.max(ret.zMax, c.z);\r
+                       ret.zMin = Math.min(ret.zMin, c.z);\r
+\r
+                       double r = MathUtil.hypot(c.y, c.z);\r
+                       ret.rMax = Math.max(ret.rMax, r);\r
+               }\r
+               ret.xSize = ret.xMax - ret.xMin;\r
+               ret.ySize = ret.yMax - ret.yMin;\r
+               ret.zSize = ret.zMax - ret.zMin;\r
+               return ret;\r
+       }\r
+\r
+       private void setupView(GL2 gl, GLU glu) {\r
+               log.verbose("GL - setupView() called");\r
+               gl.glLoadIdentity();\r
+\r
+               gl.glLightfv(GLLightingFunc.GL_LIGHT1, GLLightingFunc.GL_POSITION,\r
+                               lightPosition, 0);\r
+\r
+               // Get the bounds\r
+               Bounds b = calculateBounds();\r
+\r
+               // Calculate the distance needed to fit the bounds in both the X and Y\r
+               // direction\r
+               // Add 10% for space around it.\r
+               double dX = (b.xSize * 1.2 / 2.0)\r
+                               / Math.tan(Math.toRadians(fovX / 2.0));\r
+               double dY = (b.rMax * 2.0 * 1.2 / 2.0)\r
+                               / Math.tan(Math.toRadians(fovY / 2.0));\r
+\r
+               // Move back the greater of the 2 distances\r
+               glu.gluLookAt(0, 0, Math.max(dX, dY), 0, 0, 0, 0, 1, 0);\r
+\r
+               gl.glRotated(yaw * (180.0 / Math.PI), 0, 1, 0);\r
+               gl.glRotated(roll * (180.0 / Math.PI), 1, 0, 0);\r
+\r
+               // Center the rocket in the view.\r
+               gl.glTranslated(-b.xMin - b.xSize / 2.0, 0, 0);\r
+               \r
+               //Change to LEFT Handed coordinates\r
+               gl.glScaled(1, 1, -1);\r
+               gl.glFrontFace(GL.GL_CW);\r
+               \r
+               //Flip textures for LEFT handed coords\r
+               gl.glMatrixMode(GL.GL_TEXTURE);\r
+               gl.glLoadIdentity();\r
+               gl.glScaled(-1,1,1);\r
+               gl.glTranslated(-1,0,0);\r
+               gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);\r
+               \r
+               log.verbose("GL - setupView() complete");\r
+       }\r
+\r
+       /**\r
+        * Call when the rocket has changed\r
+        */\r
+       public void updateFigure() {\r
+               log.debug("3D Figure Updated");\r
+               rr.updateFigure();\r
+               internalRepaint();\r
+       }\r
+\r
+       private void internalRepaint(){\r
+               log.verbose("GL - internalRepaint() called");\r
+               super.repaint();\r
+               if (canvas != null)\r
+                       canvas.display();\r
+               log.verbose("GL - internalRepaint() complete");\r
+       }\r
+       \r
+       @Override\r
+       public void repaint() {\r
+               log.verbose("GL - repaint() called");\r
+               redrawExtras = true;\r
+               internalRepaint();\r
+               log.verbose("GL - repaint() complete");\r
+       }\r
+\r
+       private Set<RocketComponent> selection = new HashSet<RocketComponent>();\r
+\r
+       public void setSelection(RocketComponent[] selection) {\r
+               this.selection.clear();\r
+               if (selection != null) {\r
+                       for (RocketComponent c : selection)\r
+                               this.selection.add(c);\r
+               }\r
+               internalRepaint();\r
+       }\r
+\r
+       private void setRoll(double rot) {\r
+               if (MathUtil.equals(roll, rot))\r
+                       return;\r
+               this.roll = MathUtil.reduce360(rot);\r
+               internalRepaint();\r
+       }\r
+\r
+       private void setYaw(double rot) {\r
+               if (MathUtil.equals(yaw, rot))\r
+                       return;\r
+               this.yaw = MathUtil.reduce360(rot);\r
+               internalRepaint();\r
+       }\r
+\r
+       // ///////////// Extra methods\r
+\r
+       private Coordinate project(Coordinate c, GL2 gl, GLU glu) {\r
+               log.verbose("GL - project() called");\r
+               double[] mvmatrix = new double[16];\r
+               double[] projmatrix = new double[16];\r
+               int[] viewport = new int[4];\r
+\r
+               gl.glGetIntegerv(GL.GL_VIEWPORT, viewport, 0);\r
+               gl.glGetDoublev(GLMatrixFunc.GL_MODELVIEW_MATRIX, mvmatrix, 0);\r
+               gl.glGetDoublev(GLMatrixFunc.GL_PROJECTION_MATRIX, projmatrix, 0);\r
+\r
+               double out[] = new double[4];\r
+               glu.gluProject(c.x, c.y, c.z, mvmatrix, 0, projmatrix, 0, viewport, 0,\r
+                               out, 0);\r
+               \r
+               log.verbose("GL - peoject() complete");\r
+               return new Coordinate(out[0], out[1], out[2]);\r
+               \r
+       }\r
+\r
+       private Coordinate cp = new Coordinate(0, 0, 0);\r
+       private Coordinate cg = new Coordinate(0, 0, 0);\r
+\r
+       public void setCG(Coordinate cg) {\r
+               this.cg = cg;\r
+               redrawExtras = true;\r
+       }\r
+\r
+       public void setCP(Coordinate cp) {\r
+               this.cp = cp;\r
+               redrawExtras = true;\r
+       }\r
+\r
+       public void addRelativeExtra(FigureElement p) {\r
+               relativeExtra.add(p);\r
+               redrawExtras = true;\r
+       }\r
+\r
+       public void removeRelativeExtra(FigureElement p) {\r
+               relativeExtra.remove(p);\r
+               redrawExtras = true;\r
+       }\r
+\r
+       public void clearRelativeExtra() {\r
+               relativeExtra.clear();\r
+               redrawExtras = true;\r
+       }\r
+\r
+       public void addAbsoluteExtra(FigureElement p) {\r
+               absoluteExtra.add(p);\r
+               redrawExtras = true;\r
+       }\r
+\r
+       public void removeAbsoluteExtra(FigureElement p) {\r
+               absoluteExtra.remove(p);\r
+               redrawExtras = true;\r
+       }\r
+\r
+       public void clearAbsoluteExtra() {\r
+               absoluteExtra.clear();\r
+               redrawExtras = true;\r
+       }\r
+\r
+       private ComponentSelectionListener csl;\r
+\r
+       public static interface ComponentSelectionListener {\r
+               public void componentClicked(RocketComponent[] components, MouseEvent e);\r
+       }\r
+\r
+       public void addComponentSelectionListener(\r
+                       ComponentSelectionListener newListener) {\r
+               this.csl = newListener;\r
+       }\r
+\r
+}\r
diff --git a/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java b/core/src/net/sf/openrocket/gui/figure3d/RocketRenderer.java
new file mode 100644 (file)
index 0000000..4934102
--- /dev/null
@@ -0,0 +1,303 @@
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import java.awt.Point;\r
+import java.nio.ByteBuffer;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Set;\r
+import java.util.Vector;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+import javax.media.opengl.GL2ES1;\r
+import javax.media.opengl.GL2GL3;\r
+import javax.media.opengl.GLAutoDrawable;\r
+import javax.media.opengl.fixedfunc.GLLightingFunc;\r
+\r
+import net.sf.openrocket.motor.Motor;\r
+import net.sf.openrocket.rocketcomponent.BodyTube;\r
+import net.sf.openrocket.rocketcomponent.Configuration;\r
+import net.sf.openrocket.rocketcomponent.ExternalComponent;\r
+import net.sf.openrocket.rocketcomponent.MotorMount;\r
+import net.sf.openrocket.rocketcomponent.NoseCone;\r
+import net.sf.openrocket.rocketcomponent.RocketComponent;\r
+import net.sf.openrocket.rocketcomponent.SymmetricComponent;\r
+import net.sf.openrocket.rocketcomponent.Transition;\r
+import net.sf.openrocket.startup.Application;\r
+import net.sf.openrocket.util.Color;\r
+import net.sf.openrocket.util.Coordinate;\r
+\r
+/*\r
+ * @author Bill Kuker <bkuker@billkuker.com>\r
+ */\r
+public class RocketRenderer {\r
+       ComponentRenderer cr;\r
+\r
+       private final float[] selectedEmissive = { 1, 0, 0, 1 };\r
+       private final float[] colorBlack = { 0, 0, 0, 1 };\r
+       private final float[] color = new float[4];\r
+\r
+       public void init(GLAutoDrawable drawable) {\r
+               cr = new ComponentRenderer();\r
+               cr.init(drawable);\r
+       }\r
+       \r
+       public void updateFigure() {\r
+               cr.updateFigure();\r
+       }\r
+\r
+       private boolean isDrawn(RocketComponent c) {\r
+               return true;\r
+       }\r
+\r
+       private boolean isDrawnTransparent(RocketComponent c) {\r
+               if (c instanceof BodyTube)\r
+                       return true;\r
+               if (c instanceof NoseCone)\r
+                       return false;\r
+               if (c instanceof SymmetricComponent) {\r
+                       if (((SymmetricComponent) c).isFilled())\r
+                               return false;\r
+               }\r
+               if (c instanceof Transition) {\r
+                       Transition t = (Transition) c;\r
+                       return !t.isAftShoulderCapped() && !t.isForeShoulderCapped();\r
+               }\r
+               return false;\r
+       }\r
+\r
+       public RocketComponent pick(GLAutoDrawable drawable,\r
+                       Configuration configuration, Point p, Set<RocketComponent> ignore) {\r
+               final GL2 gl = drawable.getGL().getGL2();\r
+               gl.glEnable(GL.GL_DEPTH_TEST);\r
+               \r
+               //Store a vector of pickable parts.\r
+               final Vector<RocketComponent> pickParts = new Vector<RocketComponent>();\r
+               \r
+               for (RocketComponent c : configuration) {\r
+                       if ( ignore != null && ignore.contains(c) )\r
+                               continue;\r
+\r
+                       //Encode the index of the part as a color\r
+                       //if index is 0x0ABC the color ends up as\r
+                       //0xA0B0C000 with each nibble in the coresponding\r
+                       //high bits of the RG and B channels.\r
+                       gl.glColor4ub((byte) ((pickParts.size() >> 4) & 0xF0),\r
+                                       (byte) ((pickParts.size() << 0) & 0xF0),\r
+                                       (byte) ((pickParts.size() << 4) & 0xF0), (byte) 1);\r
+                       pickParts.add(c);\r
+                       \r
+                       if (isDrawnTransparent(c)) {\r
+                               gl.glEnable(GL.GL_CULL_FACE);\r
+                               gl.glCullFace(GL.GL_FRONT);\r
+                               cr.renderGeometry(gl, c);\r
+                               gl.glDisable(GL.GL_CULL_FACE);\r
+                       } else {\r
+                               cr.renderGeometry(gl, c);\r
+                       }\r
+               }\r
+\r
+               ByteBuffer bb = ByteBuffer.allocateDirect(4);\r
+\r
+               gl.glReadPixels(p.x, p.y, 1, 1, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, bb);\r
+\r
+               final int pickColor = bb.getInt();\r
+               final int pickIndex = ((pickColor >> 20) & 0xF00) | ((pickColor >> 16) & 0x0F0)\r
+                               | ((pickColor >> 12) & 0x00F);\r
+\r
+               if ( pickIndex < 0 || pickIndex > pickParts.size() - 1 )\r
+                       return null;\r
+               \r
+               return pickParts.get(pickIndex);\r
+       }\r
+\r
+       public void render(GLAutoDrawable drawable, Configuration configuration,\r
+                       Set<RocketComponent> selection) {\r
+               if (cr == null)\r
+                       throw new IllegalStateException(this + " Not Initialized");\r
+\r
+               GL2 gl = drawable.getGL().getGL2();\r
+\r
+               gl.glEnable(GL.GL_DEPTH_TEST); // enables depth testing\r
+               gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);\r
+\r
+               // Draw all inner components\r
+               for (RocketComponent c : configuration) {\r
+                       if (isDrawn(c)) {\r
+                               if (!isDrawnTransparent(c)) {\r
+                                       renderComponent(gl, c, 1.0f);\r
+                               }\r
+                       }\r
+               }\r
+\r
+               renderMotors(gl, configuration);\r
+\r
+               // Draw Tube and Transition back faces, blended with depth test\r
+               // so that they show up behind.\r
+               gl.glEnable(GL.GL_CULL_FACE);\r
+               gl.glCullFace(GL.GL_FRONT);\r
+               for (RocketComponent c : configuration) {\r
+                       if (isDrawn(c)) {\r
+                               if (isDrawnTransparent(c)) {\r
+                                       renderComponent(gl, c, 1.0f);\r
+                               }\r
+                       }\r
+               }\r
+               gl.glDisable(GL.GL_CULL_FACE);\r
+\r
+               // Draw T&T front faces blended, without depth test\r
+               gl.glEnable(GL.GL_BLEND);\r
+               gl.glEnable(GL.GL_CULL_FACE);\r
+               gl.glCullFace(GL.GL_BACK);\r
+               for (RocketComponent c : configuration) {\r
+                       if (isDrawn(c)) {\r
+                               if (isDrawnTransparent(c)) {\r
+                                       renderComponent(gl, c, 0.2f);\r
+                               }\r
+                       }\r
+               }\r
+               gl.glDisable(GL.GL_BLEND);\r
+               gl.glDisable(GL.GL_CULL_FACE);\r
+\r
+               gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION,\r
+                               selectedEmissive, 0);\r
+               gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_DIFFUSE, colorBlack, 0);\r
+               gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_AMBIENT, colorBlack, 0);\r
+               gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_SPECULAR, colorBlack, 0);\r
+               \r
+               gl.glDepthMask(false);\r
+               gl.glDisable(GL.GL_DEPTH_TEST);\r
+               gl.glEnable(GL.GL_STENCIL_TEST);\r
+\r
+               for (RocketComponent c : configuration) {\r
+                       if (selection.contains(c)) {\r
+                               // So it is faster to do this once before the loop,\r
+                               // but then the outlines are not as good if you multi-select.\r
+                               // Not sure which to do.\r
+\r
+                               gl.glStencilMask(1);\r
+                               gl.glDisable(GL.GL_SCISSOR_TEST);\r
+                               gl.glClearStencil(0);\r
+                               gl.glClear(GL.GL_STENCIL_BUFFER_BIT);\r
+                               gl.glStencilMask(0);\r
+\r
+                               gl.glStencilFunc(GL.GL_ALWAYS, 1, 1);\r
+                               gl.glStencilMask(1);\r
+                               gl.glColorMask(false, false, false, false);\r
+                               gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL);\r
+                               gl.glStencilOp(GL.GL_KEEP, GL.GL_KEEP, GL.GL_REPLACE);\r
+                               cr.renderGeometry(gl, c);\r
+                               gl.glStencilMask(0);\r
+\r
+                               gl.glColorMask(true, true, true, true);\r
+                               gl.glStencilFunc(GL.GL_NOTEQUAL, 1, 1);\r
+                               gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE);\r
+                               gl.glLineWidth(5.0f);\r
+                               cr.renderGeometry(gl, c);\r
+                       }\r
+               }\r
+               gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL);\r
+               gl.glDepthMask(true);\r
+               gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GLLightingFunc.GL_EMISSION,\r
+                               colorBlack, 0);\r
+               gl.glDisable(GL.GL_STENCIL_TEST);\r
+               gl.glEnable(GL.GL_DEPTH_TEST);\r
+       }\r
+\r
+       private void renderMotors(GL2 gl, Configuration configuration) {\r
+               String motorID = configuration.getMotorConfigurationID();\r
+               Iterator<MotorMount> iterator = configuration.motorIterator();\r
+               while (iterator.hasNext()) {\r
+                       MotorMount mount = iterator.next();\r
+                       Motor motor = mount.getMotor(motorID);\r
+                       double length = motor.getLength();\r
+                       double radius = motor.getDiameter() / 2;\r
+\r
+                       Coordinate[] position = ((RocketComponent) mount)\r
+                                       .toAbsolute(new Coordinate(((RocketComponent) mount)\r
+                                                       .getLength() + mount.getMotorOverhang() - length));\r
+\r
+                       for (int i = 0; i < position.length; i++) {\r
+                               cr.renderMotor(gl, position[i], length, radius);\r
+                       }\r
+               }\r
+\r
+       }\r
+\r
+       \r
+       public void renderComponent(GL2 gl, RocketComponent c, float alpha) {\r
+               gl.glLightModeli(GL2ES1.GL_LIGHT_MODEL_TWO_SIDE, 1);\r
+\r
+               getOutsideColor(c, alpha, color);\r
+               gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_DIFFUSE, color, 0);\r
+               gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_AMBIENT, color, 0);\r
+\r
+               getSpecularColor(c, alpha, color);\r
+               gl.glMaterialfv(GL.GL_FRONT, GLLightingFunc.GL_SPECULAR, color, 0);\r
+               gl.glMateriali(GL.GL_FRONT, GLLightingFunc.GL_SHININESS,\r
+                               getShininess(c));\r
+\r
+               getInsideColor(c, alpha, color);\r
+               gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_DIFFUSE, color, 0);\r
+               gl.glMaterialfv(GL.GL_BACK, GLLightingFunc.GL_AMBIENT, color, 0);\r
+\r
+               cr.renderGeometry(gl, c);\r
+       }\r
+\r
+       private int getShininess(RocketComponent c) {\r
+               if (c instanceof ExternalComponent) {\r
+                       switch (((ExternalComponent) c).getFinish()) {\r
+                       case ROUGH:\r
+                               return 10;\r
+                       case UNFINISHED:\r
+                               return 30;\r
+                       case NORMAL:\r
+                               return 40;\r
+                       case SMOOTH:\r
+                               return 80;\r
+                       case POLISHED:\r
+                               return 128;\r
+                       }\r
+                       return 100;\r
+               } else {\r
+                       return 20;\r
+               }\r
+       }\r
+\r
+       private void getSpecularColor(RocketComponent c, float alpha, float[] out) {\r
+               int shine = getShininess(c);\r
+               float m = (float) shine / 128.0f;\r
+               float d = 0.9f;\r
+               getOutsideColor(c, alpha, out);\r
+               out[0] = Math.max(out[0], d) * m;\r
+               out[1] = Math.max(out[1], d) * m;\r
+               out[2] = Math.max(out[2], d) * m;\r
+       }\r
+\r
+       private void getInsideColor(RocketComponent c, float alpha, float[] out) {\r
+               float d = 0.4f;\r
+               getOutsideColor(c, alpha, out);\r
+               out[0] *= d;\r
+               out[1] *=  d;\r
+               out[2] *= d;\r
+       }\r
+\r
+       private HashMap<Class<?>, Color> defaultColorCache = new HashMap<Class<?>, Color>();\r
+       private void getOutsideColor(RocketComponent c, float alpha, float[] out) {\r
+               Color col;\r
+               col = c.getColor();\r
+               if (col == null){\r
+                       if ( defaultColorCache.containsKey(c.getClass()) ){\r
+                               col = defaultColorCache.get(c.getClass());\r
+                       } else {\r
+                               col = Application.getPreferences().getDefaultColor(c.getClass());\r
+                               defaultColorCache.put(c.getClass(), col);\r
+                       }\r
+               }\r
+                       \r
+               out[0] = Math.max(0.2f, (float) col.getRed() / 255f);\r
+               out[1] = Math.max(0.2f, (float) col.getGreen() / 255f);\r
+               out[2] = Math.max(0.2f, (float) col.getBlue() / 255f);\r
+               out[3] = alpha;\r
+       }\r
+}\r
diff --git a/core/src/net/sf/openrocket/gui/figure3d/TransitionRenderer.java b/core/src/net/sf/openrocket/gui/figure3d/TransitionRenderer.java
new file mode 100644 (file)
index 0000000..3789a78
--- /dev/null
@@ -0,0 +1,247 @@
+/*\r
+ ** License Applicability. Except to the extent portions of this file are\r
+ ** made subject to an alternative license as permitted in the SGI Free\r
+ ** Software License B, Version 2.0 (the "License"), the contents of this\r
+ ** file are subject only to the provisions of the License. You may not use\r
+ ** this file except in compliance with the License. You may obtain a copy\r
+ ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600\r
+ ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:\r
+ ** \r
+ ** http://oss.sgi.com/projects/FreeB\r
+ ** \r
+ ** Note that, as provided in the License, the Software is distributed on an\r
+ ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS\r
+ ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND\r
+ ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A\r
+ ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.\r
+ ** \r
+ ** NOTE:  The Original Code (as defined below) has been licensed to Sun\r
+ ** Microsystems, Inc. ("Sun") under the SGI Free Software License B\r
+ ** (Version 1.1), shown above ("SGI License").   Pursuant to Section\r
+ ** 3.2(3) of the SGI License, Sun is distributing the Covered Code to\r
+ ** you under an alternative license ("Alternative License").  This\r
+ ** Alternative License includes all of the provisions of the SGI License\r
+ ** except that Section 2.2 and 11 are omitted.  Any differences between\r
+ ** the Alternative License and the SGI License are offered solely by Sun\r
+ ** and not by SGI.\r
+ **\r
+ ** Original Code. The Original Code is: OpenGL Sample Implementation,\r
+ ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,\r
+ ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.\r
+ ** Copyright in any portions created by third parties is as indicated\r
+ ** elsewhere herein. All Rights Reserved.\r
+ ** \r
+ ** Additional Notice Provisions: The application programming interfaces\r
+ ** established by SGI in conjunction with the Original Code are The\r
+ ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released\r
+ ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version\r
+ ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X\r
+ ** Window System(R) (Version 1.3), released October 19, 1998. This software\r
+ ** was created using the OpenGL(R) version 1.2.1 Sample Implementation\r
+ ** published by SGI, but has not been independently verified as being\r
+ ** compliant with the OpenGL(R) version 1.2.1 Specification.\r
+ **\r
+ ** $Date: 2009-03-04 17:23:34 -0800 (Wed, 04 Mar 2009) $ $Revision: 1856 $\r
+ ** $Header$\r
+ */\r
+\r
+/* \r
+ * Copyright (c) 2002-2004 LWJGL Project\r
+ * All rights reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are \r
+ * met:\r
+ * \r
+ * * Redistributions of source code must retain the above copyright \r
+ *   notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * * Redistributions in binary form must reproduce the above copyright\r
+ *   notice, this list of conditions and the following disclaimer in the\r
+ *   documentation and/or other materials provided with the distribution.\r
+ *\r
+ * * Neither the name of 'LWJGL' nor the names of \r
+ *   its contributors may be used to endorse or promote products derived \r
+ *   from this software without specific prior written permission.\r
+ * \r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\r
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR \r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, \r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR \r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING \r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.\r
+ * \r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions are\r
+ * met:\r
+ * \r
+ * - Redistribution of source code must retain the above copyright\r
+ *   notice, this list of conditions and the following disclaimer.\r
+ * \r
+ * - Redistribution in binary form must reproduce the above copyright\r
+ *   notice, this list of conditions and the following disclaimer in the\r
+ *   documentation and/or other materials provided with the distribution.\r
+ * \r
+ * Neither the name of Sun Microsystems, Inc. or the names of\r
+ * contributors may be used to endorse or promote products derived from\r
+ * this software without specific prior written permission.\r
+ * \r
+ * This software is provided "AS IS," without a warranty of any kind. ALL\r
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,\r
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A\r
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN\r
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR\r
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR\r
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR\r
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR\r
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE\r
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,\r
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF\r
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\r
+ * \r
+ * You acknowledge that this software is not designed or intended for use\r
+ * in the design, construction, operation or maintenance of any nuclear\r
+ * facility.\r
+ */\r
+package net.sf.openrocket.gui.figure3d;\r
+\r
+import javax.media.opengl.GL;\r
+import javax.media.opengl.GL2;\r
+\r
+import net.sf.openrocket.rocketcomponent.Transition;\r
+\r
+public final class TransitionRenderer {\r
+       private static final boolean textureFlag = true;\r
+\r
+       private TransitionRenderer() {\r
+       }\r
+\r
+       public static final void drawTransition(final GL2 gl, final Transition tr,\r
+                       final int slices, final int stacks) {\r
+\r
+               double da, r, dz;\r
+               double x, y, z, nz, nsign;\r
+               int i, j;\r
+\r
+               nsign = 1.0f;\r
+\r
+               da = 2.0f * PI / slices;\r
+               dz = (double) tr.getLength() / stacks;\r
+\r
+               double ds = 1.0f / slices;\r
+               double dt = 1.0f / stacks;\r
+               double t = 0.0f;\r
+               z = 0.0f;\r
+               r = (double) tr.getForeRadius();\r
+               for (j = 0; j < stacks; j++) {\r
+                       r = (double) tr.getRadius(z);\r
+                       double rNext = (double) tr.getRadius(z + dz);\r
+\r
+                       if (j == stacks - 1)\r
+                               rNext = (double) tr.getRadius(tr.getLength());\r
+\r
+                       // Z component of normal vectors\r
+                       nz = -(rNext - r) / dz;\r
+\r
+                       double s = 0.0f;\r
+                       glBegin(gl, GL2.GL_QUAD_STRIP);\r
+                       for (i = 0; i <= slices; i++) {\r
+                               if (i == slices) {\r
+                                       x = sin(0.0f);\r
+                                       y = cos(0.0f);\r
+                               } else {\r
+                                       x = sin((i * da));\r
+                                       y = cos((i * da));\r
+                               }\r
+                               if (nsign == 1.0f) {\r
+                                       normal3d(gl, (x * nsign), (y * nsign), (nz * nsign));\r
+                                       TXTR_COORD(gl, s, t);\r
+                                       glVertex3d(gl, (x * r), (y * r), z);\r
+                                       normal3d(gl, (x * nsign), (y * nsign), (nz * nsign));\r
+                                       TXTR_COORD(gl, s, t + dt);\r
+                                       glVertex3d(gl, (x * rNext), (y * rNext), (z + dz));\r
+                               } else {\r
+                                       normal3d(gl, x * nsign, y * nsign, nz * nsign);\r
+                                       TXTR_COORD(gl, s, t);\r
+                                       glVertex3d(gl, (x * r), (y * r), z);\r
+                                       normal3d(gl, x * nsign, y * nsign, nz * nsign);\r
+                                       TXTR_COORD(gl, s, t + dt);\r
+                                       glVertex3d(gl, (x * rNext), (y * rNext), (z + dz));\r
+                               }\r
+                               s += ds;\r
+                       } // for slices\r
+                       glEnd(gl);\r
+                       // r += dr;\r
+                       t += dt;\r
+                       z += dz;\r
+               } // for stacks\r
+\r
+       }\r
+\r
+       // ----------------------------------------------------------------------\r
+       // Internals only below this point\r
+       //\r
+\r
+       private static final double PI = (double) Math.PI;\r
+\r
+       private static final void glBegin(GL gl, int mode) {\r
+               gl.getGL2().glBegin(mode);\r
+       }\r
+\r
+       private static final void glEnd(GL gl) {\r
+               gl.getGL2().glEnd();\r
+       }\r
+\r
+       private static final void glVertex3d(GL gl, double x, double y, double z) {\r
+               gl.getGL2().glVertex3d(x, y, z);\r
+       }\r
+\r
+       private static final void glNormal3d(GL gl, double x, double y, double z) {\r
+               gl.getGL2().glNormal3d(x, y, z);\r
+       }\r
+\r
+       private static final void glTexCoord2d(GL gl, double x, double y) {\r
+               gl.getGL2().glTexCoord2d(x, y);\r
+       }\r
+\r
+       /**\r
+        * Call glNormal3f after scaling normal to unit length.\r
+        * \r
+        * @param x\r
+        * @param y\r
+        * @param z\r
+        */\r
+       private static final void normal3d(GL gl, double x, double y, double z) {\r
+               double mag;\r
+\r
+               mag = (double) Math.sqrt(x * x + y * y + z * z);\r
+               if (mag > 0.00001F) {\r
+                       x /= mag;\r
+                       y /= mag;\r
+                       z /= mag;\r
+               }\r
+               glNormal3d(gl, x, y, z);\r
+       }\r
+\r
+       private static final void TXTR_COORD(GL gl, double x, double y) {\r
+               if (textureFlag)\r
+                       glTexCoord2d(gl, x, y);\r
+       }\r
+\r
+       private static final double sin(double r) {\r
+               return (double) Math.sin(r);\r
+       }\r
+\r
+       private static final double cos(double r) {\r
+               return (double) Math.cos(r);\r
+       }\r
+}\r
index c05c1ba34dd82b9a39ded5737a5d2a9336445bb3..bdfcbd4a0a8a9218acacbf1c539b8d42bdc04005 100644 (file)
@@ -1,62 +1,5 @@
 package net.sf.openrocket.gui.main;
 
-import java.awt.Dimension;
-import java.awt.Font;
-import java.awt.Toolkit;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLDecoder;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.concurrent.ExecutionException;
-
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.InputMap;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JFileChooser;
-import javax.swing.JFrame;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JPopupMenu;
-import javax.swing.JScrollPane;
-import javax.swing.JSpinner;
-import javax.swing.JSplitPane;
-import javax.swing.JTabbedPane;
-import javax.swing.JTextField;
-import javax.swing.KeyStroke;
-import javax.swing.ListSelectionModel;
-import javax.swing.ScrollPaneConstants;
-import javax.swing.SwingUtilities;
-import javax.swing.border.BevelBorder;
-import javax.swing.border.TitledBorder;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.DefaultTreeSelectionModel;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.TreeSelectionModel;
-
 import net.miginfocom.swing.MigLayout;
 import net.sf.openrocket.aerodynamics.WarningSet;
 import net.sf.openrocket.document.OpenRocketDocument;
@@ -68,6 +11,7 @@ import net.sf.openrocket.file.openrocket.OpenRocketSaver;
 import net.sf.openrocket.file.rocksim.export.RocksimSaver;
 import net.sf.openrocket.gui.StorageOptionChooser;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
+import net.sf.openrocket.gui.customexpression.CustomExpressionDialog;
 import net.sf.openrocket.gui.dialogs.AboutDialog;
 import net.sf.openrocket.gui.dialogs.BugReportDialog;
 import net.sf.openrocket.gui.dialogs.ComponentAnalysisDialog;
@@ -105,149 +49,194 @@ import net.sf.openrocket.util.MemoryManagement.MemoryData;
 import net.sf.openrocket.util.Reflection;
 import net.sf.openrocket.util.TestRockets;
 
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.InputMap;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
+import javax.swing.JScrollPane;
+import javax.swing.JSpinner;
+import javax.swing.JSplitPane;
+import javax.swing.JTabbedPane;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.SwingUtilities;
+import javax.swing.border.BevelBorder;
+import javax.swing.border.TitledBorder;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultTreeSelectionModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
 public class BasicFrame extends JFrame {
        private static final LogHelper log = Application.getLogger();
-       
+
        /**
         * The RocketLoader instance used for loading all rocket designs.
         */
        private static final RocketLoader ROCKET_LOADER = new GeneralRocketLoader();
-       
+
        private static final RocketSaver ROCKET_SAVER = new OpenRocketSaver();
-       
+
        private static final Translator trans = Application.getTranslator();
-       
+
        public static final int COMPONENT_TAB = 0;
        public static final int SIMULATION_TAB = 1;
-       
-       
+
+
        /**
         * List of currently open frames.  When the list goes empty
         * it is time to exit the application.
         */
        private static final ArrayList<BasicFrame> frames = new ArrayList<BasicFrame>();
-       
-       
+
+
        /**
         * Whether "New" and "Open" should replace this frame.
         * Should be set to false on the first rocket modification.
         */
        private boolean replaceable = false;
-       
-       
-       
+
+
+
        private final OpenRocketDocument document;
        private final Rocket rocket;
-       
+
        private JTabbedPane tabbedPane;
        private RocketPanel rocketpanel;
        private ComponentTree tree = null;
-       
+
        private final DocumentSelectionModel selectionModel;
        private final TreeSelectionModel componentSelectionModel;
        private final ListSelectionModel simulationSelectionModel;
-       
+
        /** Actions available for rocket modifications */
        private final RocketActions actions;
-       
-       
-       
-       
+
+
+
+
        /**
         * Sole constructor.  Creates a new frame based on the supplied document
         * and adds it to the current frames list.
-        * 
+        *
         * @param document      the document to show.
         */
        public BasicFrame(OpenRocketDocument document) {
                log.debug("Instantiating new BasicFrame");
-               
+
                this.document = document;
                this.rocket = document.getRocket();
                this.rocket.getDefaultConfiguration().setAllStages();
-               
-               
-               // Set replaceable flag to false at first modification
-               rocket.addComponentChangeListener(new ComponentChangeListener() {
-                       @Override
-                       public void componentChanged(ComponentChangeEvent e) {
-                               replaceable = false;
-                               BasicFrame.this.rocket.removeComponentChangeListener(this);
-                       }
-               });
-               
-               
+
                // Create the component tree selection model that will be used
                componentSelectionModel = new DefaultTreeSelectionModel();
                componentSelectionModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
-               
+
                // Obtain the simulation selection model that will be used
                SimulationPanel simulationPanel = new SimulationPanel(document);
                simulationSelectionModel = simulationPanel.getSimulationListSelectionModel();
-               
+
                // Combine into a DocumentSelectionModel
                selectionModel = new DocumentSelectionModel(document);
                selectionModel.attachComponentTreeSelectionModel(componentSelectionModel);
                selectionModel.attachSimulationListSelectionModel(simulationSelectionModel);
-               
-               
+
+
                actions = new RocketActions(document, selectionModel, this);
-               
-               
+
+
                log.debug("Constructing the BasicFrame UI");
-               
-               // The main vertical split pane         
+
+               // The main vertical split pane
                JSplitPane vertical = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true);
                vertical.setResizeWeight(0.5);
                this.add(vertical);
-               
-               
+
+
                // The top tabbed pane
                tabbedPane = new JTabbedPane();
                //// Rocket design
                tabbedPane.addTab(trans.get("BasicFrame.tab.Rocketdesign"), null, designTab());
                //// Flight simulations
                tabbedPane.addTab(trans.get("BasicFrame.tab.Flightsim"), null, simulationPanel);
-               
+
                vertical.setTopComponent(tabbedPane);
-               
-               
-               
+
+
+
                //  Bottom segment, rocket figure
-               
+
                rocketpanel = new RocketPanel(document);
                vertical.setBottomComponent(rocketpanel);
-               
+
                rocketpanel.setSelectionModel(tree.getSelectionModel());
-               
-               
+
+
                createMenu();
-               
-               
+
+
                rocket.addComponentChangeListener(new ComponentChangeListener() {
                        @Override
                        public void componentChanged(ComponentChangeEvent e) {
                                setTitle();
                        }
                });
-               
+
                setTitle();
                this.pack();
-               
-               
+
+
                // Set initial window size
                Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
                size.width = size.width * 9 / 10;
                size.height = size.height * 9 / 10;
                this.setSize(size);
-               
+
                // Remember changed size
                GUIUtil.rememberWindowSize(this);
-               
+
                this.setLocationByPlatform(true);
-               
+
                GUIUtil.setWindowIcons(this);
-               
+
                this.validate();
                vertical.setDividerLocation(0.4);
                setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
@@ -257,12 +246,12 @@ public class BasicFrame extends JFrame {
                                closeAction();
                        }
                });
-               
+
                frames.add(this);
                log.debug("BasicFrame instantiation complete");
        }
-       
-       
+
+
        /**
         * Construct the "Rocket design" tab.  This contains a horizontal split pane
         * with the left component the design tree and the right component buttons
@@ -271,15 +260,15 @@ public class BasicFrame extends JFrame {
        private JComponent designTab() {
                JSplitPane horizontal = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true);
                horizontal.setResizeWeight(0.5);
-               
-               
+
+
                //  Upper-left segment, component tree
-               
+
                JPanel panel = new JPanel(new MigLayout("fill, flowy", "", "[grow]"));
-               
+
                tree = new ComponentTree(document);
                tree.setSelectionModel(componentSelectionModel);
-               
+
                // Remove JTree key events that interfere with menu accelerators
                InputMap im = SwingUtilities.getUIInputMap(tree, JComponent.WHEN_FOCUSED);
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.CTRL_MASK), null);
@@ -289,9 +278,9 @@ public class BasicFrame extends JFrame {
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK), null);
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK), null);
                im.put(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK), null);
-               
-               
-               
+
+
+
                // Double-click opens config dialog
                MouseListener ml = new MouseAdapter() {
                        @Override
@@ -309,7 +298,7 @@ public class BasicFrame extends JFrame {
                        }
                };
                tree.addMouseListener(ml);
-               
+
                // Update dialog when selection is changed
                componentSelectionModel.addTreeSelectionListener(new TreeSelectionListener() {
                        @Override
@@ -319,7 +308,7 @@ public class BasicFrame extends JFrame {
                                if (path == null)
                                        return;
                                tree.scrollPathToVisible(path);
-                               
+
                                if (!ComponentConfigDialog.isDialogVisible())
                                        return;
                                RocketComponent c = (RocketComponent) path.getLastPathComponent();
@@ -327,57 +316,57 @@ public class BasicFrame extends JFrame {
                                                BasicFrame.this.document, c);
                        }
                });
-               
+
                // Place tree inside scroll pane
                JScrollPane scroll = new JScrollPane(tree);
                panel.add(scroll, "spany, grow, wrap");
-               
-               
+
+
                // Buttons
                JButton button = new JButton(actions.getMoveUpAction());
                panel.add(button, "sizegroup buttons, aligny 65%");
-               
+
                button = new JButton(actions.getMoveDownAction());
                panel.add(button, "sizegroup buttons, aligny 0%");
-               
+
                button = new JButton(actions.getEditAction());
                panel.add(button, "sizegroup buttons");
-               
+
                button = new JButton(actions.getNewStageAction());
                panel.add(button, "sizegroup buttons");
-               
+
                button = new JButton(actions.getDeleteAction());
                button.setIcon(null);
                button.setMnemonic(0);
                panel.add(button, "sizegroup buttons");
-               
+
                horizontal.setLeftComponent(panel);
-               
-               
+
+
                //  Upper-right segment, component addition buttons
-               
+
                panel = new JPanel(new MigLayout("fill, insets 0", "[0::]"));
-               
+
                scroll = new JScrollPane(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
                scroll.setViewportView(new ComponentAddButtons(document, componentSelectionModel,
                                scroll.getViewport()));
                scroll.setBorder(null);
                scroll.setViewportBorder(null);
-               
+
                TitledBorder border = BorderFactory.createTitledBorder(trans.get("BasicFrame.title.Addnewcomp"));
                GUIUtil.changeFontStyle(border, Font.BOLD);
                scroll.setBorder(border);
-               
+
                panel.add(scroll, "grow");
-               
+
                horizontal.setRightComponent(panel);
-               
+
                return horizontal;
        }
-       
-       
-       
+
+
+
        /**
         * Return the currently selected rocket component, or <code>null</code> if none selected.
         */
@@ -386,11 +375,11 @@ public class BasicFrame extends JFrame {
                if (path == null)
                        return null;
                tree.scrollPathToVisible(path);
-               
+
                return (RocketComponent) path.getLastPathComponent();
        }
-       
-       
+
+
        /**
         * Creates the menu for the window.
         */
@@ -398,15 +387,15 @@ public class BasicFrame extends JFrame {
                JMenuBar menubar = new JMenuBar();
                JMenu menu;
                JMenuItem item;
-               
+
                ////  File
                menu = new JMenu(trans.get("main.menu.file"));
                menu.setMnemonic(KeyEvent.VK_F);
                //// File-handling related tasks
                menu.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.file.desc"));
                menubar.add(menu);
-               
-               //// New 
+
+               //// New
                item = new JMenuItem(trans.get("main.menu.file.new"), KeyEvent.VK_N);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK));
                item.setMnemonic(KeyEvent.VK_N);
@@ -418,14 +407,11 @@ public class BasicFrame extends JFrame {
                        public void actionPerformed(ActionEvent e) {
                                log.user("New... selected");
                                newAction();
-                               if (replaceable) {
-                                       log.info("Closing previous window");
-                                       closeAction();
-                               }
+                               closeIfReplaceable();
                        }
                });
                menu.add(item);
-               
+
                //// Open...
                item = new JMenuItem(trans.get("main.menu.file.open"), KeyEvent.VK_O);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
@@ -440,7 +426,14 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
+               //// Open Recent...
+               item = new MRUDesignFileAction(trans.get("main.menu.file.openRecent"), this);
+               //// Open a recent rocket design
+               item.getAccessibleContext().setAccessibleDescription(trans.get("BasicFrame.item.Openrecentrocketdesign"));
+               item.setIcon(Icons.FILE_OPEN);
+               menu.add(item);
+
                //// Open example...
                item = new JMenuItem(trans.get("main.menu.file.openExample"));
                //// Open an example rocket design
@@ -462,9 +455,9 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                menu.addSeparator();
-               
+
                //// Save
                item = new JMenuItem(trans.get("main.menu.file.save"), KeyEvent.VK_S);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
@@ -479,7 +472,7 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                //// Save as...
                item = new JMenuItem(trans.get("main.menu.file.saveAs"), KeyEvent.VK_A);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S,
@@ -495,7 +488,7 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                //// Print...
                item = new JMenuItem(trans.get("main.menu.file.print"), KeyEvent.VK_P);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.CTRL_MASK));
@@ -510,10 +503,10 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
+
+
                menu.addSeparator();
-               
+
                //// Close
                item = new JMenuItem(trans.get("main.menu.file.close"), KeyEvent.VK_C);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, ActionEvent.CTRL_MASK));
@@ -528,9 +521,9 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                menu.addSeparator();
-               
+
                //// Quit
                item = new JMenuItem(trans.get("main.menu.file.quit"), KeyEvent.VK_Q);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.CTRL_MASK));
@@ -545,26 +538,26 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
-               
+
+
+
                ////  Edit
                menu = new JMenu(trans.get("main.menu.edit"));
                menu.setMnemonic(KeyEvent.VK_E);
                //// Rocket editing
                menu.getAccessibleContext().setAccessibleDescription(trans.get("BasicFrame.menu.Rocketedt"));
                menubar.add(menu);
-               
-               
+
+
                Action action = UndoRedoAction.newUndoAction(document);
                item = new JMenuItem(action);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Z, ActionEvent.CTRL_MASK));
                item.setMnemonic(KeyEvent.VK_U);
                //// Undo the previous operation
                item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.edit.undo.desc"));
-               
+
                menu.add(item);
-               
+
                action = UndoRedoAction.newRedoAction(document);
                item = new JMenuItem(action);
                item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Y, ActionEvent.CTRL_MASK));
@@ -572,26 +565,26 @@ public class BasicFrame extends JFrame {
                //// Redo the previously undone operation
                item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.edit.redo.desc"));
                menu.add(item);
-               
+
                menu.addSeparator();
-               
-               
+
+
                item = new JMenuItem(actions.getCutAction());
                menu.add(item);
-               
+
                item = new JMenuItem(actions.getCopyAction());
                menu.add(item);
-               
+
                item = new JMenuItem(actions.getPasteAction());
                menu.add(item);
-               
+
                item = new JMenuItem(actions.getDeleteAction());
                menu.add(item);
-               
+
                menu.addSeparator();
-               
-               
-               
+
+
+
                item = new JMenuItem(trans.get("main.menu.edit.resize"));
                item.setIcon(Icons.EDIT_SCALE);
                item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.edit.resize.desc"));
@@ -605,9 +598,9 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
-               
+
+
+
                //// Preferences
                item = new JMenuItem(trans.get("main.menu.edit.preferences"));
                item.setIcon(Icons.PREFERENCES);
@@ -621,17 +614,17 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
-               
-               
+
+
+
+
                ////  Analyze
                menu = new JMenu(trans.get("main.menu.analyze"));
                menu.setMnemonic(KeyEvent.VK_A);
                //// Analyzing the rocket
                menu.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.analyze.desc"));
                menubar.add(menu);
-               
+
                //// Component analysis
                item = new JMenuItem(trans.get("main.menu.analyze.componentAnalysis"), KeyEvent.VK_C);
                //// Analyze the rocket components separately
@@ -644,39 +637,49 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
+
+               //// Optimize
                item = new JMenuItem(trans.get("main.menu.analyze.optimization"), KeyEvent.VK_O);
                item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.analyze.optimization.desc"));
                item.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
-                               log.user("Rocket optimization selected");
-                               new GeneralOptimizationDialog(document, BasicFrame.this).setVisible(true);
+                               log.user("Rocket optimization selected");
+                               new GeneralOptimizationDialog(document, BasicFrame.this).setVisible(true);
+                       }
+               });
+               menu.add(item);
+
+               //// Custom expressions
+               item = new JMenuItem(trans.get("main.menu.analyze.customExpressions"), KeyEvent.VK_E);
+               item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.analyze.customExpressions.desc"));
+               item.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               log.debug("Custom expressions selected");
+                               new CustomExpressionDialog(document, BasicFrame.this).setVisible(true);
                        }
                });
                menu.add(item);
-               
-               
-               
+
                ////  Debug
                // (shown if openrocket.debug.menu is defined)
                if (System.getProperty("openrocket.debug.menu") != null) {
                        menubar.add(makeDebugMenu());
                }
-               
-               
-               
+
+
+
                ////  Help
-               
+
                menu = new JMenu(trans.get("main.menu.help"));
                menu.setMnemonic(KeyEvent.VK_H);
                menu.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.help.desc"));
                menubar.add(menu);
-               
-               
+
+
                // Guided tours
-               
+
                item = new JMenuItem(trans.get("main.menu.help.tours"), KeyEvent.VK_L);
                item.setIcon(Icons.HELP_TOURS);
                item.getAccessibleContext().setAccessibleDescription(trans.get("main.menu.help.tours.desc"));
@@ -688,9 +691,9 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                menu.addSeparator();
-               
+
                //// Bug report
                item = new JMenuItem(trans.get("main.menu.help.bugReport"), KeyEvent.VK_B);
                item.setIcon(Icons.HELP_BUG_REPORT);
@@ -703,7 +706,7 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                //// Debug log
                item = new JMenuItem(trans.get("main.menu.help.debugLog"));
                item.setIcon(Icons.HELP_DEBUG_LOG);
@@ -716,10 +719,10 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                menu.addSeparator();
-               
-               
+
+
                //// License
                item = new JMenuItem(trans.get("main.menu.help.license"), KeyEvent.VK_L);
                item.setIcon(Icons.HELP_LICENSE);
@@ -732,8 +735,8 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
+
+
                //// About
                item = new JMenuItem(trans.get("main.menu.help.about"), KeyEvent.VK_A);
                item.setIcon(Icons.HELP_ABOUT);
@@ -746,24 +749,24 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
+
+
                this.setJMenuBar(menubar);
        }
-       
+
        private JMenu makeDebugMenu() {
                JMenu menu;
                JMenuItem item;
-               
+
                /*
                 * This menu is intentionally left untranslated.
                 */
-               
+
                ////  Debug menu
                menu = new JMenu("Debug");
                //// OpenRocket debugging tasks
                menu.getAccessibleContext().setAccessibleDescription("OpenRocket debugging tasks");
-               
+
                //// What is this menu?
                item = new JMenuItem("What is this menu?");
                item.addActionListener(new ActionListener() {
@@ -781,9 +784,9 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                menu.addSeparator();
-               
+
                //// Create test rocket
                item = new JMenuItem("Create test rocket");
                item.addActionListener(new ActionListener() {
@@ -798,7 +801,7 @@ public class BasicFrame extends JFrame {
                                                JOptionPane.QUESTION_MESSAGE, null, new Object[] {
                                                                "Random", "OK"
                                                }, "OK");
-                               
+
                                Rocket r;
                                if (sel == 0) {
                                        r = new TestRockets(null).makeTestRocket();
@@ -807,7 +810,7 @@ public class BasicFrame extends JFrame {
                                } else {
                                        return;
                                }
-                               
+
                                OpenRocketDocument doc = new OpenRocketDocument(r);
                                doc.setSaved(true);
                                BasicFrame frame = new BasicFrame(doc);
@@ -815,9 +818,9 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
-               
+
+
+
                item = new JMenuItem("Create 'Iso-Haisu'");
                item.addActionListener(new ActionListener() {
                        @Override
@@ -831,8 +834,8 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
+
+
                item = new JMenuItem("Create 'Big Blue'");
                item.addActionListener(new ActionListener() {
                        @Override
@@ -846,16 +849,16 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                menu.addSeparator();
-               
-               
+
+
                item = new JMenuItem("Memory statistics");
                item.addActionListener(new ActionListener() {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                log.user("Memory statistics selected");
-                               
+
                                // Get discarded but remaining objects (this also runs System.gc multiple times)
                                List<MemoryData> objects = MemoryManagement.getRemainingCollectableObjects();
                                StringBuilder sb = new StringBuilder();
@@ -872,7 +875,7 @@ public class BasicFrame extends JFrame {
                                        o = null;
                                }
                                sb.append("Total: " + count);
-                               
+
                                // Get basic memory stats
                                System.gc();
                                long max = Runtime.getRuntime().maxMemory();
@@ -883,14 +886,14 @@ public class BasicFrame extends JFrame {
                                stats[1] = String.format("   Max memory:  %.1f MB", max / 1024.0 / 1024.0);
                                stats[2] = String.format("   Used memory: %.1f MB (%.0f%%)", used / 1024.0 / 1024.0, 100.0 * used / max);
                                stats[3] = String.format("   Free memory: %.1f MB (%.0f%%)", free / 1024.0 / 1024.0, 100.0 * free / max);
-                               
-                               
+
+
                                DetailDialog.showDetailedMessageDialog(BasicFrame.this, stats, sb.toString(),
                                                "Memory statistics", JOptionPane.INFORMATION_MESSAGE);
                        }
                });
                menu.add(item);
-               
+
                //// Exhaust memory
                item = new JMenuItem("Exhaust memory");
                item.addActionListener(new ActionListener() {
@@ -920,10 +923,10 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
+
+
                menu.addSeparator();
-               
+
                //// Exception here
                item = new JMenuItem("Exception here");
                item.addActionListener(new ActionListener() {
@@ -934,7 +937,7 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                item = new JMenuItem("Exception from EDT");
                item.addActionListener(new ActionListener() {
                        @Override
@@ -950,7 +953,7 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                item = new JMenuItem("Exception from other thread");
                item.addActionListener(new ActionListener() {
                        @Override
@@ -965,7 +968,7 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
+
                item = new JMenuItem("OutOfMemoryError here");
                item.addActionListener(new ActionListener() {
                        @Override
@@ -975,11 +978,11 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
+
+
                menu.addSeparator();
-               
-               
+
+
                item = new JMenuItem("Test popup");
                item.addActionListener(new ActionListener() {
                        @Override
@@ -995,33 +998,33 @@ public class BasicFrame extends JFrame {
                        }
                });
                menu.add(item);
-               
-               
-               
-               
+
+
+
+
                return menu;
        }
-       
-       
+
+
        /**
         * Select the tab on the main pane.
-        * 
+        *
         * @param tab   one of {@link #COMPONENT_TAB} or {@link #SIMULATION_TAB}.
         */
        public void selectTab(int tab) {
                tabbedPane.setSelectedIndex(tab);
        }
-       
-       
-       
+
+
+
        private void openAction() {
                JFileChooser chooser = new JFileChooser();
-               
+
                chooser.addChoosableFileFilter(FileHelper.ALL_DESIGNS_FILTER);
                chooser.addChoosableFileFilter(FileHelper.OPENROCKET_DESIGN_FILTER);
                chooser.addChoosableFileFilter(FileHelper.ROCKSIM_DESIGN_FILTER);
                chooser.setFileFilter(FileHelper.ALL_DESIGNS_FILTER);
-               
+
                chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
                chooser.setMultiSelectionEnabled(true);
                chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
@@ -1030,31 +1033,33 @@ public class BasicFrame extends JFrame {
                        log.user("Decided not to open files, option=" + option);
                        return;
                }
-               
+
                ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
-               
+
                File[] files = chooser.getSelectedFiles();
                log.user("Opening files " + Arrays.toString(files));
-               
+
                for (File file : files) {
                        log.info("Opening file: " + file);
                        if (open(file, this)) {
-                               
-                               // Close previous window if replacing
-                               if (replaceable && document.isSaved()) {
-                                       // We are replacing the frame, make new window have current location
-                                       BasicFrame newFrame = frames.get(frames.size() - 1);
-                                       newFrame.setLocation(this.getLocation());
-                                       
-                                       log.info("Closing window because it is replaceable");
-                                       closeAction();
-                                       replaceable = false;
-                               }
+                MRUDesignFile opts = MRUDesignFile.getInstance();
+                opts.addFile(file.getAbsolutePath());
                        }
                }
        }
-       
-       
+
+       void closeIfReplaceable() {
+               // Close previous window if replacing
+               if (replaceable && document.isSaved()) {
+                       // We are replacing the frame, make new window have current location
+                       BasicFrame newFrame = frames.get(frames.size() - 1);
+                       newFrame.setLocation(this.getLocation());
+
+                       log.info("Closing window because it is replaceable");
+                       closeAction();
+               }
+               
+       }
        /**
         * Open a file based on a URL.
         * @param url           the file to open.
@@ -1063,16 +1068,16 @@ public class BasicFrame extends JFrame {
         */
        private static boolean open(URL url, BasicFrame parent) {
                String filename = null;
-               
+
                // First figure out the file name from the URL
-               
+
                // Try using URI.getPath();
                try {
                        URI uri = url.toURI();
                        filename = uri.getPath();
                } catch (URISyntaxException ignore) {
                }
-               
+
                // Try URL-decoding the URL
                if (filename == null) {
                        try {
@@ -1080,44 +1085,38 @@ public class BasicFrame extends JFrame {
                        } catch (UnsupportedEncodingException ignore) {
                        }
                }
-               
+
                // Last resort
                if (filename == null) {
                        filename = "";
                }
-               
+
                // Remove path from filename
                if (filename.lastIndexOf('/') >= 0) {
                        filename = filename.substring(filename.lastIndexOf('/') + 1);
                }
-               
-               
+
+
                // Open the file
                log.info("Opening file from url=" + url + " filename=" + filename);
                try {
                        InputStream is = url.openStream();
-                       if (open(is, filename, parent)) {
-                               // Close previous window if replacing
-                               if (parent.replaceable && parent.document.isSaved()) {
-                                       parent.closeAction();
-                                       parent.replaceable = false;
-                               }
-                       }
+                       open(is, filename, parent);
                } catch (IOException e) {
                        log.warn("Error opening file" + e);
                        JOptionPane.showMessageDialog(parent,
                                        "An error occurred while opening the file " + filename,
                                        "Error loading file", JOptionPane.ERROR_MESSAGE);
                }
-               
+
                return false;
        }
-       
-       
+
+
        /**
         * Open the specified file from an InputStream in a new design frame.  If an error
         * occurs, an error dialog is shown and <code>false</code> is returned.
-        * 
+        *
         * @param stream        the stream to load from.
         * @param filename      the file name to display in dialogs (not set to the document).
         * @param parent        the parent component for which a progress dialog is opened.
@@ -1127,12 +1126,12 @@ public class BasicFrame extends JFrame {
                OpenFileWorker worker = new OpenFileWorker(stream, ROCKET_LOADER);
                return open(worker, filename, null, parent);
        }
-       
-       
+
+
        /**
         * Open the specified file in a new design frame.  If an error occurs, an error
         * dialog is shown and <code>false</code> is returned.
-        * 
+        *
         * @param file          the file to open.
         * @param parent        the parent component for which a progress dialog is opened.
         * @return                      whether the file was successfully loaded and opened.
@@ -1141,11 +1140,11 @@ public class BasicFrame extends JFrame {
                OpenFileWorker worker = new OpenFileWorker(file, ROCKET_LOADER);
                return open(worker, file.getName(), file, parent);
        }
-       
-       
+
+
        /**
         * Open the specified file using the provided worker.
-        * 
+        *
         * @param worker        the OpenFileWorker that loads the file.
         * @param filename      the file name to display in dialogs.
         * @param file          the File to set the document to (may be null).
@@ -1153,9 +1152,9 @@ public class BasicFrame extends JFrame {
         * @return
         */
        private static boolean open(OpenFileWorker worker, String filename, File file, Window parent) {
-               
+
                MotorDatabaseLoadingDialog.check(parent);
-               
+
                // Open the file in a Swing worker thread
                log.info("Starting OpenFileWorker");
                if (!SwingWorkerDialog.runWorker(parent, "Opening file", "Reading " + filename + "...", worker)) {
@@ -1163,50 +1162,50 @@ public class BasicFrame extends JFrame {
                        log.info("User cancelled the OpenFileWorker");
                        return false;
                }
-               
-               
+
+
                // Handle the document
                OpenRocketDocument doc = null;
                try {
-                       
+
                        doc = worker.get();
-                       
+
                } catch (ExecutionException e) {
-                       
+
                        Throwable cause = e.getCause();
-                       
+
                        if (cause instanceof FileNotFoundException) {
-                               
+
                                log.warn("File not found", cause);
                                JOptionPane.showMessageDialog(parent,
                                                "File not found: " + filename,
                                                "Error opening file", JOptionPane.ERROR_MESSAGE);
                                return false;
-                               
+
                        } else if (cause instanceof RocketLoadException) {
-                               
+
                                log.warn("Error loading the file", cause);
                                JOptionPane.showMessageDialog(parent,
                                                "Unable to open file '" + filename + "': "
                                                                + cause.getMessage(),
                                                "Error opening file", JOptionPane.ERROR_MESSAGE);
                                return false;
-                               
+
                        } else {
-                               
+
                                throw new BugException("Unknown error when opening file", e);
-                               
+
                        }
-                       
+
                } catch (InterruptedException e) {
                        throw new BugException("EDT was interrupted", e);
                }
-               
+
                if (doc == null) {
                        throw new BugException("Document loader returned null");
                }
-               
-               
+
+
                // Show warnings
                WarningSet warnings = worker.getRocketLoader().getWarnings();
                if (!warnings.isEmpty()) {
@@ -1221,21 +1220,24 @@ public class BasicFrame extends JFrame {
                                        //// Warnings while opening file
                                        trans.get("BasicFrame.WarningDialog.title"), warnings);
                }
-               
-               
+
+
                // Set document state
                doc.setFile(file);
                doc.setSaved(true);
-               
-               
+
+
                // Open the frame
                log.debug("Opening new frame with the document");
                BasicFrame frame = new BasicFrame(doc);
                frame.setVisible(true);
-               
+
+               if ( parent != null && parent instanceof BasicFrame ) {
+                       ((BasicFrame)parent).closeIfReplaceable();
+               }
                return true;
        }
-       
+
        /**
         * "Save" action.  If the design is new, then this is identical to "Save As", with a default file filter for .ork.
         * If the rocket being edited previously was opened from a .ork file, then it will be saved immediately to the same
@@ -1251,13 +1253,13 @@ public class BasicFrame extends JFrame {
                        return saveAsAction();
                }
                log.info("Saving document to " + file);
-               
+
                if (FileHelper.ROCKSIM_DESIGN_FILTER.accept(file)) {
                        return saveAsRocksim(file);
                }
                return saveAs(file);
        }
-       
+
        /**
         * "Save As" action.
         *
@@ -1272,13 +1274,13 @@ public class BasicFrame extends JFrame {
         */
        private boolean saveAsAction() {
                File file = null;
-               
+
                StorageOptionChooser storageChooser =
                                new StorageOptionChooser(document, document.getDefaultStorageOptions());
                final JFileChooser chooser = new JFileChooser();
                chooser.addChoosableFileFilter(FileHelper.OPENROCKET_DESIGN_FILTER);
                chooser.addChoosableFileFilter(FileHelper.ROCKSIM_DESIGN_FILTER);
-               
+
                //Force the file filter to match the file extension that was opened.  Will default to OR if the file is null.
                if (FileHelper.ROCKSIM_DESIGN_FILTER.accept(document.getFile())) {
                        chooser.setFileFilter(FileHelper.ROCKSIM_DESIGN_FILTER);
@@ -1291,22 +1293,22 @@ public class BasicFrame extends JFrame {
                if (document.getFile() != null) {
                        chooser.setSelectedFile(document.getFile());
                }
-               
+
                int option = chooser.showSaveDialog(BasicFrame.this);
                if (option != JFileChooser.APPROVE_OPTION) {
                        log.user("User decided not to save, option=" + option);
                        return false;
                }
-               
+
                file = chooser.getSelectedFile();
                if (file == null) {
                        log.user("User did not select a file");
                        return false;
                }
-               
+
                ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
                storageChooser.storeOptions(document.getDefaultStorageOptions());
-               
+
                if (chooser.getFileFilter().equals(FileHelper.ROCKSIM_DESIGN_FILTER)) {
                        return saveAsRocksim(file);
                }
@@ -1315,7 +1317,7 @@ public class BasicFrame extends JFrame {
                        return FileHelper.confirmWrite(file, this) && saveAs(file);
                }
        }
-       
+
        /**
         * Perform the writing of the design to the given file in Rocksim format.
         *
@@ -1328,7 +1330,7 @@ public class BasicFrame extends JFrame {
                if (!FileHelper.confirmWrite(file, this)) {
                        return false;
                }
-               
+
                try {
                        new RocksimSaver().save(file, document);
                        return true;
@@ -1336,7 +1338,7 @@ public class BasicFrame extends JFrame {
                        return false;
                }
        }
-       
+
        /**
         * Perform the writing of the design to the given file in OpenRocket format.
         *
@@ -1347,25 +1349,25 @@ public class BasicFrame extends JFrame {
        private boolean saveAs(File file) {
                log.info("Saving document as " + file);
                boolean saved = false;
-               
+
                if (!StorageOptionChooser.verifyStorageOptions(document, this)) {
                        // User cancelled the dialog
                        log.user("User cancelled saving in storage options dialog");
                        return false;
                }
-               
-               
+
+
                SaveFileWorker worker = new SaveFileWorker(document, file, ROCKET_SAVER);
-               
+
                if (!SwingWorkerDialog.runWorker(this, "Saving file",
                                "Writing " + file.getName() + "...", worker)) {
-                       
+
                        // User cancelled the save
                        log.user("User cancelled the save, deleting the file");
                        file.delete();
                        return false;
                }
-               
+
                try {
                        worker.get();
                        document.setFile(file);
@@ -1373,9 +1375,9 @@ public class BasicFrame extends JFrame {
                        saved = true;
                        setTitle();
                } catch (ExecutionException e) {
-                       
+
                        Throwable cause = e.getCause();
-                       
+
                        if (cause instanceof IOException) {
                                log.warn("An I/O error occurred while saving " + file, cause);
                                JOptionPane.showMessageDialog(this, new String[] {
@@ -1385,15 +1387,15 @@ public class BasicFrame extends JFrame {
                        } else {
                                Reflection.handleWrappedException(e);
                        }
-                       
+
                } catch (InterruptedException e) {
                        throw new BugException("EDT was interrupted", e);
                }
-               
+
                return saved;
        }
-       
-       
+
+
        private boolean closeAction() {
                if (!document.isSaved()) {
                        log.info("Confirming whether to save the design");
@@ -1420,14 +1422,14 @@ public class BasicFrame extends JFrame {
                                return false;
                        }
                }
-               
+
                // Rocket has been saved or discarded
                log.debug("Disposing window");
                this.dispose();
-               
+
                ComponentConfigDialog.hideDialog();
                ComponentAnalysisDialog.hideDialog();
-               
+
                frames.remove(this);
                if (frames.isEmpty()) {
                        log.info("Last frame closed, exiting");
@@ -1435,22 +1437,26 @@ public class BasicFrame extends JFrame {
                }
                return true;
        }
-       
-       
-       
+
+
+
        /**
-        * 
+        *
         */
        public void printAction() {
-               new PrintDialog(this, document).setVisible(true);
+        Double rotation = rocketpanel.getFigure().getRotation();
+        if (rotation == null) {
+            rotation = 0d;
+        }
+               new PrintDialog(this, document, rotation).setVisible(true);
        }
-       
+
        /**
         * Open a new design window with a basic rocket+stage.
         */
        public static void newAction() {
                log.info("New action initiated");
-               
+
                Rocket rocket = new Rocket();
                Stage stage = new Stage();
                //// Sustainer
@@ -1458,13 +1464,14 @@ public class BasicFrame extends JFrame {
                rocket.addChild(stage);
                OpenRocketDocument doc = new OpenRocketDocument(rocket);
                doc.setSaved(true);
-               
+
                BasicFrame frame = new BasicFrame(doc);
                frame.replaceable = true;
                frame.setVisible(true);
-               ComponentConfigDialog.showDialog(frame, doc, rocket);
+               // kruland commented this out - I don't like it.
+               //ComponentConfigDialog.showDialog(frame, doc, rocket);
        }
-       
+
        /**
         * Quit the application.  Confirms saving unsaved designs.  The action of File->Quit.
         */
@@ -1482,33 +1489,33 @@ public class BasicFrame extends JFrame {
                log.error("Should already have exited application");
                System.exit(0);
        }
-       
-       
+
+
        /**
-        * Set the title of the frame, taking into account the name of the rocket, file it 
+        * Set the title of the frame, taking into account the name of the rocket, file it
         * has been saved to (if any) and saved status.
         */
        private void setTitle() {
                File file = document.getFile();
                boolean saved = document.isSaved();
                String title;
-               
+
                title = rocket.getName();
                if (file != null) {
                        title = title + " (" + file.getName() + ")";
                }
                if (!saved)
                        title = "*" + title;
-               
+
                setTitle(title);
        }
-       
-       
-       
+
+
+
        /**
         * Find a currently open BasicFrame containing the specified rocket.  This method
         * can be used to map a Rocket to a BasicFrame from GUI methods.
-        * 
+        *
         * @param rocket the Rocket.
         * @return               the corresponding BasicFrame, or <code>null</code> if none found.
         */
@@ -1522,11 +1529,11 @@ public class BasicFrame extends JFrame {
                log.debug("Could not find frame for rocket " + rocket);
                return null;
        }
-       
+
        /**
         * Find a currently open document by the rocket object.  This method can be used
         * to map a Rocket to OpenRocketDocument from GUI methods.
-        * 
+        *
         * @param rocket the Rocket.
         * @return               the corresponding OpenRocketDocument, or <code>null</code> if not found.
         */
diff --git a/core/src/net/sf/openrocket/gui/main/MRUDesignFile.java b/core/src/net/sf/openrocket/gui/main/MRUDesignFile.java
new file mode 100644 (file)
index 0000000..f32d23e
--- /dev/null
@@ -0,0 +1,179 @@
+package net.sf.openrocket.gui.main;
+
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.startup.Preferences;
+
+import javax.swing.event.EventListenerList;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implements a most-recently-used list backed by preferences.  This is modified/adapted from an example on the
+ * Netbeans wiki.
+ */
+public class MRUDesignFile {
+
+    public static final String MRU_FILE_LIST_PROPERTY = "MRUFileList";
+
+    public static final int MAX_SIZE = 9;
+
+    private List<String> mruFileList;
+
+    private static MRUDesignFile instance; // The single instance
+
+    private EventListenerList listenerList;
+
+    static {
+        instance = new MRUDesignFile();
+    }
+
+    /**
+     * Returns the single instance, creating one if it's the first time this method is called.
+     *
+     * @return The single instance.
+     */
+    public static MRUDesignFile getInstance() {
+        return instance;
+    }
+
+    /**
+     * Constructor.
+     */
+    protected MRUDesignFile() {
+        mruFileList = new ArrayList<String>(MAX_SIZE);
+        listenerList = new EventListenerList();
+        retrieve();
+    }
+
+    /**
+     * Get the current most-recently-used list of design files.
+     *
+     * @return a list that contains absolute file names
+     */
+    public List<String> getMRUFileList() {
+        return mruFileList;
+    }
+
+    /**
+     * Set the most-recently-used list to the given parameter and fire change events.
+     *
+     * @param list
+     */
+    public void setMRUFileList(List<String> list) {
+        this.mruFileList.clear();
+        this.mruFileList.addAll(list.subList(0, Math.min(list.size(), MAX_SIZE)));
+        firePropertyChange(MRU_FILE_LIST_PROPERTY, null, mruFileList);
+        store();
+    }
+
+    /**
+     * Remove a file from the MRU list and fire change events.
+     *
+     * @param absolutePath the filename to be removed
+     */
+    public void removeFile(String absolutePath) {
+        mruFileList.remove(absolutePath);
+        firePropertyChange(MRU_FILE_LIST_PROPERTY, null, mruFileList);
+        store();
+    }
+
+    /**
+     * Add a file to the MRU list and fire change events.
+     *
+     * @param absolutePath the filename to be added
+     */
+    public void addFile(String absolutePath) {
+        // remove the old
+        mruFileList.remove(absolutePath);
+
+        // add to the top
+        mruFileList.add(0, absolutePath);
+        while (mruFileList.size() > MAX_SIZE) {
+            mruFileList.remove(mruFileList.size() - 1);
+        }
+        firePropertyChange(MRU_FILE_LIST_PROPERTY, null, mruFileList);
+        store();
+    }
+
+    /**
+     * Clear all existing MRU references in the preferences backing store.
+     */
+    private void clear() {
+        Preferences prefs = getPreferences();
+
+        for (int i = 0; i < MAX_SIZE; i++) {
+            prefs.putString(MRU_FILE_LIST_PROPERTY + i, null);
+        }
+    }
+
+    /**
+     * Store the MRU list into the preferences backing store.
+     */
+    protected void store() {
+        Preferences prefs = getPreferences();
+
+        // clear the backing store
+        clear();
+
+        for (int i = 0; i < mruFileList.size(); i++) {
+            String str = mruFileList.get(i);
+            prefs.putString(MRU_FILE_LIST_PROPERTY + i, str);
+        }
+    }
+
+    /**
+     * Load the MRU list from the backing store.
+     */
+    protected void retrieve() {
+        mruFileList.clear();
+        Preferences prefs = getPreferences();
+
+        for (int i = 0; i < MAX_SIZE; i++) {
+            String str = prefs.getString(MRU_FILE_LIST_PROPERTY + i, null);
+            if (str != null) {
+                mruFileList.add(str);
+            }
+            else {
+                break;
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        listenerList.add(PropertyChangeListener.class, listener);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        listenerList.remove(PropertyChangeListener.class, listener);
+    }
+
+    protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
+        // Guaranteed to return a non-null array
+        Object[] listeners = listenerList.getListenerList();
+        // Process the listeners last to first, notifying
+        // those that are interested in this event
+        PropertyChangeEvent event = new PropertyChangeEvent(this, propertyName, oldValue, newValue);
+        for (int i = listeners.length - 2; i >= 0; i -= 2) {
+            if (listeners[i] == PropertyChangeListener.class) {
+                ((PropertyChangeListener) listeners[i + 1]).propertyChange(event);
+            }
+        }
+    }
+
+    /**
+     * Return the Preferences
+     *
+     * @return Preferences
+     */
+    protected final Preferences getPreferences() {
+        return Application.getPreferences();
+    }
+}
\ No newline at end of file
diff --git a/core/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java b/core/src/net/sf/openrocket/gui/main/MRUDesignFileAction.java
new file mode 100644 (file)
index 0000000..8757eaa
--- /dev/null
@@ -0,0 +1,86 @@
+package net.sf.openrocket.gui.main;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+import java.util.List;
+
+/**
+ * Implements a menu for the Most-Recently-Used Open Rocket design files.
+ */
+public final class MRUDesignFileAction extends JMenu {
+
+    /**
+     * The window to which an open design file action will be parented to (typically an instance of BasicFrame).
+     */
+    private Window parent;
+
+    /**
+     * Constructor.
+     *
+     * @param s         the I18N menu string
+     * @param theParent the window to which an open design file action will be parented to (typically an instance of
+     *                  BasicFrame).
+     */
+    public MRUDesignFileAction(String s, Window theParent) {
+        super(s);
+
+        parent = theParent;
+        MRUDesignFile opts = MRUDesignFile.getInstance();
+        opts.addPropertyChangeListener(new PropertyChangeListener() {
+            public void propertyChange(PropertyChangeEvent evt) {
+                if (!evt.getPropertyName().equals(MRUDesignFile.MRU_FILE_LIST_PROPERTY)) {
+                    return;
+                }
+                updateMenu();
+            }
+        });
+
+        updateMenu();
+    }
+
+    /**
+     * Create menu items.
+     */
+    private void updateMenu() {
+        removeAll();
+        List<String> list = MRUDesignFile.getInstance().getMRUFileList();
+        for (String name : list) {
+            Action action = createAction(name);
+            action.putValue(Action.NAME, name);
+            JMenuItem menuItem = new JMenuItem(action);
+            add(menuItem);
+        }
+    }
+
+    /**
+     * When a user clicks on one of the recently used design files, open it.
+     *
+     * @param file the design file name (absolute path)
+     *
+     * @return the action to open a design file
+     */
+    private Action createAction(String file) {
+        Action action = new AbstractAction() {
+            public void actionPerformed(ActionEvent e) {
+                String command = e.getActionCommand();
+                if (BasicFrame.open(new File(command), parent)) {
+                    MRUDesignFile.getInstance().addFile(command);
+                }
+                else {
+                    MRUDesignFile.getInstance().removeFile(command);
+                }
+            }
+        };
+
+        action.putValue(Action.ACTION_COMMAND_KEY, file);
+        return action;
+    }
+
+}
\ No newline at end of file
index 2b5ca7e7c4497810de2c0100402af8cce17da763..35c72db68007316961474486b66c502f57804c0c 100644 (file)
@@ -30,6 +30,7 @@ import javax.swing.event.DocumentEvent;
 import javax.swing.event.DocumentListener;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.SpinnerEditor;
 import net.sf.openrocket.gui.adaptors.BooleanModel;
@@ -82,19 +83,20 @@ public class SimulationEditDialog extends JDialog {
 
        private final Window parentWindow;
        private final Simulation simulation;
+       private final OpenRocketDocument document;
        private final SimulationOptions conditions;
        private final Configuration configuration;
        private static final Translator trans = Application.getTranslator();
        
        
-       public SimulationEditDialog(Window parent, Simulation s) {
-               this(parent, s, 0);
+       public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation s) {
+               this(parent, document, s, 0);
        }
        
-       public SimulationEditDialog(Window parent, Simulation s, int tab) {
+       public SimulationEditDialog(Window parent, OpenRocketDocument document, Simulation s, int tab) {
                //// Edit simulation
                super(parent, trans.get("simedtdlg.title.Editsim"), JDialog.ModalityType.DOCUMENT_MODAL);
-               
+               this.document = document;
                this.parentWindow = parent;
                this.simulation = s;
                this.conditions = simulation.getOptions();
@@ -125,7 +127,7 @@ public class SimulationEditDialog extends JDialog {
                                String name = field.getText();
                                if (name == null || name.equals(""))
                                        return;
-                               System.out.println("Setting name:" + name);
+                               //System.out.println("Setting name:" + name);
                                simulation.setName(name);
                                
                        }
@@ -169,7 +171,7 @@ public class SimulationEditDialog extends JDialog {
                        @Override
                        public void actionPerformed(ActionEvent e) {
                                SimulationEditDialog.this.dispose();
-                               SimulationRunDialog.runSimulations(parentWindow, simulation);
+                               SimulationRunDialog.runSimulations(parentWindow, SimulationEditDialog.this.document, simulation);
                        }
                });
                mainPanel.add(button, "gapright para");
@@ -241,7 +243,7 @@ public class SimulationEditDialog extends JDialog {
                label.setToolTipText(tip);
                sub.add(label);
                
-               m = new DoubleModel(conditions, "WindSpeedAverage", UnitGroup.UNITS_VELOCITY, 0);
+               m = new DoubleModel(conditions, "WindSpeedAverage", UnitGroup.UNITS_WINDSPEED, 0);
                
                spin = new JSpinner(m.getSpinnerModel());
                spin.setEditor(new SpinnerEditor(spin));
@@ -266,7 +268,7 @@ public class SimulationEditDialog extends JDialog {
                label.setToolTipText(tip);
                sub.add(label);
                
-               m = new DoubleModel(conditions, "WindSpeedDeviation", UnitGroup.UNITS_VELOCITY, 0);
+               m = new DoubleModel(conditions, "WindSpeedDeviation", UnitGroup.UNITS_WINDSPEED, 0);
                DoubleModel m2 = new DoubleModel(conditions, "WindSpeedAverage", 0.25,
                                UnitGroup.UNITS_COEFFICIENT, 0);
                
@@ -834,9 +836,6 @@ public class SimulationEditDialog extends JDialog {
                return new SimulationExportPanel(simulation);
        }
        
-       
-
-
 
        /**
         * Return a panel stating that there is no data available, and that the user
index 719e1cf6a6a3cd3d00cd4e1c7eae45ae19566067..b12b85617a5f27339689a8fb8ec4e45dfb14422b 100644 (file)
@@ -135,7 +135,7 @@ public class SimulationPanel extends JPanel {
                                
                                long t = System.currentTimeMillis();
                                new SimulationRunDialog(SwingUtilities.getWindowAncestor(
-                                                       SimulationPanel.this), sims).setVisible(true);
+                                                       SimulationPanel.this), document, sims).setVisible(true);
                                log.info("Running simulations took " + (System.currentTimeMillis() - t) + " ms");
                                fireMaintainSelection();
                        }
@@ -514,7 +514,7 @@ public class SimulationPanel extends JPanel {
        }
        
        private void openDialog(final Simulation sim, int position) {
-               new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), sim, position)
+               new SimulationEditDialog(SwingUtilities.getWindowAncestor(this), document, sim, position)
                                .setVisible(true);
                fireMaintainSelection();
        }
@@ -571,42 +571,38 @@ public class SimulationPanel extends JPanel {
                        tip = "<html><b>" + sim.getName() + "</b><br>";
                        switch (sim.getStatus()) {
                        case UPTODATE:
-                               //// <i>Up to date</i><br>
-                               tip += "<i>Up to date</i><br>";
+                               tip += trans.get ("simpanel.ttip.uptodate") + "<br>";
                                break;
                        
                        case LOADED:
-                               //// <i>Data loaded from a file</i><br>
-                               tip += "<i>Data loaded from a file</i><br>";
+                               tip += trans.get ("simpanel.ttip.loaded") + "<br>";
                                break;
                        
                        case OUTDATED:
-                               tip += "<i><font color=\"red\">Data is out of date</font></i><br>";
-                               tip += "Click <i><b>Run simulations</b></i> to simulate.<br>";
+                               tip += trans.get ("simpanel.ttip.outdated") + "<br>";
                                break;
                        
                        case EXTERNAL:
-                               tip += "<i>Imported data</i><br>";
+                               tip += trans.get ("simpanel.ttip.external") + "<br>";
                                return tip;
                                
                        case NOT_SIMULATED:
-                               tip += "<i>Not simulated yet</i><br>";
-                               tip += "Click <i><b>Run simulations</b></i> to simulate.";
+                               tip += trans.get ("simpanel.ttip.notSimulated");
                                return tip;
                        }
                        
                        if (data == null) {
-                               tip += "No simulation data available.";
+                               tip += trans.get ("simpanel.ttip.noData");
                                return tip;
                        }
                        WarningSet warnings = data.getWarningSet();
                        
                        if (warnings.isEmpty()) {
-                               tip += "<font color=\"gray\">No warnings.</font>";
+                               tip += trans.get ("simpanel.ttip.noWarnings");
                                return tip;
                        }
                        
-                       tip += "<font color=\"red\">Warnings:</font>";
+                       tip += trans.get ("simpanel.ttip.warnings");
                        for (Warning w : warnings) {
                                tip += "<br>" + w.toString();
                        }
index f85b248f640367a37df394fe710cabeef884e2d9..65fabb8fa36430ef8384c7a2dd5749ba0bc10e7c 100644 (file)
@@ -10,8 +10,11 @@ import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.util.Iterator;
 import java.util.List;
-import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 import javax.swing.JButton;
 import javax.swing.JDialog;
@@ -21,6 +24,7 @@ import javax.swing.JPanel;
 import javax.swing.JProgressBar;
 
 import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.dialogs.DetailDialog;
 import net.sf.openrocket.gui.util.GUIUtil;
@@ -32,6 +36,8 @@ import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.MotorMount.IgnitionEvent;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.simulation.customexpression.CustomExpressionSimulationListener;
 import net.sf.openrocket.simulation.exception.SimulationCancelledException;
 import net.sf.openrocket.simulation.exception.SimulationException;
 import net.sf.openrocket.simulation.exception.SimulationLaunchException;
@@ -58,8 +64,28 @@ public class SimulationRunDialog extends JDialog {
        private static final double APOGEE_PROGRESS = 0.7;
        
        
-       private final static ExecutorService executor = Executors.newFixedThreadPool(
-                       SwingPreferences.getMaxThreadCount());
+       /**
+        * A single ThreadPoolExecutor that will be used for all simulations.
+        * This executor must not be shut down.
+        */
+       private static final ThreadPoolExecutor executor;
+       static {
+               int n = SwingPreferences.getMaxThreadCount();
+               executor = new ThreadPoolExecutor(n, n,
+                               0L, TimeUnit.MILLISECONDS,
+                               new LinkedBlockingQueue<Runnable>(),
+                               new ThreadFactory() {
+                                       private ThreadFactory factory = Executors.defaultThreadFactory();
+                                       
+                                       @Override
+                                       public Thread newThread(Runnable r) {
+                                               Thread t = factory.newThread(r);
+                                               t.setDaemon(true);
+                                               return t;
+                                       }
+                               });
+       }
+       
        
        
        private final JLabel simLabel, timeLabel, altLabel, velLabel;
@@ -72,6 +98,7 @@ public class SimulationRunDialog extends JDialog {
         * will result in an exception being thrown!
         */
        private final Simulation[] simulations;
+       private final OpenRocketDocument document;
        private final String[] simulationNames;
        private final SimulationWorker[] simulationWorkers;
        private final SimulationStatus[] simulationStatuses;
@@ -79,9 +106,10 @@ public class SimulationRunDialog extends JDialog {
        private final double[] simulationMaxVelocity;
        private final boolean[] simulationDone;
        
-       public SimulationRunDialog(Window window, Simulation... simulations) {
+       public SimulationRunDialog(Window window, OpenRocketDocument document, Simulation... simulations) {
                //// Running simulations...
                super(window, trans.get("SimuRunDlg.title.RunSim"), Dialog.ModalityType.APPLICATION_MODAL);
+               this.document = document;
                
                if (simulations.length == 0) {
                        throw new IllegalArgumentException("Called with no simulations to run");
@@ -106,7 +134,7 @@ public class SimulationRunDialog extends JDialog {
                
                for (int i = 0; i < n; i++) {
                        simulationNames[i] = simulations[i].getName();
-                       simulationWorkers[i] = new InteractiveSimulationWorker(simulations[i], i);
+                       simulationWorkers[i] = new InteractiveSimulationWorker(document, simulations[i], i);
                        executor.execute(simulationWorkers[i]);
                }
                
@@ -172,10 +200,10 @@ public class SimulationRunDialog extends JDialog {
         * the Cancel button on the dialog.
         */
        public void cancelSimulations() {
-               executor.shutdownNow();
                for (SimulationWorker w : simulationWorkers) {
                        w.cancel(true);
                }
+               executor.purge();
        }
        
        
@@ -185,8 +213,8 @@ public class SimulationRunDialog extends JDialog {
         * @param parent                the parent Window of the dialog to use.
         * @param simulations   the simulations to run.
         */
-       public static void runSimulations(Window parent, Simulation... simulations) {
-               new SimulationRunDialog(parent, simulations).setVisible(true);
+       public static void runSimulations(Window parent, OpenRocketDocument document, Simulation... simulations) {
+               new SimulationRunDialog(parent, document, simulations).setVisible(true);
        }
        
        
@@ -254,6 +282,8 @@ public class SimulationRunDialog extends JDialog {
                private volatile double burnoutVelocity;
                private volatile double apogeeAltitude;
                
+               private final CustomExpressionSimulationListener exprListener;
+               
                /*
                 * -2 = time from 0 ... burnoutTimeEstimate
                 * -1 = velocity from v(burnoutTimeEstimate) ... 0
@@ -264,8 +294,10 @@ public class SimulationRunDialog extends JDialog {
                private int progress = 0;
                
                
-               public InteractiveSimulationWorker(Simulation sim, int index) {
+               public InteractiveSimulationWorker(OpenRocketDocument doc, Simulation sim, int index) {
                        super(sim);
+                       List<CustomExpression> exprs = doc.getCustomExpressions();
+                       exprListener = new CustomExpressionSimulationListener(exprs);
                        this.index = index;
                        
                        // Calculate estimate of motor burn time
@@ -291,7 +323,7 @@ public class SimulationRunDialog extends JDialog {
                 */
                @Override
                protected SimulationListener[] getExtraListeners() {
-                       return new SimulationListener[] { new SimulationProgressListener() };
+                       return new SimulationListener[] { new SimulationProgressListener(), exprListener };
                }
                
                
index a7e8386ef6b354261a2eb9b69200eab30956de9b..6fe9fe1d90a5787b0566acc0ef3f5e2233fb18cd 100644 (file)
@@ -9,6 +9,7 @@ import javax.swing.tree.DefaultTreeCellRenderer;
 
 import net.sf.openrocket.gui.main.ComponentIcons;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.TextUtil;
 
 public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
@@ -21,25 +22,38 @@ public class ComponentTreeRenderer extends DefaultTreeCellRenderer {
                        boolean expanded,
                        boolean leaf,
                        int row,
-                       boolean hasFocus) {
+                       boolean hasFocus1) {
                
-               super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
+               super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus1);
                
                // Set icon
                setIcon(ComponentIcons.getSmallIcon(value.getClass()));
                
                // Set tooltip
                RocketComponent c = (RocketComponent) value;
+               this.setToolTipText(getToolTip(c));
+               
+               return this;
+       }
+       
+       
+       private String getToolTip(RocketComponent c) {
+               StringBuilder sb = new StringBuilder();
+               sb.append("<html>");
+               
+               sb.append("<b>").append(c.getName()).append("</b>");
+               if (c.isMassive()) {
+                       sb.append(" (").append(UnitGroup.UNITS_MASS.toStringUnit(c.getMass())).append(")");
+               }
+               
                String comment = c.getComment().trim();
                if (comment.length() > 0) {
                        comment = TextUtil.htmlEncode(comment);
-                       comment = "<html>" + comment.replace("\n", "<br>");
-                       this.setToolTipText(comment);
-               } else {
-                       this.setToolTipText(null);
+                       comment = comment.replace("\n", "<br>");
+                       sb.append("<br>").append(comment);
                }
                
-               return this;
+               return sb.toString();
        }
        
 }
index bd58782f70b9de073c18412ea3bb42ec319ca65f..4438b2079ef744f4146e3bb20f6a08968fc4f98a 100644 (file)
@@ -63,7 +63,7 @@ public class PlotConfiguration implements Cloneable {
                configs.add(config);
                
                //// Stability vs. time
-               config = new PlotConfiguration("Stability vs. time");
+               config = new PlotConfiguration(trans.get("PlotConfiguration.Stability"));
                config.addPlotDataType(FlightDataType.TYPE_STABILITY, 0);
                config.addPlotDataType(FlightDataType.TYPE_CP_LOCATION, 1);
                config.addPlotDataType(FlightDataType.TYPE_CG_LOCATION, 1);
@@ -76,7 +76,7 @@ public class PlotConfiguration implements Cloneable {
                configs.add(config);
                
                //// Drag coefficients vs. Mach number
-               config = new PlotConfiguration("Drag coefficients vs. Mach number",
+               config = new PlotConfiguration(trans.get("PlotConfiguration.Dragcoef"),
                                FlightDataType.TYPE_MACH_NUMBER);
                config.addPlotDataType(FlightDataType.TYPE_DRAG_COEFF, 0);
                config.addPlotDataType(FlightDataType.TYPE_FRICTION_DRAG_COEFF, 0);
@@ -85,7 +85,7 @@ public class PlotConfiguration implements Cloneable {
                configs.add(config);
                
                //// Roll characteristics
-               config = new PlotConfiguration("Roll characteristics");
+               config = new PlotConfiguration(trans.get("PlotConfiguration.Rollcharacteristics"));
                config.addPlotDataType(FlightDataType.TYPE_ROLL_RATE, 0);
                config.addPlotDataType(FlightDataType.TYPE_ROLL_MOMENT_COEFF, 1);
                config.addPlotDataType(FlightDataType.TYPE_ROLL_FORCING_COEFF, 1);
@@ -100,7 +100,7 @@ public class PlotConfiguration implements Cloneable {
                configs.add(config);
                
                //// Angle of attack and orientation vs. time
-               config = new PlotConfiguration("Angle of attack and orientation vs. time");
+               config = new PlotConfiguration(trans.get("PlotConfiguration.Angleofattack"));
                config.addPlotDataType(FlightDataType.TYPE_AOA, 0);
                config.addPlotDataType(FlightDataType.TYPE_ORIENTATION_PHI);
                config.addPlotDataType(FlightDataType.TYPE_ORIENTATION_THETA);
@@ -113,7 +113,7 @@ public class PlotConfiguration implements Cloneable {
                configs.add(config);
                
                //// Simulation time step and computation time
-               config = new PlotConfiguration("Simulation time step and computation time");
+               config = new PlotConfiguration(trans.get("PlotConfiguration.Simulationtime"));
                config.addPlotDataType(FlightDataType.TYPE_TIME_STEP);
                config.addPlotDataType(FlightDataType.TYPE_COMPUTATION_TIME);
                config.setEvent(FlightEvent.Type.IGNITION, true);
@@ -358,7 +358,7 @@ public class PlotConfiguration implements Cloneable {
         */
        public PlotConfiguration fillAutoAxes(FlightDataBranch data) {
                PlotConfiguration config = recursiveFillAutoAxes(data).getU();
-               System.out.println("BEST FOUND, fitting");
+               //System.out.println("BEST FOUND, fitting");
                config.fitAxes(data);
                return config;
        }
@@ -483,13 +483,13 @@ public class PlotConfiguration implements Cloneable {
                double scale = Math.max(left.getRangeLength(), right.getRangeLength()) /
                                                Math.min(left.getRangeLength(), right.getRangeLength());
                
-               System.out.println("Scale: " + scale);
+               //System.out.println("Scale: " + scale);
                
                scale = roundScale(scale);
                if (right.getRangeLength() > left.getRangeLength()) {
                        scale = 1 / scale;
                }
-               System.out.println("Rounded scale: " + scale);
+               //System.out.println("Rounded scale: " + scale);
                
                // Scale right axis, enlarge axes if necessary and scale back
                min2 *= scale;
index d26ea7c2b5a74b9f360c5e5dcd26507a5a8d41f2..ada19bfcd8a98b7a7e94ea890e23e4ef24d2b4ac 100644 (file)
@@ -115,7 +115,7 @@ public class SimulationPlotDialog extends JDialog {
                
                is = ClassLoader.getSystemResourceAsStream(file);
                if (is == null) {
-                       System.out.println("ERROR: File " + file + " not found!");
+                       //System.out.println("ERROR: File " + file + " not found!");
                        return;
                }
                
index 06544f52676938211927e56925044e36a4995b9e..515ad0c8344e744a0a231846a40212f93aa2e1c4 100644 (file)
@@ -119,8 +119,16 @@ public class SimulationPlotPanel extends JPanel {
                }
                
                configurationSelector.addItemListener(new ItemListener() {
+                       
                        @Override
                        public void itemStateChanged(ItemEvent e) {
+                               // We are only concerned with ItemEvent.SELECTED to update
+                               // the UI when the selected item changes.
+                               // TODO - this should probably be implemented as an ActionListener instead
+                               // of ItemStateListener.
+                               if ( e.getStateChange() == ItemEvent.DESELECTED) {
+                                       return;
+                               }
                                if (modifying > 0)
                                        return;
                                PlotConfiguration conf = (PlotConfiguration) configurationSelector.getSelectedItem();
@@ -357,7 +365,9 @@ public class SimulationPlotPanel extends JPanel {
                        typeSelectorPanel.add(new PlotTypeSelector(i, type, unit, axis), "wrap");
                }
                
-               typeSelectorPanel.repaint();
+               // In order to consistantly update the ui, we need to validate before repaint.
+               typeSelectorPanel.validate();
+               typeSelectorPanel.repaint();    
                
                eventTableModel.fireTableDataChanged();
        }
diff --git a/core/src/net/sf/openrocket/gui/plugin/DoSomethingPlugin.java b/core/src/net/sf/openrocket/gui/plugin/DoSomethingPlugin.java
new file mode 100644 (file)
index 0000000..d238c4e
--- /dev/null
@@ -0,0 +1,16 @@
+package net.sf.openrocket.gui.plugin;
+
+import javax.swing.Action;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.main.BasicFrame;
+
+public class DoSomethingPlugin extends OpenRocketSwingMenuPlugin {
+       
+       @Override
+       public Action getAction(BasicFrame frame, OpenRocketDocument document) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/gui/plugin/OpenRocketSwingMenuPlugin.java b/core/src/net/sf/openrocket/gui/plugin/OpenRocketSwingMenuPlugin.java
new file mode 100644 (file)
index 0000000..e76e64a
--- /dev/null
@@ -0,0 +1,22 @@
+package net.sf.openrocket.gui.plugin;
+
+import java.util.List;
+
+import net.sf.openrocket.plugin.framework.Service;
+
+public abstract class OpenRocketSwingMenuPlugin implements Service, SwingMenuPlugin {
+       
+       @Override
+       public String[] getMenuPosition() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+       
+       
+       @Override
+       public <E> List<E> getPlugins(Class<E> type, Object... args) {
+               // TODO Auto-generated method stub
+               return null;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/gui/plugin/SwingMenuPlugin.java b/core/src/net/sf/openrocket/gui/plugin/SwingMenuPlugin.java
new file mode 100644 (file)
index 0000000..e27b78a
--- /dev/null
@@ -0,0 +1,40 @@
+package net.sf.openrocket.gui.plugin;
+
+import javax.swing.Action;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.main.BasicFrame;
+
+/**
+ * A plugin that provides a menu item to the Swing GUI menus.
+ * This may open a dialog window or perform some other action on
+ * the current document.
+ * <p>
+ * During plugin discovery, the BasicFrame and OpenRocketDocument
+ * objects are passed to the plugin.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public interface SwingMenuPlugin {
+       
+       /**
+        * Return the menu position where the action is placed.
+        * The first string in the array indicates the menu to place
+        * the item in, the second is the sub-menu, the third is the
+        * sub-sub-menu etc.
+        * <p>
+        * The strings are translated menu names.
+        * 
+        * @return      the menu position for the action
+        */
+       public String[] getMenuPosition();
+       
+       /**
+        * Return the Action that the menu item performs.  This contains
+        * the menu item text and may contain an icon.
+        * 
+        * @return      the action to perform on the menu item.
+        */
+       public Action getAction(BasicFrame frame, OpenRocketDocument document);
+       
+}
diff --git a/core/src/net/sf/openrocket/gui/preset/ButtonColumn.java b/core/src/net/sf/openrocket/gui/preset/ButtonColumn.java
new file mode 100644 (file)
index 0000000..13b8653
--- /dev/null
@@ -0,0 +1,238 @@
+package net.sf.openrocket.gui.preset;
+
+import javax.swing.AbstractCellEditor;
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JTable;
+import javax.swing.UIManager;
+import javax.swing.border.Border;
+import javax.swing.border.LineBorder;
+import javax.swing.table.TableCellEditor;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumnModel;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+
+/**
+ *  The ButtonColumn class provides a renderer and an editor that looks like a
+ *  JButton. The renderer and editor will then be used for a specified column
+ *  in the table. The TableModel will contain the String to be displayed on
+ *  the button.
+ *
+ *  The button can be invoked by a mouse click or by pressing the space bar
+ *  when the cell has focus. Optionaly a mnemonic can be set to invoke the
+ *  button. When the button is invoked the provided Action is invoked. The
+ *  source of the Action will be the table. The action command will contain
+ *  the model row number of the button that was clicked.
+ *
+ * Credits: A post by Rob Camick   http://tips4java.wordpress.com/2009/07/12/table-button-column/
+ */
+public class ButtonColumn extends AbstractCellEditor
+       implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener
+{
+       private JTable table;
+       private Action action;
+       private int mnemonic;
+       private Border originalBorder;
+       private Border focusBorder;
+
+       private JButton renderButton;
+       private JButton editButton;
+       private Object editorValue;
+       private boolean isButtonColumnEditor;
+
+       /**
+        *  Create the ButtonColumn to be used as a renderer and editor. The
+        *  renderer and editor will automatically be installed on the TableColumn
+        *  of the specified column.
+        *
+        *  @param table the table containing the button renderer/editor
+        *  @param action the Action to be invoked when the button is invoked
+        *  @param column the column to which the button renderer/editor is added
+        */
+       public ButtonColumn(JTable table, Action action, int column)
+       {
+               this.table = table;
+               this.action = action;
+
+               renderButton = new JButton();
+               editButton = new JButton();
+               editButton.setFocusPainted( false );
+               editButton.addActionListener( this );
+               originalBorder = editButton.getBorder();
+               setFocusBorder( new LineBorder(Color.BLUE) );
+
+               TableColumnModel columnModel = table.getColumnModel();
+               columnModel.getColumn(column).setCellRenderer( this );
+               columnModel.getColumn(column).setCellEditor( this );
+               table.addMouseListener( this );
+       }
+
+
+       /**
+        *  Get foreground color of the button when the cell has focus
+        *
+        *  @return the foreground color
+        */
+       public Border getFocusBorder()
+       {
+               return focusBorder;
+       }
+
+       /**
+        *  The foreground color of the button when the cell has focus
+        *
+        *  @param focusBorder the foreground color
+        */
+       public void setFocusBorder(Border focusBorder)
+       {
+               this.focusBorder = focusBorder;
+               editButton.setBorder( focusBorder );
+       }
+
+       public int getMnemonic()
+       {
+               return mnemonic;
+       }
+
+       /**
+        *  The mnemonic to activate the button when the cell has focus
+        *
+        *  @param mnemonic the mnemonic
+        */
+       public void setMnemonic(int mnemonic)
+       {
+               this.mnemonic = mnemonic;
+               renderButton.setMnemonic(mnemonic);
+               editButton.setMnemonic(mnemonic);
+       }
+
+       @Override
+       public Component getTableCellEditorComponent(
+               JTable table, Object value, boolean isSelected, int row, int column)
+       {
+               if (value == null)
+               {
+                       editButton.setText( "" );
+                       editButton.setIcon( null );
+               }
+               else if (value instanceof Icon)
+               {
+                       editButton.setText( "" );
+                       editButton.setIcon( (Icon)value );
+               }
+               else
+               {
+                       editButton.setText( value.toString() );
+                       editButton.setIcon( null );
+               }
+
+               this.editorValue = value;
+               return editButton;
+       }
+
+       @Override
+       public Object getCellEditorValue()
+       {
+               return editorValue;
+       }
+
+//
+//  Implement TableCellRenderer interface
+//
+       public Component getTableCellRendererComponent(
+               JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
+       {
+               if (isSelected)
+               {
+                       renderButton.setForeground(table.getSelectionForeground());
+                       renderButton.setBackground(table.getSelectionBackground());
+               }
+               else
+               {
+                       renderButton.setForeground(table.getForeground());
+                       renderButton.setBackground(UIManager.getColor("Button.background"));
+               }
+
+               if (hasFocus)
+               {
+                       renderButton.setBorder( focusBorder );
+               }
+               else
+               {
+                       renderButton.setBorder( originalBorder );
+               }
+
+//             renderButton.setText( (value == null) ? "" : value.toString() );
+               if (value == null)
+               {
+                       renderButton.setText( "" );
+                       renderButton.setIcon( null );
+               }
+               else if (value instanceof Icon)
+               {
+                       renderButton.setText( "" );
+                       renderButton.setIcon( (Icon)value );
+               }
+               else
+               {
+                       renderButton.setText( value.toString() );
+                       renderButton.setIcon( null );
+               }
+
+               return renderButton;
+       }
+
+//
+//  Implement ActionListener interface
+//
+       /*
+        *      The button has been pressed. Stop editing and invoke the custom Action
+        */
+       public void actionPerformed(ActionEvent e)
+       {
+               int row = table.convertRowIndexToModel( table.getEditingRow() );
+               fireEditingStopped();
+
+               //  Invoke the Action
+
+               ActionEvent event = new ActionEvent(
+                       table,
+                       ActionEvent.ACTION_PERFORMED,
+                       "" + row);
+               action.actionPerformed(event);
+       }
+
+//
+//  Implement MouseListener interface
+//
+       /*
+        *  When the mouse is pressed the editor is invoked. If you then drag
+        *  the mouse to another cell before releasing it, the editor is still
+        *  active. Make sure editing is stopped when the mouse is released.
+        */
+    public void mousePressed(MouseEvent e)
+    {
+       if (table.isEditing()
+               &&  table.getCellEditor() == this)
+                       isButtonColumnEditor = true;
+    }
+
+    public void mouseReleased(MouseEvent e)
+    {
+       if (isButtonColumnEditor
+       &&  table.isEditing())
+               table.getCellEditor().stopCellEditing();
+
+               isButtonColumnEditor = false;
+    }
+
+    public void mouseClicked(MouseEvent e) {}
+       public void mouseEntered(MouseEvent e) {}
+    public void mouseExited(MouseEvent e) {}
+}
diff --git a/core/src/net/sf/openrocket/gui/preset/ComponentPresetEditor.java b/core/src/net/sf/openrocket/gui/preset/ComponentPresetEditor.java
new file mode 100644 (file)
index 0000000..9f11cdd
--- /dev/null
@@ -0,0 +1,505 @@
+package net.sf.openrocket.gui.preset;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSeparator;
+import javax.swing.JTable;
+import javax.swing.table.DefaultTableModel;
+import javax.xml.bind.JAXBException;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.util.FileHelper;
+import net.sf.openrocket.gui.util.Icons;
+import net.sf.openrocket.gui.util.SwingPreferences;
+import net.sf.openrocket.l10n.ResourceBundleTranslator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.loader.MaterialHolder;
+import net.sf.openrocket.preset.loader.RocksimComponentFileTranslator;
+import net.sf.openrocket.preset.xml.OpenRocketComponentDTO;
+import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
+import net.sf.openrocket.startup.Application;
+
+/**
+ * A UI for editing component presets.  Currently this is a standalone application - run the main within this class.
+ * TODO: Full I18n TODO: Save As .csv
+ */
+public class ComponentPresetEditor extends JPanel implements PresetResultListener {
+
+    /**
+     * The logger.
+     */
+    private static final LogHelper log = Application.getLogger();
+
+    /**
+     * The I18N translator.
+     */
+    private static ResourceBundleTranslator trans = null;
+
+    /**
+     * The table of presets.
+     */
+    private JTable table;
+
+    /**
+     * The table's data model.
+     */
+    private DataTableModel model;
+
+    /**
+     * Flag that indicates if an existing Preset is currently being edited.
+     */
+ //   private boolean editingSelected = false;
+
+    private final OpenedFileContext editContext = new OpenedFileContext();
+
+    static {
+        trans = new ResourceBundleTranslator("l10n.messages");
+        net.sf.openrocket.startup.Application.setBaseTranslator(trans);
+    }
+
+    /**
+     * Create the panel.
+     *
+     * @param frame the parent window
+     */
+    public ComponentPresetEditor(final JFrame frame) {
+        setLayout(new MigLayout("", "[82.00px, grow][168.00px, grow][84px, grow][117.00px, grow][][222px]",
+                "[346.00px, grow][29px]"));
+
+        model = new DataTableModel(new String[]{"Manufacturer", "Type", "Part No", "Description", ""});
+
+        table = new JTable(model);
+        table.getTableHeader().setFont(new JLabel().getFont());
+        //The action never gets called because the table MouseAdapter intercepts it first.  Still need an empty
+        // instance though.
+        Action action = new AbstractAction() {
+            @Override
+            public void actionPerformed(final ActionEvent e) {
+            }
+        };
+        //Create a editor/renderer for the delete operation.  Instantiation self-registers into the table.
+        new ButtonColumn(table, action, 4);
+        table.getColumnModel().getColumn(4).setMaxWidth(Icons.EDIT_DELETE.getIconWidth());
+        table.getColumnModel().getColumn(4).setMinWidth(Icons.EDIT_DELETE.getIconWidth());
+
+        JScrollPane scrollPane = new JScrollPane(table);
+        table.setFillsViewportHeight(true);
+        table.setAutoCreateRowSorter(true);
+        add(scrollPane, "cell 0 0 6 1,grow");
+
+        table.addMouseListener(new MouseAdapter() {
+            public void mouseClicked(MouseEvent e) {
+                JTable target = (JTable) e.getSource();
+                int selectedColumn = table.getColumnModel().getColumnIndexAtX( target.getSelectedColumn() );
+                int selectedRow = table.getRowSorter().convertRowIndexToModel( target.getSelectedRow() );
+                if (selectedColumn == 4) {
+                    if (JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(ComponentPresetEditor.this,
+                            "Do you want to delete this preset?",
+                            "Confirm Delete", JOptionPane.YES_OPTION,
+                            JOptionPane.QUESTION_MESSAGE)) {
+                        model.removeRow(selectedRow);
+                    }
+                }
+                else {
+                    if (e.getClickCount() == 2) {
+                        editContext.setEditingSelected(true);
+                        new PresetEditorDialog(ComponentPresetEditor.this,
+                                (ComponentPreset) model.getAssociatedObject(selectedRow), editContext.getMaterialsLoaded()).setVisible(true);
+                    }
+                }
+            }
+        });
+
+
+        JMenuBar menuBar = new JMenuBar();
+        frame.setJMenuBar(menuBar);
+
+        JMenu mnFile = new JMenu("File");
+        menuBar.add(mnFile);
+
+        JMenuItem mntmOpen = new JMenuItem("Open...");
+        mnFile.add(mntmOpen);
+        mntmOpen.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(final ActionEvent e) {
+                if (model.getRowCount() > 0) {
+                    /*
+                     *  If the table model already contains presets, ask the user if they a) want to discard those
+                     *  presets, b) save them before reading in another component file, or c) merge the read component file
+                     *  with the current contents of the table model.
+                     */
+                    Object[] options = {"Save",
+                            "Merge",
+                            "Discard",
+                            "Cancel"};
+                    int n = JOptionPane.showOptionDialog(frame,
+                            "The editor contains existing component presets.  What would you like to do with them?",
+                            "Existing Component Presets",
+                            JOptionPane.YES_NO_CANCEL_OPTION,
+                            JOptionPane.QUESTION_MESSAGE,
+                            null,
+                            options,
+                            options[0]);
+                    if (n == 0) { //Save.  Then remove existing rows and open.
+                        if (saveAndHandleError()) {
+                            model.removeAllRows();
+                        }
+                        else { //Save failed; bail out.
+                            return;
+                        }
+                    }
+                    else if (n == 2) { //Discard and open
+                        model.removeAllRows();
+                    }
+                    else if (n == 3) { //Cancel.  Bail out.
+                        return;
+                    }
+                }
+                //Open file dialog
+                openComponentFile();
+            }
+        });
+
+        JSeparator separator = new JSeparator();
+        mnFile.add(separator);
+
+        JMenuItem mntmSave = new JMenuItem("Save As...");
+        mnFile.add(mntmSave);
+        mntmSave.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(final ActionEvent e) {
+                saveAndHandleError();
+            }
+        });
+
+        JSeparator separator_1 = new JSeparator();
+        mnFile.add(separator_1);
+
+        JMenuItem mntmExit = new JMenuItem("Exit");
+        mnFile.add(mntmExit);
+        mntmExit.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent arg0) {
+                System.exit(0);
+            }
+        });
+
+
+        JButton addBtn = new JButton("Add");
+        addBtn.addMouseListener(new MouseAdapter() {
+            @Override
+            public void mouseClicked(MouseEvent arg0) {
+                editContext.setEditingSelected(false);
+                new PresetEditorDialog(ComponentPresetEditor.this).setVisible(true);
+            }
+        });
+        add(addBtn, "cell 0 1,alignx left,aligny top");
+    }
+
+    /**
+     * Callback method from the PresetEditorDialog to notify this class when a preset has been saved.  The 'save' is
+     * really just a call back here so the preset can be added to the master table.  It's not to be confused with the
+     * save to disk.
+     *
+     * @param preset the new or modified preset
+     */
+    @Override
+    public void notifyResult(final ComponentPreset preset) {
+        if (preset != null) {
+            DataTableModel model = (DataTableModel) table.getModel();
+            //Is this a new preset?
+            String description = preset.has(ComponentPreset.DESCRIPTION) ? preset.get(ComponentPreset.DESCRIPTION) :
+                    preset.getPartNo();
+            if (!editContext.isEditingSelected()|| table.getSelectedRow() == -1) {
+                model.addRow(new Object[]{preset.getManufacturer().getDisplayName(), preset.getType().name(),
+                        preset.getPartNo(), description, Icons.EDIT_DELETE}, preset);
+            }
+            else {
+                //This is a modified preset; update all of the columns and the stored associated instance.
+                int row = table.getSelectedRow();
+                model.setValueAt(preset.getManufacturer().getDisplayName(), row, 0);
+                model.setValueAt(preset.getType().name(), row, 1);
+                model.setValueAt(preset.getPartNo(), row, 2);
+                model.setValueAt(description, row, 3);
+                model.associated.set(row, preset);
+            }
+        }
+        editContext.setEditingSelected(false);
+    }
+
+    /**
+     * Launch the test main.
+     */
+    public static void main(String[] args) {
+        try {
+            Application.setPreferences(new SwingPreferences());
+            JFrame dialog = new JFrame();
+            dialog.getContentPane().add(new ComponentPresetEditor(dialog));
+            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
+            dialog.pack();
+            dialog.setVisible(true);
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * A table model that adds associated objects to each row, allowing for easy retrieval.
+     */
+    class DataTableModel extends DefaultTableModel {
+
+        private List<Object> associated = new ArrayList<Object>();
+
+        /**
+         * Constructs a <code>DefaultTableModel</code> with as many columns as there are elements in
+         * <code>columnNames</code> and <code>rowCount</code> of <code>null</code> object values.  Each column's name
+         * will be taken from the <code>columnNames</code> array.
+         *
+         * @param columnNames <code>array</code> containing the names of the new columns; if this is <code>null</code>
+         *                    then the model has no columns
+         *
+         * @see #setDataVector
+         * @see #setValueAt
+         */
+        DataTableModel(final Object[] columnNames) {
+            super(columnNames, 0);
+        }
+
+        public void addRow(Object[] data, Object associatedData) {
+            super.addRow(data);
+            associated.add(getRowCount() - 1, associatedData);
+        }
+
+        public void removeAllRows() {
+            for (int x = getRowCount(); x > 0; x--) {
+                super.removeRow(x - 1);
+            }
+            associated.clear();
+        }
+
+        public void removeRow(int row) {
+            super.removeRow(row);
+            associated.remove(row);
+        }
+
+        public Object getAssociatedObject(int row) {
+            return associated.get(row);
+        }
+
+        public boolean isCellEditable(int rowIndex, int mColIndex) {
+            return false;
+        }
+    }
+
+    /**
+     * Open the component file.  Present a chooser for the user to navigate to the file.
+     *
+     * @return true if the file was successfully opened; Note: side effect, is that the ComponentPresets read from the
+     *         file are written to the table model.
+     */
+    private boolean openComponentFile() {
+        final JFileChooser chooser = new JFileChooser();
+        chooser.addChoosableFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER);
+        chooser.addChoosableFileFilter(FileHelper.CSV_FILE_FILTER);
+        chooser.setFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER);
+        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
+        if (editContext.getLastDirectory() != null) {
+            chooser.setCurrentDirectory(editContext.getLastDirectory());
+        }
+        else {
+            chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
+        }
+
+        int option = chooser.showOpenDialog(ComponentPresetEditor.this);
+        if (option != JFileChooser.APPROVE_OPTION) {
+            editContext.setOpenedFile(null);
+            log.user("User decided not to open, option=" + option);
+            return false;
+        }
+
+        File file = chooser.getSelectedFile();
+        try {
+            if (file == null) {
+                log.user("User did not select a file");
+                return false;
+            }
+
+            editContext.setLastDirectory(file.getParentFile());
+            editContext.setMaterialsLoaded(null);
+            List<ComponentPreset> presets = null;
+
+            if (file.getName().toLowerCase().endsWith(".orc")) {
+               OpenRocketComponentDTO fileContents = new OpenRocketComponentSaver().unmarshalFromOpenRocketComponent(new FileReader(file));
+               editContext.setMaterialsLoaded( new MaterialHolder(fileContents.asMaterialList()) );
+               presets = fileContents.asComponentPresets();
+            }
+            else {
+                if (file.getName().toLowerCase().endsWith(".csv")) {
+                    file = file.getParentFile();
+                }
+                presets = new ArrayList<ComponentPreset>();
+                MaterialHolder materialHolder = RocksimComponentFileTranslator.loadAll(presets, file);
+                editContext.setMaterialsLoaded(materialHolder);
+            }
+            if (presets != null) {
+                for (ComponentPreset next : presets) {
+                    notifyResult(next);
+                }
+                editContext.setOpenedFile(file);
+            }
+        }
+        catch (Exception e) {
+            JOptionPane.showMessageDialog(ComponentPresetEditor.this, "Unable to open OpenRocket component file: " +
+                    file.getName() + " Invalid format. " + e.getMessage());
+            editContext.setOpenedFile(null);
+            editContext.setEditingSelected(false);
+            return false;
+        }
+        return true;
+    }
+
+    private boolean saveAndHandleError() {
+        try {
+            return saveAsORC();
+        }
+        catch (Exception e1) {
+            JOptionPane.showMessageDialog(ComponentPresetEditor.this, e1.getLocalizedMessage(),
+                    "Error saving ORC file.", JOptionPane.ERROR_MESSAGE);
+            return false;
+        }
+    }
+
+    /**
+     * Save the contents of the table model as XML in .orc format.
+     *
+     * @return true if the file was written
+     *
+     * @throws JAXBException thrown if the data could not be marshaled
+     * @throws IOException   thrown if there was a problem with writing the file
+     */
+    private boolean saveAsORC() throws JAXBException, IOException {
+        File file = null;
+
+        final JFileChooser chooser = new JFileChooser();
+        chooser.addChoosableFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER);
+
+        chooser.setFileFilter(FileHelper.OPEN_ROCKET_COMPONENT_FILTER);
+        if (editContext.getOpenedFile() != null) {
+            chooser.setSelectedFile(editContext.getOpenedFile());
+        }
+        else {
+            chooser.setCurrentDirectory(((SwingPreferences) Application.getPreferences()).getDefaultDirectory());
+        }
+
+        int option = chooser.showSaveDialog(ComponentPresetEditor.this);
+        if (option != JFileChooser.APPROVE_OPTION) {
+            log.user("User decided not to save, option=" + option);
+            return false;
+        }
+
+        file = chooser.getSelectedFile();
+        if (file == null) {
+            log.user("User did not select a file");
+            return false;
+        }
+
+        ((SwingPreferences) Application.getPreferences()).setDefaultDirectory(chooser.getCurrentDirectory());
+
+        file = FileHelper.forceExtension(file, "orc");
+
+        MaterialHolder materials = new MaterialHolder();
+        List<ComponentPreset> presets = new ArrayList<ComponentPreset>();
+
+        for (int x = 0; x < model.getRowCount(); x++) {
+            ComponentPreset preset = (ComponentPreset) model.getAssociatedObject(x);
+            // If we don't have a material already defined for saving...
+            if ( materials.getMaterial(preset.get(ComponentPreset.MATERIAL)) == null ) {
+               // Check if we loaded a material with this name.
+               Material m = editContext.getMaterialsLoaded().getMaterial(preset.get(ComponentPreset.MATERIAL));
+               // If there was no material loaded with that name, use the component's material.
+               if ( m == null ) {
+                       m = preset.get(ComponentPreset.MATERIAL);
+               }
+                materials.put(m);
+            }
+            presets.add(preset);
+        }
+
+        return FileHelper.confirmWrite(file, this) && new OpenRocketComponentSaver().save(file, new ArrayList<Material>(materials.values()), presets);
+    }
+
+    class OpenedFileContext {
+
+        /**
+         * State variable to keep track of which file was opened, in case it needs to be saved back to that file.
+         */
+        private File openedFile = null;
+
+        /**
+         * Last directory; file chooser is set here so user doesn't have to keep navigating to a common area.
+         */
+        private File lastDirectory = null;
+
+        private boolean editingSelected = false;
+
+        private MaterialHolder materialsLoaded = null;
+
+        OpenedFileContext() {
+        }
+
+        public File getOpenedFile() {
+            return openedFile;
+        }
+
+        public void setOpenedFile(final File theOpenedFile) {
+            openedFile = theOpenedFile;
+        }
+
+        public File getLastDirectory() {
+            return lastDirectory;
+        }
+
+        public void setLastDirectory(final File theLastDirectory) {
+            lastDirectory = theLastDirectory;
+        }
+
+        public boolean isEditingSelected() {
+            return editingSelected;
+        }
+
+        public void setEditingSelected(final boolean theEditingSelected) {
+            editingSelected = theEditingSelected;
+        }
+
+        public MaterialHolder getMaterialsLoaded() {
+            return materialsLoaded;
+        }
+
+        public void setMaterialsLoaded(final MaterialHolder theMaterialsLoaded) {
+            materialsLoaded = theMaterialsLoaded;
+        }
+    }
+}
diff --git a/core/src/net/sf/openrocket/gui/preset/DeselectableComboBox.java b/core/src/net/sf/openrocket/gui/preset/DeselectableComboBox.java
new file mode 100644 (file)
index 0000000..758a850
--- /dev/null
@@ -0,0 +1,83 @@
+package net.sf.openrocket.gui.preset;
+
+import javax.swing.*;
+import javax.swing.plaf.basic.BasicComboBoxRenderer;
+import java.awt.*;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * A combo box that allows for items to be deselected.
+ */
+public class DeselectableComboBox extends JComboBox {
+
+    public DeselectableComboBox() {
+        super();
+        super.setRenderer(new DeselectedtemsRenderer());
+    }
+
+    private Set disabled_items = new HashSet();
+
+    public void addItem(Object anObject, boolean disabled) {
+        super.addItem(anObject);
+        if (disabled) {
+            disabled_items.add(getItemCount() - 1);
+        }
+    }
+
+    @Override
+    public void removeAllItems() {
+        super.removeAllItems();
+        disabled_items = new HashSet();
+    }
+
+    @Override
+    public void removeItemAt(final int anIndex) {
+        super.removeItemAt(anIndex);
+        disabled_items.remove(anIndex);
+    }
+
+    @Override
+    public void removeItem(final Object anObject) {
+        for (int i = 0; i < getItemCount(); i++) {
+            if (getItemAt(i) == anObject) {
+                disabled_items.remove(i);
+            }
+        }
+        super.removeItem(anObject);
+    }
+
+    @Override
+    public void setSelectedIndex(int index) {
+        if (!disabled_items.contains(index)) {
+            super.setSelectedIndex(index);
+        }
+    }
+
+    private class DeselectedtemsRenderer extends BasicComboBoxRenderer {
+
+        @Override
+        public Component getListCellRendererComponent(JList list,
+                                                      Object value,
+                                                      int index,
+                                                      boolean isSelected,
+                                                      boolean cellHasFocus) {
+
+            if (isSelected) {
+                setBackground(list.getSelectionBackground());
+                setForeground(list.getSelectionForeground());
+            }
+            else {
+                setBackground(list.getBackground());
+                setForeground(list.getForeground());
+            }
+            if (disabled_items.contains(index)) {
+                setBackground(list.getBackground());
+                setForeground(UIManager.getColor("Label.disabledForeground"));
+            }
+            setFont(list.getFont());
+            setText((value == null) ? "" : value.toString());
+            return this;
+        }
+    }
+}
diff --git a/core/src/net/sf/openrocket/gui/preset/ImagePreviewPanel.java b/core/src/net/sf/openrocket/gui/preset/ImagePreviewPanel.java
new file mode 100644 (file)
index 0000000..bab36ec
--- /dev/null
@@ -0,0 +1,105 @@
+
+package net.sf.openrocket.gui.preset;
+
+
+import javax.swing.*;
+import java.awt.*;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.File;
+
+/**
+ * From a JavaLobby article by Michael Urban:  http://www.javalobby.org/java/forums/t49462.html
+ */
+public class ImagePreviewPanel extends JPanel
+        implements PropertyChangeListener {
+
+    private int width, height;
+    private ImageIcon icon;
+    private Image image;
+    private static final int ACCSIZE = 155;
+    private Color bg;
+
+    public ImagePreviewPanel() {
+        setPreferredSize(new Dimension(ACCSIZE, -1));
+        bg = getBackground();
+    }
+
+    public void propertyChange(PropertyChangeEvent e) {
+        String propertyName = e.getPropertyName();
+
+        // Make sure we are responding to the right event.
+        if (propertyName.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
+            File selection = (File)e.getNewValue();
+            String name;
+
+            if (selection == null)
+                return;
+            else
+                name = selection.getAbsolutePath();
+
+            /*
+             * Make reasonably sure we have an image format that AWT can
+             * handle so we don't try to draw something silly.
+             */
+            if ((name != null) &&
+                    name.toLowerCase().endsWith(".jpg") ||
+                    name.toLowerCase().endsWith(".jpeg") ||
+                    name.toLowerCase().endsWith(".gif") ||
+                    name.toLowerCase().endsWith(".png")) {
+                icon = new ImageIcon(name);
+                image = icon.getImage();
+                scaleImage();
+                repaint();
+            }
+        }
+    }
+
+    private void scaleImage() {
+        width = image.getWidth(this);
+        height = image.getHeight(this);
+        double ratio = 1.0;
+
+        /*
+         * Determine how to scale the image. Since the accessory can expand
+         * vertically make sure we don't go larger than 150 when scaling
+         * vertically.
+         */
+        if (width >= height) {
+            ratio = (double)(ACCSIZE-5) / width;
+            width = ACCSIZE-5;
+            height = (int)(height * ratio);
+        }
+        else {
+            if (getHeight() > 150) {
+                ratio = (double)(ACCSIZE-5) / height;
+                height = ACCSIZE-5;
+                width = (int)(width * ratio);
+            }
+            else {
+                ratio = (double)getHeight() / height;
+                height = getHeight();
+                width = (int)(width * ratio);
+            }
+        }
+
+        image = image.getScaledInstance(width, height, Image.SCALE_DEFAULT);
+    }
+
+    public void paintComponent(Graphics g) {
+        g.setColor(bg);
+
+        /*
+         * If we don't do this, we will end up with garbage from previous
+         * images if they have larger sizes than the one we are currently
+         * drawing. Also, it seems that the file list can paint outside
+         * of its rectangle, and will cause odd behavior if we don't clear
+         * or fill the rectangle for the accessory before drawing. This might
+         * be a bug in JFileChooser.
+         */
+        g.fillRect(0, 0, ACCSIZE, getHeight());
+        g.drawImage(image, getWidth() / 2 - width / 2 + 5,
+                getHeight() / 2 - height / 2, this);
+    }
+
+}
diff --git a/core/src/net/sf/openrocket/gui/preset/MaterialModel.java b/core/src/net/sf/openrocket/gui/preset/MaterialModel.java
new file mode 100644 (file)
index 0000000..f51f214
--- /dev/null
@@ -0,0 +1,138 @@
+package net.sf.openrocket.gui.preset;
+
+import net.sf.openrocket.database.Database;
+import net.sf.openrocket.database.DatabaseListener;
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.gui.dialogs.CustomMaterialDialog;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.loader.MaterialHolder;
+import net.sf.openrocket.startup.Application;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.SwingUtilities;
+import java.awt.Component;
+
+/**
+ * A material model specifically for presets.
+ */
+public class MaterialModel extends DefaultComboBoxModel implements DatabaseListener<Material> {
+
+    private static final String CUSTOM = "Custom";
+
+    private final Database<Material> database;
+
+    private static final Translator trans = Application.getTranslator();
+
+    private Material.Type type;
+
+    private Component parent;
+
+    public MaterialModel(Component theParent, Material.Type theType, Database<Material> materials) {
+        parent = theParent;
+        type = theType;
+        database = materials;
+        database.addDatabaseListener(this);
+    }
+
+    public MaterialModel(Component theParent, Material.Type theType) {
+        parent = theParent;
+        type = theType;
+
+        switch (type) {
+            case LINE:
+                this.database = Databases.LINE_MATERIAL;
+                break;
+
+            case BULK:
+                this.database = Databases.BULK_MATERIAL;
+                break;
+
+            case SURFACE:
+                this.database = Databases.SURFACE_MATERIAL;
+                break;
+
+            default:
+                throw new IllegalArgumentException("Unknown material type:" + type);
+        }
+
+        database.addDatabaseListener(this);
+    }
+
+    @Override
+    public void setSelectedItem(Object item) {
+        if (item == null) {
+            // Clear selection - huh?
+            return;
+        }
+
+        if (item == CUSTOM) {
+
+            // Open custom material dialog in the future, after combo box has closed
+            SwingUtilities.invokeLater(new Runnable() {
+                @Override
+                public void run() {
+                    CustomMaterialDialog dialog = new CustomMaterialDialog(SwingUtilities.getWindowAncestor(parent), (Material) getSelectedItem(), true,
+                            //// Define custom material
+                            trans.get("MaterialModel.title.Defcustmat"));
+
+                    dialog.setVisible(true);
+
+                    if (!dialog.getOkClicked()) {
+                        return;
+                    }
+
+                    Material material = dialog.getMaterial();
+                    MaterialModel.super.setSelectedItem(material);
+                    if (dialog.isAddSelected()) {
+                        database.add(material);
+                    }
+                }
+            });
+
+        }
+        else if (item instanceof Material) {
+            super.setSelectedItem(item);
+        }
+        else {
+            throw new IllegalArgumentException("Illegal item class " + item.getClass() +
+                    " item=" + item);
+        }
+    }
+
+    @Override
+    public Object getElementAt(int index) {
+        if (index == database.size()) {
+            return CUSTOM;
+        }
+        else if (index >= database.size() + 1) {
+            return null;
+        }
+        return database.get(index);
+    }
+
+    @Override
+    public int getSize() {
+        return database.size() + 1;
+    }
+
+    ////////  Change listeners
+
+    @Override
+    public void elementAdded(Material element, Database<Material> source) {
+        this.fireContentsChanged(this, 0, database.size());
+    }
+
+    @Override
+    public void elementRemoved(Material element, Database<Material> source) {
+        this.fireContentsChanged(this, 0, database.size());
+    }
+
+    public Material.Type getType() {
+        return type;
+    }
+
+    public void removeListener() {
+        database.removeChangeListener(this);
+    }
+}
diff --git a/core/src/net/sf/openrocket/gui/preset/PresetEditorDialog.java b/core/src/net/sf/openrocket/gui/preset/PresetEditorDialog.java
new file mode 100644 (file)
index 0000000..9d1b220
--- /dev/null
@@ -0,0 +1,2217 @@
+package net.sf.openrocket.gui.preset;
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.imageio.ImageIO;
+import javax.swing.ComboBoxModel;
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.ImageIcon;
+import javax.swing.InputVerifier;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JSpinner;
+import javax.swing.JTextField;
+import javax.swing.border.EmptyBorder;
+import javax.swing.filechooser.FileNameExtensionFilter;
+import javax.swing.text.JTextComponent;
+
+import net.miginfocom.swing.MigLayout;
+import net.sf.openrocket.gui.SpinnerEditor;
+import net.sf.openrocket.gui.adaptors.DoubleModel;
+import net.sf.openrocket.gui.components.UnitSelector;
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+import net.sf.openrocket.preset.loader.MaterialHolder;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.unit.UnitGroup;
+
+/**
+ * Preset editor for creating new preset components.
+ */
+public class PresetEditorDialog extends JDialog implements ItemListener {
+       
+       private static Translator trans = Application.getTranslator();
+       
+       private static LogHelper log = Application.getLogger();
+       
+       private static final String NON_NEGATIVE_INTEGER_FIELD = "(\\d){0,10}";
+       
+       /**
+        * Input of non-negative decimals.
+        */
+       final PresetInputVerifier NON_NEGATIVE_INTEGER = new PresetInputVerifier(Pattern.compile(NON_NEGATIVE_INTEGER_FIELD));
+       
+       private final JPanel contentPanel = new JPanel();
+       private DeselectableComboBox typeCombo;
+       private JTextField mfgTextField;
+       private MaterialChooser materialChooser;
+       private MaterialHolder holder = null;
+       
+       private JTextField ncPartNoTextField;
+       private JTextField ncDescTextField;
+       private DoubleModel ncLength;
+       private JCheckBox ncFilledCB;
+       private JComboBox ncShapeCB;
+       private DoubleModel ncAftDia;
+       private DoubleModel ncAftShoulderDia;
+       private DoubleModel ncAftShoulderLen;
+       private DoubleModel ncMass;
+       private ImageIcon ncImage;
+       private JButton ncImageBtn;
+       
+       private JTextField trPartNoTextField;
+       private JTextField trDescTextField;
+       private DoubleModel trLength;
+       private DoubleModel trAftDia;
+       private DoubleModel trAftShoulderDia;
+       private DoubleModel trAftShoulderLen;
+       private DoubleModel trForeDia;
+       private DoubleModel trForeShoulderDia;
+       private DoubleModel trForeShoulderLen;
+       private DoubleModel trMass;
+       private ImageIcon trImage;
+       private JCheckBox trFilledCB;
+       private JComboBox trShapeCB;
+       private JButton trImageBtn;
+       
+       private JTextField btPartNoTextField;
+       private JTextField btDescTextField;
+       private DoubleModel btMass;
+       private DoubleModel btInnerDia;
+       private DoubleModel btOuterDia;
+       private DoubleModel btLength;
+       private ImageIcon btImage;
+       private JButton btImageBtn;
+       
+       private JTextField tcPartNoTextField;
+       private JTextField tcDescTextField;
+       private DoubleModel tcMass;
+       private DoubleModel tcInnerDia;
+       private DoubleModel tcOuterDia;
+       private DoubleModel tcLength;
+       private ImageIcon tcImage;
+       private JButton tcImageBtn;
+       
+       private JTextField bhPartNoTextField;
+       private JTextField bhDescTextField;
+       private DoubleModel bhOuterDia;
+       private DoubleModel bhLength;
+       private DoubleModel bhMass;
+       private ImageIcon bhImage;
+       private JButton bhImageBtn;
+       
+       private JTextField crPartNoTextField;
+       private JTextField crDescTextField;
+       private DoubleModel crOuterDia;
+       private DoubleModel crInnerDia;
+       private DoubleModel crThickness;
+       private DoubleModel crMass;
+       private ImageIcon crImage;
+       private JButton crImageBtn;
+       
+       private JTextField ebPartNoTextField;
+       private JTextField ebDescTextField;
+       private DoubleModel ebOuterDia;
+       private DoubleModel ebInnerDia;
+       private DoubleModel ebThickness;
+       private DoubleModel ebMass;
+       private ImageIcon ebImage;
+       private JButton ebImageBtn;
+       
+       private JTextField llPartNoTextField;
+       private JTextField llDescTextField;
+       private DoubleModel llOuterDia;
+       private DoubleModel llInnerDia;
+       private DoubleModel llLength;
+       private DoubleModel llMass;
+       private ImageIcon llImage;
+       private JButton llImageBtn;
+       
+       private JTextField stPartNoTextField;
+       private JTextField stDescTextField;
+       private DoubleModel stThickness;
+       private DoubleModel stWidth;
+       private DoubleModel stLength;
+       private DoubleModel stMass;
+       private ImageIcon stImage;
+       private JButton stImageBtn;
+       
+       private JTextField pcPartNoTextField;
+       private JTextField pcDescTextField;
+       private JTextField pcSides;
+       private JTextField pcLineCount;
+       private DoubleModel pcDiameter;
+       private DoubleModel pcLineLength;
+       private MaterialChooser pcLineMaterialChooser;
+       private DoubleModel pcMass;
+       private ImageIcon pcImage;
+       private JButton pcImageBtn;
+       
+       private final JFileChooser imageChooser = createImageChooser();
+       
+       private JPanel componentOverlayPanel;
+       
+       private PresetResultListener resultListener;
+       
+       private static Map<String, String> componentMap = new HashMap<String, String>();
+       
+       private static final String NOSE_CONE_KEY = "NoseCone.NoseCone";
+       private static final String BODY_TUBE_KEY = "BodyTube.BodyTube";
+       private static final String TUBE_COUPLER_KEY = "TubeCoupler.TubeCoupler";
+       private static final String TRANSITION_KEY = "Transition.Transition";
+       private static final String CR_KEY = "ComponentIcons.Centeringring";
+       private static final String BULKHEAD_KEY = "Bulkhead.Bulkhead";
+       private static final String EB_KEY = "ComponentIcons.Engineblock";
+       private static final String LAUNCH_LUG_KEY = "ComponentIcons.Launchlug";
+       private static final String STREAMER_KEY = "ComponentIcons.Streamer";
+       private static final String PARACHUTE_KEY = "ComponentIcons.Parachute";
+       
+       
+       static {
+               componentMap.put(trans.get(NOSE_CONE_KEY), "NOSECONE");
+               componentMap.put(trans.get(BODY_TUBE_KEY), "BODYTUBE");
+               componentMap.put(trans.get(TUBE_COUPLER_KEY), "TUBECOUPLER");
+               componentMap.put(trans.get(TRANSITION_KEY), "TRANSITION");
+               componentMap.put(trans.get(CR_KEY), "CENTERINGRING");
+               componentMap.put(trans.get(BULKHEAD_KEY), "BULKHEAD");
+               componentMap.put(trans.get(EB_KEY), "ENGINEBLOCK");
+               componentMap.put(trans.get(LAUNCH_LUG_KEY), "LAUNCHLUG");
+               componentMap.put(trans.get(PARACHUTE_KEY), "PARACHUTE");
+               componentMap.put(trans.get(STREAMER_KEY), "STREAMER");
+       }
+       
+       /**
+        * Create the dialog.
+        *
+        * @param theCallback the listener that gets the results of editing the presets
+        */
+       public PresetEditorDialog(PresetResultListener theCallback) {
+               this(theCallback, null, null);
+       }
+       
+       /**
+        * Create the dialog.
+        *
+        * @param theCallback the listener that gets the results of editing the presets
+        * @param toEdit      the ComponentPreset to be edited; or null if a new one is being added
+        * @param matHolder   the set of materials; if null then use system materials
+        */
+       public PresetEditorDialog(PresetResultListener theCallback, ComponentPreset toEdit, MaterialHolder matHolder) {
+               resultListener = theCallback;
+               getContentPane().setMinimumSize(new Dimension(200, 200));
+               setBounds(100, 100, 825, 610);
+               getContentPane().setLayout(new BorderLayout());
+               contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
+               getContentPane().add(contentPanel, BorderLayout.CENTER);
+               contentPanel.setLayout(new MigLayout("", "[][grow][94.00,grow][232.0,grow][130.00][grow]", "[][][20.00,grow][grow]"));
+               JLabel lblManufacturer = new JLabel("Manufacturer:");
+               contentPanel.add(lblManufacturer, "cell 2 0,alignx left,aligny center");
+               
+               mfgTextField = new JTextField();
+               contentPanel.add(mfgTextField, "cell 3 0,growx");
+               mfgTextField.setColumns(10);
+               
+               JLabel typeLabel = new JLabel("Type:");
+               contentPanel.add(typeLabel, "cell 2 1,alignx left,aligny center");
+               
+               componentOverlayPanel = new JPanel();
+               contentPanel.add(componentOverlayPanel, "cell 1 3 5 2,grow");
+               componentOverlayPanel.setLayout(new CardLayout(0, 0));
+               
+               typeCombo = new DeselectableComboBox();
+               typeCombo.addItemListener(this);
+               typeCombo.setModel(new DefaultComboBoxModel());
+               setItems(typeCombo, toEdit);
+               contentPanel.add(typeCombo, "cell 3 1,growx");
+               
+               JLabel bhMaterialLabel = new JLabel("Material:");
+               contentPanel.add(bhMaterialLabel, "cell 2 2, alignx left");
+               
+               materialChooser = new MaterialChooser(new MaterialModel(this, Material.Type.BULK));
+               
+               contentPanel.add(materialChooser, "cell 3 2,growx");
+               
+               {
+                       JPanel ncPanel = new JPanel();
+                       componentOverlayPanel.add(ncPanel, "NOSECONE");
+                       ncPanel.setLayout(new MigLayout("", "[61px][159.00,grow][45.00][109.00,grow][189.00,grow][grow]", "[16px][][][][][]"));
+                       JLabel ncPartNoLabel = new JLabel("Part No:");
+                       ncPanel.add(ncPartNoLabel, "cell 0 0,alignx left,aligny center");
+                       
+                       ncPartNoTextField = new JTextField();
+                       ncPanel.add(ncPartNoTextField, "cell 1 0,growx");
+                       ncPartNoTextField.setColumns(10);
+                       
+                       JLabel ncDescLabel = new JLabel("Description:");
+                       ncPanel.add(ncDescLabel, "cell 3 0,alignx left,aligny center");
+                       
+                       ncDescTextField = new JTextField();
+                       ncPanel.add(ncDescTextField, "cell 4 0,growx");
+                       ncDescTextField.setColumns(10);
+                       
+                       ncFilledCB = new JCheckBox("Filled");
+                       ncPanel.add(ncFilledCB, "cell 1 1");
+                       
+                       JLabel ncMaterialLabel = new JLabel(trans.get("RocketCompCfg.lbl.Componentmaterial"));
+                       ncPanel.add(ncMaterialLabel, "cell 0 1,alignx left");
+                       
+                       JLabel ncMassLabel = new JLabel(trans.get("RocketCompCfg.lbl.Componentmass"));
+                       ncPanel.add(ncMassLabel, "cell 3 1,alignx left");
+                       
+                       ncMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       JSpinner spin = new JSpinner(ncMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ncPanel.add(spin, "cell 4 1, growx");
+                       ncPanel.add(new UnitSelector(ncMass), "growx");
+                       
+                       JLabel ncShapeLabel = new JLabel(trans.get("NoseConeCfg.lbl.Noseconeshape"));
+                       ncPanel.add(ncShapeLabel, "cell 0 2,alignx left");
+                       
+                       ncShapeCB = new JComboBox();
+                       ncShapeCB.setModel(new DefaultComboBoxModel(new String[] { Transition.Shape.OGIVE.getName(), Transition.Shape.CONICAL.getName(), Transition.Shape.PARABOLIC.getName(),
+                                       Transition.Shape.ELLIPSOID.getName(), Transition.Shape.HAACK.getName() }));
+                       ncPanel.add(ncShapeCB, "cell 1 2,growx");
+                       
+                       JLabel ncLengthLabel = new JLabel(trans.get("NoseConeCfg.lbl.Noseconelength"));
+                       ncPanel.add(ncLengthLabel, "cell 3 2,alignx left");
+                       
+                       ncLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(ncLength.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ncPanel.add(spin, "cell 4 2, growx");
+                       ncPanel.add(new UnitSelector(ncLength), "growx");
+                       
+                       JLabel ncAftDiaLabel = new JLabel("Aft Dia.:");
+                       ncPanel.add(ncAftDiaLabel, "cell 0 3,alignx left");
+                       
+                       ncAftDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(ncAftDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ncPanel.add(spin, "cell 1 3, growx");
+                       ncPanel.add(new UnitSelector(ncAftDia), "growx");
+                       
+                       JLabel ncAftShoulderLenLabel = new JLabel("Aft Shoulder Len:");
+                       ncPanel.add(ncAftShoulderLenLabel, "cell 0 4,alignx left");
+                       
+                       ncAftShoulderLen = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(ncAftShoulderLen.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ncPanel.add(spin, "cell 1 4, growx");
+                       ncPanel.add(new UnitSelector(ncAftShoulderLen), "growx");
+                       
+                       JLabel ncAftShoulderDiaLabel = new JLabel("Aft Shoulder Dia.:");
+                       ncPanel.add(ncAftShoulderDiaLabel, "cell 0 5,alignx left, aligny top, pad 7 0 0 0");
+                       
+                       ncAftShoulderDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(ncAftShoulderDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ncPanel.add(spin, "cell 1 5, growx, aligny top");
+                       ncPanel.add(new UnitSelector(ncAftShoulderDia), "growx, aligny top, pad 7 0 0 0");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       ncPanel.add(panel, "cell 4 3, span 1 3");
+                       panel.setLayout(null);
+                       ncImageBtn = new JButton("No Image");
+                       ncImageBtn.setMaximumSize(new Dimension(75, 75));
+                       ncImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(ncImageBtn);
+                       ncImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       ncImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               ncImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               ncImageBtn.setIcon(ncImage);
+                                       }
+                               }
+                       });
+                       
+               }
+               {
+                       JPanel trPanel = new JPanel();
+                       componentOverlayPanel.add(trPanel, "TRANSITION");
+                       trPanel.setLayout(new MigLayout("", "[61px][159.00,grow][45.00][109.00,grow][189.00,grow][grow]", "[16px][][][][][]"));
+                       
+                       JLabel trPartNoLabel = new JLabel("Part No:");
+                       trPanel.add(trPartNoLabel, "cell 0 0,alignx left");
+                       
+                       trPartNoTextField = new JTextField();
+                       trPanel.add(trPartNoTextField, "cell 1 0,growx");
+                       trPartNoTextField.setColumns(10);
+                       
+                       JLabel trDescLabel = new JLabel("Description:");
+                       trPanel.add(trDescLabel, "cell 3 0,alignx left");
+                       
+                       trDescTextField = new JTextField();
+                       trPanel.add(trDescTextField, "cell 4 0,growx");
+                       trDescTextField.setColumns(10);
+                       
+                       trFilledCB = new JCheckBox("Filled");
+                       trPanel.add(trFilledCB, "cell 1 1");
+                       
+                       JLabel trMassLabel = new JLabel("Mass:");
+                       trPanel.add(trMassLabel, "cell 3 1,alignx left");
+                       
+                       trMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       JSpinner spin = new JSpinner(trMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       trPanel.add(spin, "cell 4 1, growx");
+                       trPanel.add(new UnitSelector(trMass), "growx");
+                       
+                       JLabel trShapeLabel = new JLabel("Shape:");
+                       trPanel.add(trShapeLabel, "cell 0 2,alignx left");
+                       
+                       trShapeCB = new JComboBox();
+                       trShapeCB.setModel(new DefaultComboBoxModel(new String[] { Transition.Shape.OGIVE.getName(), Transition.Shape.CONICAL.getName(), Transition.Shape.PARABOLIC.getName(),
+                                       Transition.Shape.ELLIPSOID.getName(), Transition.Shape.HAACK.getName() }));
+                       trPanel.add(trShapeCB, "cell 1 2,growx");
+                       
+                       JLabel trLengthLabel = new JLabel("Length:");
+                       trPanel.add(trLengthLabel, "cell 3 2,alignx left");
+                       
+                       trLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(trLength.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       trPanel.add(spin, "cell 4 2, growx");
+                       trPanel.add(new UnitSelector(trLength), "growx");
+                       
+                       JLabel trAftDiaLabel = new JLabel("Aft Dia.:");
+                       trPanel.add(trAftDiaLabel, "cell 0 3,alignx left");
+                       
+                       trAftDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(trAftDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       trPanel.add(spin, "cell 1 3, growx");
+                       trPanel.add(new UnitSelector(trAftDia), "growx");
+                       
+                       JLabel trForeDiaLabel = new JLabel("Fore Dia.:");
+                       trPanel.add(trForeDiaLabel, "cell 3 3,alignx left");
+                       
+                       trForeDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(trForeDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       trPanel.add(spin, "cell 4 3, growx");
+                       trPanel.add(new UnitSelector(trForeDia), "growx");
+                       
+                       JLabel trAftShouldDiaLabel = new JLabel("Aft Shoulder Dia.:");
+                       trPanel.add(trAftShouldDiaLabel, "cell 0 4,alignx left");
+                       
+                       trAftShoulderDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(trAftShoulderDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       trPanel.add(spin, "cell 1 4, growx");
+                       trPanel.add(new UnitSelector(trAftShoulderDia), "growx");
+                       
+                       JLabel trForeShouldDiaLabel = new JLabel("Fore Shoulder Dia.:");
+                       trPanel.add(trForeShouldDiaLabel, "cell 3 4,alignx left");
+                       
+                       trForeShoulderDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(trForeShoulderDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       trPanel.add(spin, "cell 4 4, growx");
+                       trPanel.add(new UnitSelector(trForeShoulderDia), "growx");
+                       
+                       JLabel trAftShoulderLenLabel = new JLabel("Aft Shoulder Len.:");
+                       trPanel.add(trAftShoulderLenLabel, "cell 0 5,alignx left");
+                       
+                       trAftShoulderLen = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(trAftShoulderLen.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       trPanel.add(spin, "cell 1 5, growx");
+                       trPanel.add(new UnitSelector(trAftShoulderLen), "growx");
+                       
+                       JLabel lblForeShoulderLen = new JLabel("Fore Shoulder Len.:");
+                       trPanel.add(lblForeShoulderLen, "cell 3 5,alignx left");
+                       
+                       trForeShoulderLen = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0, 2);
+                       spin = new JSpinner(trForeShoulderLen.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       trPanel.add(spin, "cell 4 5, growx");
+                       trPanel.add(new UnitSelector(trForeShoulderLen), "growx");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       trPanel.add(panel, "cell 4 6");
+                       panel.setLayout(null);
+                       trImageBtn = new JButton("No Image");
+                       trImageBtn.setMaximumSize(new Dimension(75, 75));
+                       trImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(trImageBtn);
+                       trImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       trImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               trImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               trImageBtn.setIcon(trImage);
+                                       }
+                               }
+                       });
+                       
+               }
+               {
+                       JPanel btPanel = new JPanel();
+                       componentOverlayPanel.add(btPanel, "BODYTUBE");
+                       btPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+                       JLabel btPartNoLabel = new JLabel("Part No:");
+                       btPanel.add(btPartNoLabel, "cell 0 0,alignx left");
+                       
+                       btPartNoTextField = new JTextField();
+                       btPanel.add(btPartNoTextField, "cell 1 0,growx");
+                       btPartNoTextField.setColumns(10);
+                       
+                       JLabel btDescLabel = new JLabel("Description:");
+                       btPanel.add(btDescLabel, "cell 3 0,alignx left");
+                       
+                       btDescTextField = new JTextField();
+                       btPanel.add(btDescTextField, "cell 4 0,growx");
+                       btDescTextField.setColumns(10);
+                       
+                       JLabel btLengthLabel = new JLabel("Length:");
+                       btPanel.add(btLengthLabel, "cell 0 1,alignx left");
+                       
+                       btLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       JSpinner spin = new JSpinner(btLength.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       btPanel.add(spin, "cell 1 1, growx");
+                       btPanel.add(new UnitSelector(btLength), "growx");
+                       
+                       JLabel btMassLabel = new JLabel("Mass:");
+                       btPanel.add(btMassLabel, "cell 3 1,alignx left");
+                       
+                       btMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       spin = new JSpinner(btMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       btPanel.add(spin, "cell 4 1, growx");
+                       btPanel.add(new UnitSelector(btMass), "w 34lp!");
+                       
+                       JLabel btInnerDiaLabel = new JLabel("Inner Dia.:");
+                       btPanel.add(btInnerDiaLabel, "cell 0 2,alignx left");
+                       
+                       btInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(btInnerDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       btPanel.add(spin, "cell 1 2, growx");
+                       btPanel.add(new UnitSelector(btInnerDia), "growx");
+                       
+                       JLabel btOuterDiaLabel = new JLabel("Outer Dia.:");
+                       btPanel.add(btOuterDiaLabel, "cell 3 2,alignx left");
+                       
+                       btOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(btOuterDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       btPanel.add(spin, "cell 4 2, growx");
+                       btPanel.add(new UnitSelector(btOuterDia), "w 34lp!");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       btPanel.add(panel, "cell 4 3");
+                       panel.setLayout(null);
+                       btImageBtn = new JButton("No Image");
+                       btImageBtn.setMaximumSize(new Dimension(75, 75));
+                       btImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(btImageBtn);
+                       btImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       btImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               btImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               btImageBtn.setIcon(btImage);
+                                       }
+                               }
+                       });
+                       
+               }
+               {
+                       JPanel tcPanel = new JPanel();
+                       componentOverlayPanel.add(tcPanel, "TUBECOUPLER");
+                       tcPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+                       JLabel tcPartNoLabel = new JLabel("Part No:");
+                       tcPanel.add(tcPartNoLabel, "cell 0 0,alignx left");
+                       
+                       tcPartNoTextField = new JTextField();
+                       tcPanel.add(tcPartNoTextField, "cell 1 0,growx");
+                       tcPartNoTextField.setColumns(10);
+                       
+                       JLabel tcDescLabel = new JLabel("Description:");
+                       tcPanel.add(tcDescLabel, "cell 3 0,alignx left");
+                       
+                       tcDescTextField = new JTextField();
+                       tcPanel.add(tcDescTextField, "cell 4 0,growx");
+                       tcDescTextField.setColumns(10);
+                       
+                       JLabel tcLengthLabel = new JLabel("Length:");
+                       tcPanel.add(tcLengthLabel, "cell 0 1,alignx left");
+                       
+                       tcLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       JSpinner spin = new JSpinner(tcLength.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       tcPanel.add(spin, "cell 1 1, growx");
+                       tcPanel.add(new UnitSelector(tcLength), "growx");
+                       
+                       JLabel tcMassLabel = new JLabel("Mass:");
+                       tcPanel.add(tcMassLabel, "cell 3 1,alignx left");
+                       
+                       tcMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       spin = new JSpinner(tcMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       tcPanel.add(spin, "cell 4 1, growx");
+                       tcPanel.add(new UnitSelector(tcMass), "w 34lp!");
+                       
+                       JLabel tcInnerDiaLabel = new JLabel("Inner Dia.:");
+                       tcPanel.add(tcInnerDiaLabel, "cell 0 2,alignx left");
+                       
+                       tcInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(tcInnerDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       tcPanel.add(spin, "cell 1 2, growx");
+                       tcPanel.add(new UnitSelector(tcInnerDia), "growx");
+                       
+                       JLabel tcOuterDiaLabel = new JLabel("Outer Dia.:");
+                       tcPanel.add(tcOuterDiaLabel, "cell 3 2,alignx left");
+                       
+                       tcOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(tcOuterDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       tcPanel.add(spin, "cell 4 2, growx");
+                       tcPanel.add(new UnitSelector(tcOuterDia), "w 34lp!");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       tcPanel.add(panel, "cell 4 3");
+                       panel.setLayout(null);
+                       tcImageBtn = new JButton("No Image");
+                       tcImageBtn.setMaximumSize(new Dimension(75, 75));
+                       tcImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(tcImageBtn);
+                       tcImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       tcImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               tcImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               tcImageBtn.setIcon(tcImage);
+                                       }
+                               }
+                       });
+                       
+                       
+               }
+               {
+                       JPanel bhPanel = new JPanel();
+                       componentOverlayPanel.add(bhPanel, "BULKHEAD");
+                       bhPanel.setLayout(new MigLayout("", "[][157.00,grow 79][65.00][grow]", "[][][][]"));
+                       
+                       JLabel bhPartNoLabel = new JLabel("Part No:");
+                       bhPanel.add(bhPartNoLabel, "cell 0 0,alignx left");
+                       
+                       bhPartNoTextField = new JTextField();
+                       bhPanel.add(bhPartNoTextField, "cell 1 0,growx");
+                       bhPartNoTextField.setColumns(10);
+                       
+                       JLabel bhDescLabel = new JLabel("Description:");
+                       bhPanel.add(bhDescLabel, "cell 3 0,alignx left");
+                       
+                       bhDescTextField = new JTextField();
+                       bhPanel.add(bhDescTextField, "cell 4 0,growx");
+                       bhDescTextField.setColumns(10);
+                       
+                       JLabel bhLengthLabel = new JLabel("Thickness:");
+                       bhPanel.add(bhLengthLabel, "cell 0 1,alignx left");
+                       
+                       bhLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       JSpinner spin = new JSpinner(bhLength.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       bhPanel.add(spin, "cell 1 1, growx");
+                       bhPanel.add(new UnitSelector(bhLength), "w 34lp!");
+                       
+                       JLabel bhMassLabel = new JLabel("Mass:");
+                       bhPanel.add(bhMassLabel, "cell 3 1,alignx left");
+                       
+                       bhMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       spin = new JSpinner(bhMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       bhPanel.add(spin, "cell 4 1, growx");
+                       bhPanel.add(new UnitSelector(bhMass), "growx");
+                       
+                       JLabel bhOuterDiaLabel = new JLabel("Outer Dia.:");
+                       bhPanel.add(bhOuterDiaLabel, "cell 0 2,alignx left, aligny top, pad 7 0 0 0");
+                       
+                       bhOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(bhOuterDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       bhPanel.add(spin, "cell 1 2, growx, aligny top");
+                       bhPanel.add(new UnitSelector(bhOuterDia), "w 34lp!, h 27lp!, aligny top, pad 7 0 0 0");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       bhPanel.add(panel, "cell 4 2");
+                       panel.setLayout(null);
+                       bhImageBtn = new JButton("No Image");
+                       bhImageBtn.setMaximumSize(new Dimension(75, 75));
+                       bhImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(bhImageBtn);
+                       bhImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       bhImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               bhImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               bhImageBtn.setIcon(bhImage);
+                                       }
+                               }
+                       });
+                       
+               }
+               {
+                       JPanel crPanel = new JPanel();
+                       componentOverlayPanel.add(crPanel, "CENTERINGRING");
+                       crPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+                       
+                       JLabel crPartNoLabel = new JLabel("Part No:");
+                       crPanel.add(crPartNoLabel, "cell 0 0,alignx left");
+                       
+                       crPartNoTextField = new JTextField();
+                       crPanel.add(crPartNoTextField, "cell 1 0, growx");
+                       crPartNoTextField.setColumns(10);
+                       
+                       JLabel crDescLabel = new JLabel("Description:");
+                       crPanel.add(crDescLabel, "cell 3 0,alignx left");
+                       
+                       crDescTextField = new JTextField();
+                       crPanel.add(crDescTextField, "cell 4 0, growx");
+                       crDescTextField.setColumns(10);
+                       
+                       JLabel crThicknessLabel = new JLabel("Thickness:");
+                       crPanel.add(crThicknessLabel, "cell 0 1,alignx left");
+                       
+                       crThickness = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       JSpinner spin = new JSpinner(crThickness.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       crPanel.add(spin, "cell 1 1, growx");
+                       crPanel.add(new UnitSelector(crThickness), "growx");
+                       
+                       JLabel crMassLabel = new JLabel("Mass:");
+                       crPanel.add(crMassLabel, "cell 3 1,alignx left");
+                       
+                       crMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       spin = new JSpinner(crMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       crPanel.add(spin, "cell 4 1, growx");
+                       crPanel.add(new UnitSelector(crMass), "w 34lp!");
+                       
+                       JLabel crOuterDiaLabel = new JLabel("Outer Dia.:");
+                       crPanel.add(crOuterDiaLabel, "cell 0 2,alignx left");
+                       
+                       crOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(crOuterDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       crPanel.add(spin, "cell 1 2, growx");
+                       crPanel.add(new UnitSelector(crOuterDia), "w 34lp!");
+                       
+                       JLabel crInnerDiaLabel = new JLabel("Inner Dia.:");
+                       crPanel.add(crInnerDiaLabel, "cell 3 2,alignx left");
+                       
+                       crInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(crInnerDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       crPanel.add(spin, "cell 4 2, growx");
+                       crPanel.add(new UnitSelector(crInnerDia), "w 34lp!");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       crPanel.add(panel, "cell 4 3");
+                       panel.setLayout(null);
+                       crImageBtn = new JButton("No Image");
+                       crImageBtn.setMaximumSize(new Dimension(75, 75));
+                       crImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(crImageBtn);
+                       crImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       crImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               crImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               crImageBtn.setIcon(crImage);
+                                       }
+                               }
+                       });
+                       
+               }
+               {
+                       JPanel ebPanel = new JPanel();
+                       componentOverlayPanel.add(ebPanel, "ENGINEBLOCK");
+                       ebPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+                       JLabel ebPartNoLabel = new JLabel("Part No:");
+                       ebPanel.add(ebPartNoLabel, "cell 0 0,alignx left");
+                       
+                       ebPartNoTextField = new JTextField();
+                       ebPanel.add(ebPartNoTextField, "cell 1 0,growx");
+                       ebPartNoTextField.setColumns(10);
+                       
+                       JLabel ebDescLabel = new JLabel("Description:");
+                       ebPanel.add(ebDescLabel, "cell 3 0,alignx left");
+                       
+                       ebDescTextField = new JTextField();
+                       ebPanel.add(ebDescTextField, "cell 4 0,growx");
+                       ebDescTextField.setColumns(10);
+                       
+                       JLabel ebThicknessLabel = new JLabel("Thickness:");
+                       ebPanel.add(ebThicknessLabel, "cell 0 1,alignx left");
+                       
+                       ebThickness = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       JSpinner spin = new JSpinner(ebThickness.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ebPanel.add(spin, "cell 1 1, growx");
+                       ebPanel.add(new UnitSelector(ebThickness), "growx");
+                       
+                       JLabel ebMassLabel = new JLabel("Mass:");
+                       ebPanel.add(ebMassLabel, "cell 3 1,alignx left");
+                       
+                       ebMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       spin = new JSpinner(ebMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ebPanel.add(spin, "cell 4 1, growx");
+                       ebPanel.add(new UnitSelector(ebMass), "w 34lp!");
+                       
+                       JLabel ebOuterDiaLabel = new JLabel("Outer Dia.:");
+                       ebPanel.add(ebOuterDiaLabel, "cell 0 2,alignx left");
+                       
+                       ebOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(ebOuterDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ebPanel.add(spin, "cell 1 2, growx");
+                       ebPanel.add(new UnitSelector(ebOuterDia), "growx");
+                       
+                       JLabel ebInnerDiaLabel = new JLabel("Inner Dia.:");
+                       ebPanel.add(ebInnerDiaLabel, "cell 3 2,alignx left");
+                       
+                       ebInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(ebInnerDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       ebPanel.add(spin, "cell 4 2, growx");
+                       ebPanel.add(new UnitSelector(ebInnerDia), "w 34lp!");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       ebPanel.add(panel, "cell 4 3");
+                       panel.setLayout(null);
+                       ebImageBtn = new JButton("No Image");
+                       ebImageBtn.setMaximumSize(new Dimension(75, 75));
+                       ebImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(ebImageBtn);
+                       ebImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       ebImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               ebImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               ebImageBtn.setIcon(ebImage);
+                                       }
+                               }
+                       });
+               }
+               
+               {
+                       JPanel llPanel = new JPanel();
+                       componentOverlayPanel.add(llPanel, "LAUNCHLUG");
+                       llPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+                       JLabel llPartNoLabel = new JLabel("Part No:");
+                       llPanel.add(llPartNoLabel, "cell 0 0,alignx left");
+                       
+                       llPartNoTextField = new JTextField();
+                       llPanel.add(llPartNoTextField, "cell 1 0,growx");
+                       llPartNoTextField.setColumns(10);
+                       
+                       JLabel llDescLabel = new JLabel("Description:");
+                       llPanel.add(llDescLabel, "cell 3 0,alignx left");
+                       
+                       llDescTextField = new JTextField();
+                       llPanel.add(llDescTextField, "cell 4 0,growx");
+                       llDescTextField.setColumns(10);
+                       
+                       JLabel llLengthLabel = new JLabel("Length:");
+                       llPanel.add(llLengthLabel, "cell 0 1,alignx left");
+                       
+                       llLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       JSpinner spin = new JSpinner(llLength.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       llPanel.add(spin, "cell 1 1, growx");
+                       llPanel.add(new UnitSelector(llLength), "growx");
+                       
+                       JLabel llMassLabel = new JLabel("Mass:");
+                       llPanel.add(llMassLabel, "cell 3 1,alignx left");
+                       
+                       llMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       spin = new JSpinner(llMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       llPanel.add(spin, "cell 4 1, growx");
+                       llPanel.add(new UnitSelector(llMass), "w 34lp!");
+                       
+                       JLabel llOuterDiaLabel = new JLabel("Outer Dia.:");
+                       llPanel.add(llOuterDiaLabel, "cell 0 2,alignx left");
+                       
+                       llOuterDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(llOuterDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       llPanel.add(spin, "cell 1 2, growx");
+                       llPanel.add(new UnitSelector(llOuterDia), "growx");
+                       
+                       JLabel llInnerDiaLabel = new JLabel("Inner Dia.:");
+                       llPanel.add(llInnerDiaLabel, "cell 3 2,alignx left");
+                       
+                       llInnerDia = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(llInnerDia.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       llPanel.add(spin, "cell 4 2, growx");
+                       llPanel.add(new UnitSelector(llInnerDia), "w 34lp!");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       llPanel.add(panel, "cell 4 3");
+                       panel.setLayout(null);
+                       llImageBtn = new JButton("No Image");
+                       llImageBtn.setMaximumSize(new Dimension(75, 75));
+                       llImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(llImageBtn);
+                       llImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       llImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               llImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               llImageBtn.setIcon(llImage);
+                                       }
+                               }
+                       });
+               }
+               
+               {
+                       JPanel stPanel = new JPanel();
+                       componentOverlayPanel.add(stPanel, "STREAMER");
+                       stPanel.setLayout(new MigLayout("", "[][grow][][grow]", "[][][][]"));
+                       JLabel stPartNoLabel = new JLabel("Part No:");
+                       stPanel.add(stPartNoLabel, "cell 0 0,alignx left");
+                       
+                       stPartNoTextField = new JTextField();
+                       stPanel.add(stPartNoTextField, "cell 1 0,growx");
+                       stPartNoTextField.setColumns(10);
+                       
+                       JLabel stDescLabel = new JLabel("Description:");
+                       stPanel.add(stDescLabel, "cell 3 0,alignx left");
+                       
+                       stDescTextField = new JTextField();
+                       stPanel.add(stDescTextField, "cell 4 0,growx");
+                       stDescTextField.setColumns(10);
+                       
+                       JLabel stLengthLabel = new JLabel("Length:");
+                       stPanel.add(stLengthLabel, "cell 0 1,alignx left");
+                       
+                       stLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       JSpinner spin = new JSpinner(stLength.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       stPanel.add(spin, "cell 1 1, growx");
+                       stPanel.add(new UnitSelector(stLength), "growx");
+                       
+                       JLabel stMassLabel = new JLabel("Mass:");
+                       stPanel.add(stMassLabel, "cell 3 1,alignx left");
+                       
+                       stMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       spin = new JSpinner(stMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       stPanel.add(spin, "cell 4 1, growx");
+                       stPanel.add(new UnitSelector(stMass), "growx");
+                       
+                       JLabel stThicknessLabel = new JLabel("Thickness:");
+                       stPanel.add(stThicknessLabel, "cell 0 2,alignx left");
+                       
+                       stThickness = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(stThickness.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       stPanel.add(spin, "cell 1 2, growx");
+                       stPanel.add(new UnitSelector(stThickness), "growx");
+                       
+                       JLabel stWidthLabel = new JLabel("Width:");
+                       stPanel.add(stWidthLabel, "cell 3 2,alignx left");
+                       
+                       stWidth = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(stWidth.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       stPanel.add(spin, "cell 4 2, growx");
+                       stPanel.add(new UnitSelector(stWidth), "growx");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       stPanel.add(panel, "cell 4 3");
+                       panel.setLayout(null);
+                       stImageBtn = new JButton("No Image");
+                       stImageBtn.setMaximumSize(new Dimension(75, 75));
+                       stImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(stImageBtn);
+                       stImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       stImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               stImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               stImageBtn.setIcon(stImage);
+                                       }
+                               }
+                       });
+               }
+               
+               {
+                       JPanel pcPanel = new JPanel();
+                       componentOverlayPanel.add(pcPanel, "PARACHUTE");
+                       pcPanel.setLayout(new MigLayout("", "[][157.00,grow 79][65.00][grow][][]", "[][][][][][]"));
+                       JLabel pcPartNoLabel = new JLabel("Part No:");
+                       pcPanel.add(pcPartNoLabel, "cell 0 0,alignx left");
+                       
+                       pcPartNoTextField = new JTextField();
+                       pcPanel.add(pcPartNoTextField, "cell 1 0,growx");
+                       pcPartNoTextField.setColumns(10);
+                       
+                       JLabel pcDescLabel = new JLabel("Description:");
+                       pcPanel.add(pcDescLabel, "cell 3 0,alignx left");
+                       
+                       pcDescTextField = new JTextField();
+                       pcPanel.add(pcDescTextField, "cell 4 0,growx");
+                       pcDescTextField.setColumns(10);
+                       
+                       JLabel pcSidesLabel = new JLabel("Sides:");
+                       pcPanel.add(pcSidesLabel, "cell 0 1,alignx left");
+                       
+                       pcSides = new JTextField();
+                       pcPanel.add(pcSides, "cell 1 1, growx");
+                       pcSides.setInputVerifier(NON_NEGATIVE_INTEGER);
+                       pcSides.setColumns(10);
+                       
+                       JLabel pcMassLabel = new JLabel("Mass:");
+                       pcPanel.add(pcMassLabel, "cell 3 1,alignx left");
+                       
+                       pcMass = new DoubleModel(0, UnitGroup.UNITS_MASS, 0);
+                       JSpinner spin = new JSpinner(pcMass.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       pcPanel.add(spin, "cell 4 1, growx");
+                       pcPanel.add(new UnitSelector(pcMass), "growx");
+                       
+                       JLabel pcDiameterLabel = new JLabel("Diameter:");
+                       pcPanel.add(pcDiameterLabel, "cell 0 2,alignx left");
+                       
+                       pcDiameter = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(pcDiameter.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       pcPanel.add(spin, "cell 1 2, growx");
+                       pcPanel.add(new UnitSelector(pcDiameter));
+                       
+                       JLabel pcLineLengthLabel = new JLabel("Line Length:");
+                       pcPanel.add(pcLineLengthLabel, "cell 3 2,alignx left");
+                       
+                       pcLineLength = new DoubleModel(0, UnitGroup.UNITS_LENGTH, 0);
+                       spin = new JSpinner(pcLineLength.getSpinnerModel());
+                       spin.setEditor(new SpinnerEditor(spin));
+                       pcPanel.add(spin, "cell 4 2, growx");
+                       pcPanel.add(new UnitSelector(pcLineLength), "growx");
+                       
+                       JLabel pcLineCountLabel = new JLabel("Line Count:");
+                       pcPanel.add(pcLineCountLabel, "cell 3 3,alignx left");
+                       
+                       pcLineCount = new JTextField();
+                       pcLineCount.setInputVerifier(NON_NEGATIVE_INTEGER);
+                       pcPanel.add(pcLineCount, "cell 4 3, growx");
+                       pcLineCount.setColumns(10);
+                       
+                       JLabel pcLineMaterialLabel = new JLabel("Line Material:");
+                       pcPanel.add(pcLineMaterialLabel, "cell 3 4,alignx left, aligny top, pad 7 0 0 0 ");
+                       
+                       pcLineMaterialChooser = new MaterialChooser();
+                       pcLineMaterialChooser.setModel(new MaterialModel(PresetEditorDialog.this, Material.Type.LINE));
+                       pcPanel.add(pcLineMaterialChooser, "cell 4 4, span 3 1, growx, aligny top");
+                       
+                       JPanel panel = new JPanel();
+                       panel.setMinimumSize(new Dimension(200, 200));
+                       pcPanel.add(panel, "cell 1 3, span 1 3");
+                       panel.setLayout(null);
+                       pcImageBtn = new JButton("No Image");
+                       pcImageBtn.setMaximumSize(new Dimension(75, 75));
+                       pcImageBtn.setMinimumSize(new Dimension(75, 75));
+                       panel.add(pcImageBtn);
+                       pcImageBtn.setBounds(new Rectangle(6, 6, 132, 145));
+                       
+                       pcImageBtn.addActionListener(new ActionListener() {
+                               @Override
+                               public void actionPerformed(final ActionEvent e) {
+                                       int returnVal = imageChooser.showOpenDialog(PresetEditorDialog.this);
+                                       
+                                       if (returnVal == JFileChooser.APPROVE_OPTION) {
+                                               File file = imageChooser.getSelectedFile();
+                                               pcImage = scaleImage(new ImageIcon(file.getAbsolutePath()).getImage(), 155);
+                                               pcImageBtn.setIcon(pcImage);
+                                       }
+                               }
+                       });
+               }
+               
+               JPanel buttonPane = new JPanel();
+               getContentPane().add(buttonPane, BorderLayout.SOUTH);
+               buttonPane.setLayout(new MigLayout("", "[130px][176.00px][131.00px]", "[29px]"));
+               JButton btnSaveAndNew = new JButton("Save and New");
+               btnSaveAndNew.addMouseListener(new MouseAdapter() {
+                       @Override
+                       public void mouseClicked(MouseEvent arg0) {
+                               saveResult();
+                       }
+               });
+               buttonPane.add(btnSaveAndNew, "cell 0 0,alignx left,aligny top");
+               
+               JButton okButton = new JButton("Save and Close");
+               okButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent event) {
+                               if (saveResult()) {
+                                       dispose();
+                               }
+                       }
+               });
+               okButton.setActionCommand("OK");
+               buttonPane.add(okButton, "cell 1 0,alignx left,aligny top");
+               getRootPane().setDefaultButton(okButton);
+               
+               JButton cancelButton = new JButton("Close");
+               cancelButton.addActionListener(new ActionListener() {
+                       @Override
+                       public void actionPerformed(ActionEvent event) {
+                               dispose();
+                       }
+               });
+               cancelButton.setActionCommand("Close");
+               buttonPane.add(cancelButton, "cell 6 0,alignx right,aligny top");
+               
+               if (toEdit != null) {
+                       fillEditor(toEdit, matHolder);
+               }
+               holder = matHolder;
+       }
+       
+       /**
+        * When an existing preset is edited, we want to disable the other types of presets.  If the user wants a different
+        * type of component, then they should delete this one and add a new one.
+        *
+        * @param cb     the combo box component
+        * @param preset the preset being edited
+        */
+       private void setItems(DeselectableComboBox cb, ComponentPreset preset) {
+               cb.addItem(trans.get(NOSE_CONE_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.NOSE_CONE));
+               cb.addItem(trans.get(BODY_TUBE_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.BODY_TUBE));
+               cb.addItem(trans.get(BULKHEAD_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.BULK_HEAD));
+               cb.addItem(trans.get(CR_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.CENTERING_RING));
+               cb.addItem(trans.get(EB_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.ENGINE_BLOCK));
+               cb.addItem(trans.get(TRANSITION_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.TRANSITION));
+               cb.addItem(trans.get(TUBE_COUPLER_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.TUBE_COUPLER));
+               cb.addItem(trans.get(LAUNCH_LUG_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.LAUNCH_LUG));
+               cb.addItem(trans.get(PARACHUTE_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.PARACHUTE));
+               cb.addItem(trans.get(STREAMER_KEY), preset != null && !preset.get(ComponentPreset.TYPE).equals(ComponentPreset.Type.STREAMER));
+       }
+       
+       /**
+        * Create an image chooser.  Currently png and jpg are supported.
+        *
+        * @return a file chooser that looks for image files
+        */
+       private JFileChooser createImageChooser() {
+               final JFileChooser chooser = new JFileChooser();
+               ImagePreviewPanel preview = new ImagePreviewPanel();
+               chooser.setAccessory(preview);
+               chooser.addPropertyChangeListener(preview);
+               chooser.setAcceptAllFileFilterUsed(false);
+               chooser.addChoosableFileFilter(new FileNameExtensionFilter("Image Files", "png", "jpg", "jpeg"));
+               return chooser;
+       }
+       
+       /**
+        * To support editing of an existing preset, the swing components need to be prepopulated with the field data.
+        *
+        * @param preset the preset to edit
+        */
+       private void fillEditor(ComponentPreset preset, MaterialHolder holder) {
+               ComponentPreset.Type t = preset.getType();
+               
+               mfgTextField.setText(preset.get(ComponentPreset.MANUFACTURER).getDisplayName());
+               setMaterial(materialChooser, preset, holder, Material.Type.BULK, ComponentPreset.MATERIAL);
+               switch (t) {
+               case BODY_TUBE:
+                       typeCombo.setSelectedItem(trans.get(BODY_TUBE_KEY));
+                       btDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       
+                       if (preset.has(ComponentPreset.INNER_DIAMETER)) {
+                               btInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                               btInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               btLength.setValue(preset.get(ComponentPreset.LENGTH));
+                               btLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               btMass.setValue(preset.get(ComponentPreset.MASS));
+                               btMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+                               btOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                               btOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               btImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               btImageBtn.setIcon(btImage);
+                       }
+                       btPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       break;
+               case BULK_HEAD:
+                       typeCombo.setSelectedItem(trans.get(BULKHEAD_KEY));
+                       bhDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               bhLength.setValue(preset.get(ComponentPreset.LENGTH));
+                               bhLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               bhMass.setValue(preset.get(ComponentPreset.MASS));
+                               bhMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+                               bhOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                               bhOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               bhImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               bhImageBtn.setIcon(bhImage);
+                       }
+                       bhPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       break;
+               case CENTERING_RING:
+                       typeCombo.setSelectedItem(trans.get(CR_KEY));
+                       crDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.INNER_DIAMETER)) {
+                               crInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                               crInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               crThickness.setValue(preset.get(ComponentPreset.LENGTH));
+                               crThickness.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               crMass.setValue(preset.get(ComponentPreset.MASS));
+                               crMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+                               crOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                               crOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               crImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               crImageBtn.setIcon(crImage);
+                       }
+                       crPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       break;
+               case ENGINE_BLOCK:
+                       typeCombo.setSelectedItem(trans.get(EB_KEY));
+                       ebDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.INNER_DIAMETER)) {
+                               ebInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                               ebInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               ebThickness.setValue(preset.get(ComponentPreset.LENGTH));
+                               ebThickness.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               ebMass.setValue(preset.get(ComponentPreset.MASS));
+                               ebMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+                               ebOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                               ebOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               ebImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               ebImageBtn.setIcon(ebImage);
+                       }
+                       ebPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       break;
+               case NOSE_CONE:
+                       typeCombo.setSelectedItem(trans.get(NOSE_CONE_KEY));
+                       ncDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.AFT_OUTER_DIAMETER)) {
+                               ncAftDia.setValue(preset.get(ComponentPreset.AFT_OUTER_DIAMETER));
+                               ncAftDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.AFT_SHOULDER_DIAMETER)) {
+                               ncAftShoulderDia.setValue(preset.get(ComponentPreset.AFT_SHOULDER_DIAMETER));
+                               ncAftShoulderDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.AFT_SHOULDER_LENGTH)) {
+                               ncAftShoulderLen.setValue(preset.get(ComponentPreset.AFT_SHOULDER_LENGTH));
+                               ncAftShoulderLen.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               ncMass.setValue(preset.get(ComponentPreset.MASS));
+                               ncMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.SHAPE)) {
+                               ncShapeCB.setSelectedItem(preset.get(ComponentPreset.SHAPE).toString());
+                       }
+                       if (preset.has(ComponentPreset.FILLED)) {
+                               ncFilledCB.setSelected((preset.get(ComponentPreset.FILLED)));
+                       }
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               ncLength.setValue(preset.get(ComponentPreset.LENGTH));
+                               ncLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               ncImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               ncImageBtn.setIcon(ncImage);
+                       }
+                       ncPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       break;
+               case TRANSITION:
+                       typeCombo.setSelectedItem(trans.get(TRANSITION_KEY));
+                       trDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.AFT_OUTER_DIAMETER)) {
+                               trAftDia.setValue(preset.get(ComponentPreset.AFT_OUTER_DIAMETER));
+                               trAftDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.AFT_SHOULDER_DIAMETER)) {
+                               trAftShoulderDia.setValue(preset.get(ComponentPreset.AFT_SHOULDER_DIAMETER));
+                               trAftShoulderDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.AFT_SHOULDER_LENGTH)) {
+                               trAftShoulderLen.setValue(preset.get(ComponentPreset.AFT_SHOULDER_LENGTH));
+                               trAftShoulderLen.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.FORE_OUTER_DIAMETER)) {
+                               trForeDia.setValue(preset.get(ComponentPreset.FORE_OUTER_DIAMETER));
+                               trForeDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.FORE_SHOULDER_DIAMETER)) {
+                               trForeShoulderDia.setValue(preset.get(ComponentPreset.FORE_SHOULDER_DIAMETER));
+                               trForeShoulderDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.FORE_SHOULDER_LENGTH)) {
+                               trForeShoulderLen.setValue(preset.get(ComponentPreset.FORE_SHOULDER_LENGTH));
+                               trForeShoulderLen.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               trMass.setValue(preset.get(ComponentPreset.MASS));
+                               trMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.SHAPE)) {
+                               trShapeCB.setSelectedItem(preset.get(ComponentPreset.SHAPE).toString());
+                       }
+                       if (preset.has(ComponentPreset.FILLED)) {
+                               trFilledCB.setSelected((preset.get(ComponentPreset.FILLED)));
+                       }
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               trLength.setValue(preset.get(ComponentPreset.LENGTH));
+                               trLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               trImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               trImageBtn.setIcon(trImage);
+                       }
+                       trPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       break;
+               case TUBE_COUPLER:
+                       typeCombo.setSelectedItem(trans.get(TUBE_COUPLER_KEY));
+                       tcDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.INNER_DIAMETER)) {
+                               tcInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                               tcInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               tcLength.setValue(preset.get(ComponentPreset.LENGTH));
+                               tcLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               tcMass.setValue(preset.get(ComponentPreset.MASS));
+                               tcMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+                               tcOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                               tcOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       tcPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               tcImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               tcImageBtn.setIcon(tcImage);
+                       }
+                       break;
+               case LAUNCH_LUG:
+                       typeCombo.setSelectedItem(trans.get(LAUNCH_LUG_KEY));
+                       llDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.INNER_DIAMETER)) {
+                               llInnerDia.setValue(preset.get(ComponentPreset.INNER_DIAMETER));
+                               llInnerDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               llLength.setValue(preset.get(ComponentPreset.LENGTH));
+                               llLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               llMass.setValue(preset.get(ComponentPreset.MASS));
+                               llMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.OUTER_DIAMETER)) {
+                               llOuterDia.setValue(preset.get(ComponentPreset.OUTER_DIAMETER));
+                               llOuterDia.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       llPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               llImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               llImageBtn.setIcon(llImage);
+                       }
+                       break;
+               case PARACHUTE:
+                       setMaterial(materialChooser, preset, holder, Material.Type.SURFACE, ComponentPreset.MATERIAL);
+                       typeCombo.setSelectedItem(trans.get(PARACHUTE_KEY));
+                       pcDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.LINE_COUNT)) {
+                               pcLineCount.setText(preset.get(ComponentPreset.LINE_COUNT).toString());
+                       }
+                       if (preset.has(ComponentPreset.SIDES)) {
+                               pcSides.setText(preset.get(ComponentPreset.SIDES).toString());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               pcMass.setValue(preset.get(ComponentPreset.MASS));
+                               pcMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.DIAMETER)) {
+                               pcDiameter.setValue(preset.get(ComponentPreset.DIAMETER));
+                               pcDiameter.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.LINE_LENGTH)) {
+                               pcLineLength.setValue(preset.get(ComponentPreset.LINE_LENGTH));
+                               pcLineLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       pcPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               pcImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               pcImageBtn.setIcon(pcImage);
+                       }
+                       setMaterial(pcLineMaterialChooser, preset, holder, Material.Type.LINE, ComponentPreset.LINE_MATERIAL);
+                       //                pcLineMaterialChooser.setModel(new MaterialModel(PresetEditorDialog.this, Material.Type.LINE));
+                       
+                       //                pcLineMaterialChooser.getModel().setSelectedItem(preset.get(ComponentPreset.LINE_MATERIAL));
+                       break;
+               case STREAMER:
+                       setMaterial(materialChooser, preset, holder, Material.Type.SURFACE, ComponentPreset.MATERIAL);
+                       typeCombo.setSelectedItem(trans.get(STREAMER_KEY));
+                       stDescTextField.setText(preset.get(ComponentPreset.DESCRIPTION));
+                       if (preset.has(ComponentPreset.LENGTH)) {
+                               stLength.setValue(preset.get(ComponentPreset.LENGTH));
+                               stLength.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.THICKNESS)) {
+                               stThickness.setValue(preset.get(ComponentPreset.LENGTH));
+                               stThickness.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.MASS)) {
+                               stMass.setValue(preset.get(ComponentPreset.MASS));
+                               stMass.setCurrentUnit(UnitGroup.UNITS_MASS.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.WIDTH)) {
+                               stWidth.setValue(preset.get(ComponentPreset.WIDTH));
+                               stWidth.setCurrentUnit(UnitGroup.UNITS_LENGTH.getDefaultUnit());
+                       }
+                       if (preset.has(ComponentPreset.IMAGE)) {
+                               stImage = new ImageIcon(byteArrayToImage(preset.get(ComponentPreset.IMAGE)));
+                               stImageBtn.setIcon(stImage);
+                       }
+                       stPartNoTextField.setText(preset.get(ComponentPreset.PARTNO));
+                       break;
+               default:
+               }
+       }
+       
+       private void setMaterial(final JComboBox chooser, final ComponentPreset preset, final MaterialHolder holder,
+                       final Material.Type theType, final TypedKey key) {
+               if (holder == null) {
+                       chooser.setModel(new MaterialModel(PresetEditorDialog.this, theType));
+               }
+               else {
+                       chooser.setModel(new MaterialModel(PresetEditorDialog.this, theType,
+                                       holder.asDatabase(theType)));
+               }
+               if (preset != null) {
+                       chooser.getModel().setSelectedItem(preset.get(key));
+               }
+       }
+       
+       /**
+        * Extract the preset data from the UI fields, create a ComponentPreset instance, and notify the listener.
+        */
+       private boolean saveResult() {
+               String type = (String) typeCombo.getSelectedItem();
+               
+               ComponentPreset result = null;
+               
+               if (type.equals(trans.get(NOSE_CONE_KEY))) {
+                       result = extractNoseCone();
+                       if (result != null) {
+                               clearNoseCone();
+                       }
+               }
+               else if (type.equals(trans.get(TRANSITION_KEY))) {
+                       result = extractTransition();
+                       if (result != null) {
+                               clearTransition();
+                       }
+               }
+               else if (type.equals(trans.get(BODY_TUBE_KEY))) {
+                       result = extractBodyTube();
+                       if (result != null) {
+                               clearBodyTube();
+                       }
+               }
+               else if (type.equals(trans.get(TUBE_COUPLER_KEY))) {
+                       result = extractTubeCoupler();
+                       if (result != null) {
+                               clearTubeCoupler();
+                       }
+               }
+               else if (type.equals(trans.get(EB_KEY))) {
+                       result = extractEngineBlock();
+                       if (result != null) {
+                               clearEngineBlock();
+                       }
+               }
+               else if (type.equals(trans.get(CR_KEY))) {
+                       result = extractCenteringRing();
+                       if (result != null) {
+                               clearCenteringRing();
+                       }
+               }
+               else if (type.equals(trans.get(BULKHEAD_KEY))) {
+                       result = extractBulkhead();
+                       if (result != null) {
+                               clearBulkhead();
+                       }
+               }
+               else if (type.equals(trans.get(LAUNCH_LUG_KEY))) {
+                       result = extractLaunchLug();
+                       if (result != null) {
+                               clearLaunchLug();
+                       }
+               }
+               else if (type.equals(trans.get(PARACHUTE_KEY))) {
+                       result = extractParachute();
+                       if (result != null) {
+                               clearParachute();
+                       }
+               }
+               else if (type.equals(trans.get(STREAMER_KEY))) {
+                       result = extractStreamer();
+                       if (result != null) {
+                               clearStreamer();
+                       }
+               }
+               if (result != null) {
+                       resultListener.notifyResult(result);
+                       return true;
+               }
+               else {
+                       return false;
+               }
+       }
+       
+       private ComponentPreset extractNoseCone() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+                       props.put(ComponentPreset.AFT_OUTER_DIAMETER, ncAftDia.getValue());
+                       props.put(ComponentPreset.AFT_SHOULDER_DIAMETER, ncAftShoulderDia.getValue());
+                       props.put(ComponentPreset.AFT_SHOULDER_LENGTH, ncAftShoulderLen.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, ncDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, ncPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       props.put(ComponentPreset.LENGTH, ncLength.getValue());
+                       props.put(ComponentPreset.SHAPE, Transition.Shape.toShape((String) ncShapeCB.getSelectedItem()));
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, ncMass.getValue());
+                       props.put(ComponentPreset.FILLED, ncFilledCB.isSelected());
+                       if (ncImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(ncImage.getImage()));
+                       }
+                       
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert nose cone attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory nose cone attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearNoseCone() {
+               ncAftDia.setValue(0);
+               ncAftShoulderDia.setValue(0);
+               ncAftShoulderLen.setValue(0);
+               ncDescTextField.setText("");
+               ncPartNoTextField.setText("");
+               ncLength.setValue(0);
+               ncMass.setValue(0);
+               ncFilledCB.setSelected(false);
+               ncImage = null;
+               ncImageBtn.setIcon(null);
+       }
+       
+       private ComponentPreset extractTransition() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+                       props.put(ComponentPreset.AFT_OUTER_DIAMETER, trAftDia.getValue());
+                       props.put(ComponentPreset.AFT_SHOULDER_DIAMETER, trAftShoulderDia.getValue());
+                       props.put(ComponentPreset.AFT_SHOULDER_LENGTH, trAftShoulderLen.getValue());
+                       props.put(ComponentPreset.FORE_OUTER_DIAMETER, trForeDia.getValue());
+                       props.put(ComponentPreset.FORE_SHOULDER_DIAMETER, trForeShoulderDia.getValue());
+                       props.put(ComponentPreset.FORE_SHOULDER_LENGTH, trForeShoulderLen.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, trDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, trPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       
+                       props.put(ComponentPreset.LENGTH, trLength.getValue());
+                       props.put(ComponentPreset.SHAPE, Transition.Shape.toShape((String) trShapeCB.getSelectedItem()));
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, trMass.getValue());
+                       props.put(ComponentPreset.FILLED, trFilledCB.isSelected());
+                       if (trImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(trImage.getImage()));
+                       }
+                       
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert transition attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory transition attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearTransition() {
+               trAftDia.setValue(0);
+               trAftShoulderDia.setValue(0);
+               trAftShoulderLen.setValue(0);
+               trForeDia.setValue(0);
+               trForeShoulderDia.setValue(0);
+               trForeShoulderLen.setValue(0);
+               trDescTextField.setText("");
+               trPartNoTextField.setText("");
+               trLength.setValue(0);
+               trMass.setValue(0);
+               trFilledCB.setSelected(false);
+               trImage = null;
+               trImageBtn.setIcon(null);
+       }
+       
+       private ComponentPreset extractBodyTube() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+                       props.put(ComponentPreset.OUTER_DIAMETER, btOuterDia.getValue());
+                       props.put(ComponentPreset.INNER_DIAMETER, btInnerDia.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, btDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, btPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       props.put(ComponentPreset.LENGTH, btLength.getValue());
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, btMass.getValue());
+                       if (btImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(btImage.getImage()));
+                       }
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert body tube attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory body tube attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearBodyTube() {
+               btOuterDia.setValue(0);
+               btInnerDia.setValue(0);
+               btDescTextField.setText("");
+               btPartNoTextField.setText("");
+               btLength.setValue(0);
+               btMass.setValue(0);
+               btImage = null;
+               btImageBtn.setIcon(null);
+       }
+       
+       public ComponentPreset extractTubeCoupler() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+                       props.put(ComponentPreset.OUTER_DIAMETER, tcOuterDia.getValue());
+                       props.put(ComponentPreset.INNER_DIAMETER, tcInnerDia.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, tcDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, tcPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       props.put(ComponentPreset.LENGTH, tcLength.getValue());
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, tcMass.getValue());
+                       if (tcImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(tcImage.getImage()));
+                       }
+                       
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert tube coupler attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory tube coupler attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearTubeCoupler() {
+               tcOuterDia.setValue(0);
+               tcInnerDia.setValue(0);
+               tcDescTextField.setText("");
+               tcPartNoTextField.setText("");
+               tcLength.setValue(0);
+               tcMass.setValue(0);
+               tcImage = null;
+               tcImageBtn.setIcon(null);
+       }
+       
+       private ComponentPreset extractBulkhead() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+                       props.put(ComponentPreset.OUTER_DIAMETER, bhOuterDia.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, bhDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, bhPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       props.put(ComponentPreset.LENGTH, bhLength.getValue());
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, bhMass.getValue());
+                       if (bhImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(bhImage.getImage()));
+                       }
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert bulkhead attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory bulkhead attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearBulkhead() {
+               bhOuterDia.setValue(0);
+               bhDescTextField.setText("");
+               bhPartNoTextField.setText("");
+               bhLength.setValue(0);
+               bhMass.setValue(0);
+               bhImage = null;
+               bhImageBtn.setIcon(null);
+       }
+       
+       private ComponentPreset extractCenteringRing() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+                       props.put(ComponentPreset.OUTER_DIAMETER, crOuterDia.getValue());
+                       props.put(ComponentPreset.INNER_DIAMETER, crInnerDia.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, crDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, crPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       props.put(ComponentPreset.LENGTH, crThickness.getValue());
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, crMass.getValue());
+                       if (crImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(crImage.getImage()));
+                       }
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert centering ring attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory centering ring attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearCenteringRing() {
+               crOuterDia.setValue(0);
+               crInnerDia.setValue(0);
+               crDescTextField.setText("");
+               crPartNoTextField.setText("");
+               crThickness.setValue(0);
+               crMass.setValue(0);
+               crImage = null;
+               crImageBtn.setIcon(null);
+       }
+       
+       public ComponentPreset extractEngineBlock() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+                       props.put(ComponentPreset.OUTER_DIAMETER, ebOuterDia.getValue());
+                       props.put(ComponentPreset.INNER_DIAMETER, ebInnerDia.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, ebDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, ebPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       props.put(ComponentPreset.LENGTH, ebThickness.getValue());
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, ebMass.getValue());
+                       if (ebImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(ebImage.getImage()));
+                       }
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert engine block attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory engine block attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearEngineBlock() {
+               ebOuterDia.setValue(0);
+               ebInnerDia.setValue(0);
+               ebDescTextField.setText("");
+               ebPartNoTextField.setText("");
+               ebThickness.setValue(0);
+               ebMass.setValue(0);
+               ebImage = null;
+               ebImageBtn.setIcon(null);
+       }
+       
+       public ComponentPreset extractLaunchLug() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+                       props.put(ComponentPreset.OUTER_DIAMETER, llOuterDia.getValue());
+                       props.put(ComponentPreset.INNER_DIAMETER, llInnerDia.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, llDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, llPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       props.put(ComponentPreset.LENGTH, llLength.getValue());
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, llMass.getValue());
+                       if (llImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(llImage.getImage()));
+                       }
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert launch lug attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory launch lug attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearLaunchLug() {
+               llOuterDia.setValue(0);
+               llInnerDia.setValue(0);
+               llDescTextField.setText("");
+               llPartNoTextField.setText("");
+               llLength.setValue(0);
+               llMass.setValue(0);
+               llImage = null;
+               llImageBtn.setIcon(null);
+       }
+       
+       public ComponentPreset extractParachute() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.PARACHUTE);
+                       props.put(ComponentPreset.DIAMETER, pcDiameter.getValue());
+                       props.put(ComponentPreset.DESCRIPTION, pcDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, pcPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       if (!pcLineCount.getText().equals("")) {
+                               props.put(ComponentPreset.LINE_COUNT, Integer.parseInt(pcLineCount.getText()));
+                       }
+                       if (!pcSides.getText().equals("")) {
+                               props.put(ComponentPreset.SIDES, Integer.parseInt(pcSides.getText()));
+                       }
+                       props.put(ComponentPreset.LINE_LENGTH, pcLineLength.getValue());
+                       Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       material = (Material) pcLineMaterialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.LINE_MATERIAL, material);
+                       }
+                       props.put(ComponentPreset.MASS, pcMass.getValue());
+                       if (pcImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(pcImage.getImage()));
+                       }
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert parachute attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory parachute attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearParachute() {
+               ebOuterDia.setValue(0);
+               ebInnerDia.setValue(0);
+               ebDescTextField.setText("");
+               ebPartNoTextField.setText("");
+               ebThickness.setValue(0);
+               ebMass.setValue(0);
+               ebImage = null;
+               ebImageBtn.setIcon(null);
+       }
+       
+       public ComponentPreset extractStreamer() {
+               TypedPropertyMap props = new TypedPropertyMap();
+               try {
+                       props.put(ComponentPreset.TYPE, ComponentPreset.Type.STREAMER);
+                       props.put(ComponentPreset.DESCRIPTION, stDescTextField.getText());
+                       props.put(ComponentPreset.PARTNO, stPartNoTextField.getText());
+                       props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(mfgTextField.getText()));
+                       props.put(ComponentPreset.THICKNESS, stThickness.getValue());
+                       props.put(ComponentPreset.LENGTH, stLength.getValue());
+                       props.put(ComponentPreset.WIDTH, stWidth.getValue());
+                       final Material material = (Material) materialChooser.getSelectedItem();
+                       if (material != null) {
+                               props.put(ComponentPreset.MATERIAL, material);
+                       }
+                       else {
+                               JOptionPane.showMessageDialog(null, "A material must be selected.", "Error", JOptionPane.ERROR_MESSAGE);
+                               return null;
+                       }
+                       props.put(ComponentPreset.MASS, stMass.getValue());
+                       if (stImage != null) {
+                               props.put(ComponentPreset.IMAGE, imageToByteArray(stImage.getImage()));
+                       }
+                       return ComponentPresetFactory.create(props);
+               } catch (NumberFormatException nfe) {
+                       JOptionPane.showMessageDialog(null, "Could not convert engine block attribute.", "Error", JOptionPane.ERROR_MESSAGE);
+               } catch (InvalidComponentPresetException e) {
+                       JOptionPane.showMessageDialog(null, craftErrorMessage(e, "Mandatory engine block attribute not set."), "Error", JOptionPane.ERROR_MESSAGE);
+               }
+               return null;
+       }
+       
+       private void clearStreamer() {
+               stWidth.setValue(0);
+               stLength.setValue(0);
+               stDescTextField.setText("");
+               stPartNoTextField.setText("");
+               stThickness.setValue(0);
+               stMass.setValue(0);
+               stImage = null;
+               stImageBtn.setIcon(null);
+       }
+       
+       @Override
+       public void itemStateChanged(ItemEvent evt) {
+               CardLayout cl = (CardLayout) (componentOverlayPanel.getLayout());
+               final String item = (String) evt.getItem();
+               if (materialChooser != null && evt.getStateChange() == ItemEvent.SELECTED) {
+                       if (item.equals(trans.get(PARACHUTE_KEY)) || item.equals(trans.get(STREAMER_KEY))) {
+                               if (!((MaterialModel) materialChooser.getModel()).getType().equals(Material.Type.SURFACE)) {
+                                       setMaterial(materialChooser, null, holder, Material.Type.SURFACE, ComponentPreset.MATERIAL);
+                               }
+                       }
+                       else {
+                               if (!((MaterialModel) materialChooser.getModel()).getType().equals(Material.Type.BULK)) {
+                                       setMaterial(materialChooser, null, holder, Material.Type.BULK, ComponentPreset.MATERIAL);
+                               }
+                       }
+               }
+               cl.show(componentOverlayPanel, componentMap.get(item));
+       }
+       
+       //Todo: I18N
+       private String craftErrorMessage(InvalidComponentPresetException e, String baseMsg) {
+               StringBuilder stringBuilder = new StringBuilder();
+               List<String> invalids = e.getErrors();
+               stringBuilder.append(baseMsg).append("\n");
+               for (int i = 0; i < invalids.size(); i++) {
+                       String s = invalids.get(i);
+                       stringBuilder.append(s).append("\n");
+               }
+               
+               return stringBuilder.toString();
+       }
+       
+       /**
+        * Convert an image to a byte array in png format.
+        *
+        * @param originalImage
+        *
+        * @return
+        */
+       private byte[] imageToByteArray(Image originalImage) {
+               byte[] imageInByte = null;
+               try {
+                       BufferedImage bi = imageToBufferedImage(originalImage);
+                       ByteArrayOutputStream baos = new ByteArrayOutputStream();
+                       ImageIO.write(bi, "png", baos);
+                       baos.flush();
+                       imageInByte = baos.toByteArray();
+                       baos.close();
+               } catch (IOException e) {
+                       log.error("Could not read image.");
+               }
+               return imageInByte;
+       }
+       
+       private BufferedImage imageToBufferedImage(final Image originalImage) {
+               BufferedImage bi = new BufferedImage(originalImage.getWidth(null), originalImage.getHeight(null), BufferedImage.TYPE_INT_RGB);
+               
+               Graphics2D g2 = bi.createGraphics();
+               g2.drawImage(originalImage, 0, 0, null);
+               return bi;
+       }
+       
+       private BufferedImage byteArrayToImage(byte[] src) {
+               // convert byte array back to BufferedImage
+               InputStream in = new ByteArrayInputStream(src);
+               try {
+                       return ImageIO.read(in);
+               } catch (IOException e) {
+                       log.error("Could not convert image.");
+               }
+               return null;
+       }
+       
+       private ImageIcon scaleImage(Image image, int targetDimension) {
+               int width = image.getWidth(this);
+               int height = image.getHeight(this);
+               double ratio = 1.0;
+               
+               /*
+                * Determine how to scale the image. Since the accessory can expand
+                * vertically make sure we don't go larger than 150 when scaling
+                * vertically.
+                */
+               if (width >= height) {
+                       ratio = (double) (targetDimension - 5) / width;
+                       width = targetDimension - 5;
+                       height = (int) (height * ratio);
+               }
+               else {
+                       if (getHeight() > 150) {
+                               ratio = (double) (targetDimension - 5) / height;
+                               height = targetDimension - 5;
+                               width = (int) (width * ratio);
+                       }
+                       else {
+                               ratio = (double) getHeight() / height;
+                               height = getHeight();
+                               width = (int) (width * ratio);
+                       }
+               }
+               
+               return new ImageIcon(image.getScaledInstance(width, height, Image.SCALE_DEFAULT));
+       }
+       
+       static class PresetInputVerifier extends InputVerifier {
+               
+               /**
+                * Matches user input against a regular expression.
+                */
+               private Matcher matcher;
+               
+               PresetInputVerifier(final Pattern thePattern) {
+                       matcher = thePattern.matcher("");
+               }
+               
+               /**
+                * Return true only if the untrimmed user input matches the regular expression provided to the constructor.
+                *
+                * @param aComponent must be an instance of JTextComponent.
+                */
+               @Override
+               public boolean verify(JComponent aComponent) {
+                       JTextComponent textComponent = (JTextComponent) aComponent;
+                       String text = textComponent.getText();
+                       matcher.reset(text);
+                       return matcher.matches();
+               }
+               
+               /**
+                * Always returns <tt>true</tt>, in this implementation, such that focus can always transfer to another
+                * component whenever the validation fails.
+                * <p/>
+                * <P>If <tt>super.shouldYieldFocus</tt> returns <tt>false</tt>, then clear the text field.
+                *
+                * @param aComponent is a <tt>JTextComponent</tt>.
+                */
+               @Override
+               public boolean shouldYieldFocus(JComponent aComponent) {
+                       if (!super.shouldYieldFocus(aComponent)) {
+                               ((JTextComponent) aComponent).setText("");
+                       }
+                       return true;
+               }
+       }
+       
+       class MaterialChooser extends JComboBox {
+               
+               public MaterialChooser() {
+               }
+               
+               public MaterialChooser(MaterialModel model) {
+                       super(model);
+               }
+               
+               /**
+                * Sets the data model that the <code>JComboBox</code> uses to obtain the list of items.
+                *
+                * @param aModel the <code>ComboBoxModel</code> that provides the displayed list of items
+                *
+                * @beaninfo bound: true description: Model that the combo box uses to get data to display.
+                */
+               @Override
+               public void setModel(final ComboBoxModel aModel) {
+                       if (getModel() instanceof MaterialModel) {
+                               MaterialModel old = (MaterialModel) getModel();
+                               old.removeListener();
+                       }
+                       super.setModel(aModel);
+                       
+               }
+       }
+}
diff --git a/core/src/net/sf/openrocket/gui/preset/PresetResultListener.java b/core/src/net/sf/openrocket/gui/preset/PresetResultListener.java
new file mode 100644 (file)
index 0000000..a5c2e1b
--- /dev/null
@@ -0,0 +1,11 @@
+
+package net.sf.openrocket.gui.preset;
+
+import net.sf.openrocket.preset.ComponentPreset;
+
+/**
+ */
+public interface PresetResultListener {
+
+    void notifyResult(ComponentPreset preset);
+}
diff --git a/core/src/net/sf/openrocket/gui/print/AbstractPrintable.java b/core/src/net/sf/openrocket/gui/print/AbstractPrintable.java
new file mode 100644 (file)
index 0000000..585e497
--- /dev/null
@@ -0,0 +1,80 @@
+package net.sf.openrocket.gui.print;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
+import java.awt.image.BufferedImage;
+
+public abstract class AbstractPrintable<T> extends PrintableComponent {
+    /**
+     * A thin stroke.
+     */
+    public final static BasicStroke thinStroke = new BasicStroke(1.0f);
+
+    /**
+     * A thick stroke.
+     */
+    public final static BasicStroke thickStroke = new BasicStroke(4.0f);
+
+    /**
+     * Constructor. Initialize this printable with the component to be printed.
+     *
+     * @param isDoubleBuffered  a boolean, true for double-buffering
+     * @param transition  the component to be printed
+     */
+    public AbstractPrintable(boolean isDoubleBuffered, T transition) {
+        init(transition);
+    }
+
+    /**
+     * Initialize the printable.
+     *
+     * @param component the component
+     */
+    protected abstract void init(T component);
+
+    /**
+     * Draw the component onto the graphics context.
+     *
+     * @param g2 the graphics context
+     */
+    protected abstract void draw(Graphics2D g2);
+
+    /**
+     * Returns a generated image of the component.  May then be used wherever AWT images can be used, or converted to
+     * another image/picture format and used accordingly.
+     *
+     * @return an awt image of the printable component
+     */
+    public Image createImage() {
+        int width = getWidth() + getOffsetX();
+        int height = getHeight() + getOffsetY();
+        // Create a buffered image in which to draw
+        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+        // Create a graphics contents on the buffered image
+        Graphics2D g2d = bufferedImage.createGraphics();
+        // Draw graphics
+        g2d.setBackground(Color.white);
+        g2d.clearRect(0, 0, width, height);
+        paintComponent(g2d);
+        // Graphics context no longer needed so dispose it
+        g2d.dispose();
+        return bufferedImage;
+    }
+
+    @Override
+    public void paintComponent(Graphics g) {
+        Graphics2D g2 = (Graphics2D) g;
+        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+                RenderingHints.VALUE_ANTIALIAS_ON);
+
+        g2.setColor(Color.BLACK);
+        g2.setStroke(thinStroke);
+               g2.translate(getOffsetX(), getOffsetY());
+
+        draw(g2);
+    }
+}
diff --git a/core/src/net/sf/openrocket/gui/print/AbstractPrintableTransition.java b/core/src/net/sf/openrocket/gui/print/AbstractPrintableTransition.java
deleted file mode 100644 (file)
index 8e6042d..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-package net.sf.openrocket.gui.print;
-
-import net.sf.openrocket.rocketcomponent.Transition;
-
-import javax.swing.*;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-
-public abstract class AbstractPrintableTransition extends JPanel {
-    /**
-     * The stroke of the transition arc.
-     */
-    private final static BasicStroke thinStroke = new BasicStroke(1.0f);
-
-    /**
-     * The X margin.
-     */
-    protected int marginX = (int) PrintUnit.INCHES.toPoints(0.25f);
-
-    /**
-     * The Y margin.
-     */
-    protected int marginY = (int) PrintUnit.INCHES.toPoints(0.25f);
-
-    /**
-     * Constructor. Initialize this printable with the component to be printed.
-     *
-     * @param isDoubleBuffered  a boolean, true for double-buffering
-     * @param transition  the component to be printed
-     */
-    public AbstractPrintableTransition(boolean isDoubleBuffered, Transition transition) {
-        super(isDoubleBuffered);
-        setBackground(Color.white);
-        init(transition);
-    }
-
-    /**
-     * Compute the basic values of each arc of the transition/shroud.  This is adapted from
-     * <a href="http://www.rocketshoppe.com/info/Transitions.pdf">The Properties of
-     * Model Rocket Body Tube Transitions, by J.R. Brohm</a>
-     *
-     * @param component the transition component
-     */
-    protected abstract void init(Transition component);
-
-    /**
-     * Draw the component onto the graphics context.
-     *
-     * @param g2 the graphics context
-     */
-    protected abstract void draw(Graphics2D g2);
-
-    /**
-     * Returns a generated image of the transition.  May then be used wherever AWT images can be used, or converted to
-     * another image/picture format and used accordingly.
-     *
-     * @return an awt image of the fin set
-     */
-    public Image createImage() {
-        int width = getWidth() + marginX;
-        int height = getHeight() + marginY;
-        // Create a buffered image in which to draw
-        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        // Create a graphics contents on the buffered image
-        Graphics2D g2d = bufferedImage.createGraphics();
-        // Draw graphics
-        g2d.setBackground(Color.white);
-        g2d.clearRect(0, 0, width, height);
-        paintComponent(g2d);
-        // Graphics context no longer needed so dispose it
-        g2d.dispose();
-        return bufferedImage;
-    }
-
-    @Override
-    public void paintComponent(Graphics g) {
-        Graphics2D g2 = (Graphics2D) g;
-        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
-                RenderingHints.VALUE_ANTIALIAS_ON);
-
-        g2.setColor(Color.BLACK);
-        g2.setStroke(thinStroke);
-
-        draw(g2);
-    }
-}
index e6290c3e906e6aee23db04d3ac7ad828c916457e..54c0f3eb8fa102bff8b7ec1f4e08d34335da1026 100644 (file)
@@ -6,13 +6,13 @@ package net.sf.openrocket.gui.print;
 import java.awt.Graphics2D;
 import java.io.IOException;
 import java.text.DecimalFormat;
+import java.util.List;
 
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.gui.figureelements.FigureElement;
 import net.sf.openrocket.gui.figureelements.RocketInfo;
 import net.sf.openrocket.gui.scalefigure.RocketPanel;
-import net.sf.openrocket.gui.util.SwingPreferences;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.masscalc.BasicMassCalculator;
 import net.sf.openrocket.masscalc.MassCalculator;
@@ -75,27 +75,33 @@ import com.itextpdf.text.pdf.PdfWriter;
  * </pre>
  */
 public class DesignReport {
-       
+
        /**
         * The logger.
         */
        private static final LogHelper log = Application.getLogger();
-       
-       /**
+    public static final double SCALE_FUDGE_FACTOR = 0.4d;
+
+    /**
         * The OR Document.
         */
        private OpenRocketDocument rocketDocument;
-       
+
        /**
         * A panel used for rendering of the design diagram.
         */
        final RocketPanel panel;
-       
+
        /**
         * The iText document.
         */
        protected Document document;
-       
+
+    /**
+     * The figure rotation.
+     */
+    private double rotation = 0d;
+
        /** The displayed strings. */
        private static final String STAGES = "Stages: ";
        private static final String MASS_WITH_MOTORS = "Mass (with motors): ";
@@ -121,19 +127,21 @@ public class DesignReport {
        private static final String LANDING_VELOCITY = "Landing Velocity";
        private static final String ROCKET_DESIGN = "Rocket Design";
        private static final double GRAVITY_CONSTANT = 9.80665d;
-       
+
        /**
         * Constructor.
         *
         * @param theRocDoc the OR document
         * @param theIDoc   the iText document
+     * @param figureRotation the angle the figure is rotated on the screen; printed report will mimic
         */
-       public DesignReport(OpenRocketDocument theRocDoc, Document theIDoc) {
+       public DesignReport(OpenRocketDocument theRocDoc, Document theIDoc, Double figureRotation) {
                document = theIDoc;
                rocketDocument = theRocDoc;
                panel = new RocketPanel(rocketDocument);
+        rotation = figureRotation;
        }
-       
+
        /**
         * Main entry point.  Prints the rocket drawing and design data.
         *
@@ -146,44 +154,38 @@ public class DesignReport {
                com.itextpdf.text.Rectangle pageSize = document.getPageSize();
                int pageImageableWidth = (int) pageSize.getWidth() - (int) pageSize.getBorderWidth() * 2;
                int pageImageableHeight = (int) pageSize.getHeight() / 2 - (int) pageSize.getBorderWidthTop();
-               
+
                PrintUtilities.addText(document, PrintUtilities.BIG_BOLD, ROCKET_DESIGN);
-               
+
                Rocket rocket = rocketDocument.getRocket();
                final Configuration configuration = rocket.getDefaultConfiguration().clone();
                configuration.setAllStages();
                PdfContentByte canvas = writer.getDirectContent();
-               
+
                final PrintFigure figure = new PrintFigure(configuration);
-               
+        figure.setRotation(rotation);
+
                FigureElement cp = panel.getExtraCP();
                FigureElement cg = panel.getExtraCG();
                RocketInfo text = panel.getExtraText();
-               
+
                double scale = paintRocketDiagram(pageImageableWidth, pageImageableHeight, canvas, figure, cp, cg);
-               
+
                canvas.beginText();
-               try {
-                       canvas.setFontAndSize(BaseFont.createFont(PrintUtilities.NORMAL.getFamilyname(), BaseFont.CP1252,
-                                                                                                               BaseFont.EMBEDDED), PrintUtilities.NORMAL_FONT_SIZE);
-               } catch (DocumentException e) {
-                       log.error("Could not set font.", e);
-               } catch (IOException e) {
-                       log.error("Could not create font.", e);
-               }
+               canvas.setFontAndSize(ITextHelper.getBaseFont(), PrintUtilities.NORMAL_FONT_SIZE);
                int figHeightPts = (int) (PrintUnit.METERS.toPoints(figure.getFigureHeight()) * 0.4 * (scale / PrintUnit.METERS
                                .toPoints(1)));
                final int diagramHeight = pageImageableHeight * 2 - 70 - (figHeightPts);
                canvas.moveText(document.leftMargin() + pageSize.getBorderWidthLeft(), diagramHeight);
                canvas.moveTextWithLeading(0, -16);
-               
+
                float initialY = canvas.getYTLM();
-               
+
                canvas.showText(rocketDocument.getRocket().getName());
-               
+
                canvas.newlineShowText(STAGES);
                canvas.showText("" + rocket.getStageCount());
-               
+
 
                if (configuration.hasMotors()) {
                        if (configuration.getStageCount() > 1) {
@@ -195,28 +197,29 @@ public class DesignReport {
                        canvas.newlineShowText(MASS_EMPTY);
                }
                canvas.showText(text.getMass(UnitGroup.UNITS_MASS.getDefaultUnit()));
-               
+
                canvas.newlineShowText(STABILITY);
                canvas.showText(text.getStability());
-               
+
                canvas.newlineShowText(CG);
                canvas.showText(text.getCg());
-               
+
                canvas.newlineShowText(CP);
                canvas.showText(text.getCp());
                canvas.endText();
-               
+
                try {
                        //Move the internal pointer of the document below that of what was just written using the direct byte buffer.
                        Paragraph paragraph = new Paragraph();
                        float finalY = canvas.getYTLM();
                        int heightOfDiagramAndText = (int) (pageSize.getHeight() - (finalY - initialY + diagramHeight));
-                       
+
                        paragraph.setSpacingAfter(heightOfDiagramAndText);
                        document.add(paragraph);
-                       
+
                        String[] motorIds = rocket.getMotorConfigurationIDs();
-                       
+            List<Simulation> simulations = rocketDocument.getSimulations();
+
                        for (int j = 0; j < motorIds.length; j++) {
                                String motorId = motorIds[j];
                                if (motorId != null) {
@@ -230,7 +233,8 @@ public class DesignReport {
                                        if (j > 1) {
                                                leading = 25;
                                        }
-                                       addFlightData(rocket, motorId, parent, leading);
+                    FlightData flight = findSimulation(motorId, simulations);
+                                       addFlightData(flight, rocket, motorId, parent, leading);
                                        addMotorData(rocket, motorId, parent);
                                        document.add(parent);
                                }
@@ -239,8 +243,8 @@ public class DesignReport {
                        log.error("Could not modify document.", e);
                }
        }
-       
-       
+
+
        /**
         * Paint a diagram of the rocket into the PDF document.
         *
@@ -261,28 +265,33 @@ public class DesignReport {
                theFigure.addRelativeExtra(theCp);
                theFigure.addRelativeExtra(theCg);
                theFigure.updateFigure();
-               
+
                double scale =
                                (thePageImageableWidth * 2.2) / theFigure.getFigureWidth();
-               
                theFigure.setScale(scale);
                /*
                 * page dimensions are in points-per-inch, which, in Java2D, are the same as pixels-per-inch; thus we don't need any conversion
                 */
                theFigure.setSize(thePageImageableWidth, thePageImageableHeight);
                theFigure.updateFigure();
-               
 
                final DefaultFontMapper mapper = new DefaultFontMapper();
                Graphics2D g2d = theCanvas.createGraphics(thePageImageableWidth, thePageImageableHeight * 2, mapper);
-               g2d.translate(20, 120);
-               
-               g2d.scale(0.4d, 0.4d);
+        final double halfFigureHeight = SCALE_FUDGE_FACTOR * theFigure.getFigureHeightPx()/2;
+        int y = PrintUnit.POINTS_PER_INCH;
+        //If the y dimension is negative, then it will potentially be drawn off the top of the page.  Move the origin
+        //to allow for this.
+        if (theFigure.getDimensions().getY() < 0.0d) {
+            y += (int)halfFigureHeight;
+        }
+        g2d.translate(20, y);
+
+               g2d.scale(SCALE_FUDGE_FACTOR, SCALE_FUDGE_FACTOR);
                theFigure.paint(g2d);
                g2d.dispose();
                return scale;
        }
-       
+
        /**
         * Add the motor data for a motor configuration to the table.
         *
@@ -291,41 +300,41 @@ public class DesignReport {
         * @param parent        the parent to which the motor data will be added
         */
        private void addMotorData(Rocket rocket, String motorId, final PdfPTable parent) {
-               
+
                PdfPTable motorTable = new PdfPTable(8);
                motorTable.setWidthPercentage(68);
                motorTable.setHorizontalAlignment(Element.ALIGN_LEFT);
-               
-               final PdfPCell motorCell = ITextHelper.createCell(MOTOR, PdfPCell.BOTTOM);
+
+               final PdfPCell motorCell = ITextHelper.createCell(MOTOR, PdfPCell.BOTTOM, PrintUtilities.SMALL);
                final int mPad = 10;
                motorCell.setPaddingLeft(mPad);
                motorTable.addCell(motorCell);
-               motorTable.addCell(ITextHelper.createCell(AVG_THRUST, PdfPCell.BOTTOM));
-               motorTable.addCell(ITextHelper.createCell(BURN_TIME, PdfPCell.BOTTOM));
-               motorTable.addCell(ITextHelper.createCell(MAX_THRUST, PdfPCell.BOTTOM));
-               motorTable.addCell(ITextHelper.createCell(TOTAL_IMPULSE, PdfPCell.BOTTOM));
-               motorTable.addCell(ITextHelper.createCell(THRUST_TO_WT, PdfPCell.BOTTOM));
-               motorTable.addCell(ITextHelper.createCell(PROPELLANT_WT, PdfPCell.BOTTOM));
-               motorTable.addCell(ITextHelper.createCell(SIZE, PdfPCell.BOTTOM));
-               
+               motorTable.addCell(ITextHelper.createCell(AVG_THRUST, PdfPCell.BOTTOM, PrintUtilities.SMALL));
+               motorTable.addCell(ITextHelper.createCell(BURN_TIME, PdfPCell.BOTTOM, PrintUtilities.SMALL));
+               motorTable.addCell(ITextHelper.createCell(MAX_THRUST, PdfPCell.BOTTOM, PrintUtilities.SMALL));
+               motorTable.addCell(ITextHelper.createCell(TOTAL_IMPULSE, PdfPCell.BOTTOM, PrintUtilities.SMALL));
+               motorTable.addCell(ITextHelper.createCell(THRUST_TO_WT, PdfPCell.BOTTOM, PrintUtilities.SMALL));
+               motorTable.addCell(ITextHelper.createCell(PROPELLANT_WT, PdfPCell.BOTTOM, PrintUtilities.SMALL));
+               motorTable.addCell(ITextHelper.createCell(SIZE, PdfPCell.BOTTOM, PrintUtilities.SMALL));
+
                DecimalFormat ttwFormat = new DecimalFormat("0.00");
-               
+
                MassCalculator massCalc = new BasicMassCalculator();
-               
+
                Configuration config = new Configuration(rocket);
                config.setMotorConfigurationID(motorId);
-               
+
                int totalMotorCount = 0;
                double totalPropMass = 0;
                double totalImpulse = 0;
                double totalTTW = 0;
-               
+
                int stage = 0;
                double stageMass = 0;
-               
+
                boolean topBorder = false;
                for (RocketComponent c : rocket) {
-                       
+
                        if (c instanceof Stage) {
                                config.setToStage(stage);
                                stage++;
@@ -334,26 +343,26 @@ public class DesignReport {
                                totalTTW = 0;
                                topBorder = true;
                        }
-                       
+
                        if (c instanceof MotorMount && ((MotorMount) c).isMotorMount()) {
                                MotorMount mount = (MotorMount) c;
-                               
+
                                if (mount.isMotorMount() && mount.getMotor(motorId) != null) {
                                        Motor motor = mount.getMotor(motorId);
                                        int motorCount = c.toAbsolute(Coordinate.NUL).length;
-                                       
+
 
                                        int border = Rectangle.NO_BORDER;
                                        if (topBorder) {
                                                border = Rectangle.TOP;
                                                topBorder = false;
                                        }
-                                       
+
                                        String name = motor.getDesignation();
                                        if (motorCount > 1) {
                                                name += " (" + Chars.TIMES + motorCount + ")";
                                        }
-                                       
+
                                        final PdfPCell motorVCell = ITextHelper.createCell(name, border);
                                        motorVCell.setPaddingLeft(mPad);
                                        motorTable.addCell(motorVCell);
@@ -365,21 +374,21 @@ public class DesignReport {
                                                        UnitGroup.UNITS_FORCE.getDefaultUnit().toStringUnit(motor.getMaxThrustEstimate()), border));
                                        motorTable.addCell(ITextHelper.createCell(
                                                        UnitGroup.UNITS_IMPULSE.getDefaultUnit().toStringUnit(motor.getTotalImpulseEstimate()), border));
-                                       
+
                                        double ttw = motor.getAverageThrustEstimate() / (stageMass * GRAVITY_CONSTANT);
                                        motorTable.addCell(ITextHelper.createCell(
                                                        ttwFormat.format(ttw) + ":1", border));
-                                       
+
                                        double propMass = (motor.getLaunchCG().weight - motor.getEmptyCG().weight);
                                        motorTable.addCell(ITextHelper.createCell(
                                                        UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(propMass), border));
-                                       
+
                                        final Unit motorUnit = UnitGroup.UNITS_MOTOR_DIMENSIONS.getDefaultUnit();
                                        motorTable.addCell(ITextHelper.createCell(motorUnit.toString(motor.getDiameter()) +
                                                                                                                                "/" +
                                                                                                                                motorUnit.toString(motor.getLength()) + " " +
                                                                                                                                motorUnit.toString(), border));
-                                       
+
                                        // Sum up total count
                                        totalMotorCount += motorCount;
                                        totalPropMass += propMass * motorCount;
@@ -388,7 +397,7 @@ public class DesignReport {
                                }
                        }
                }
-               
+
                if (totalMotorCount > 1) {
                        int border = Rectangle.TOP;
                        final PdfPCell motorVCell = ITextHelper.createCell("Total:", border);
@@ -404,78 +413,67 @@ public class DesignReport {
                        motorTable.addCell(ITextHelper.createCell(
                                                UnitGroup.UNITS_MASS.getDefaultUnit().toStringUnit(totalPropMass), border));
                        motorTable.addCell(ITextHelper.createCell("", border));
-                       
+
                }
-               
+
                PdfPCell c = new PdfPCell(motorTable);
                c.setBorder(PdfPCell.LEFT);
                c.setBorderWidthTop(0f);
                parent.addCell(c);
        }
-       
-       
+
+
        /**
-        * Add the motor data for a motor configuration to the table.
+        * Add the flight data for a simulation configuration to the table.
         *
+     * @param flight    the flight data for a single simulation
         * @param theRocket the rocket
         * @param motorId   a motor configuration id
-        * @param parent    the parent to which the motor data will be added
+        * @param parent    the parent to which the simulation flight data will be added
         * @param leading   the number of points for the leading
         */
-       private void addFlightData(final Rocket theRocket, final String motorId, final PdfPTable parent, int leading) {
-               
-               // Perform flight simulation
-               Rocket duplicate = theRocket.copyWithOriginalID();
-               FlightData flight = null;
-               try {
-                       Simulation simulation = ((SwingPreferences)Application.getPreferences()).getBackgroundSimulation(duplicate);
-                       simulation.getOptions().setMotorConfigurationID(motorId);
-                       simulation.simulate();
-                       flight = simulation.getSimulatedData();
-               } catch (SimulationException e1) {
-                       // Ignore
-               }
-               
-               // Output the flight data
+       private void addFlightData(final FlightData flight, final Rocket theRocket, final String motorId, final PdfPTable parent, int leading) {
+
+        // Output the flight data
                if (flight != null) {
                        try {
                                final Unit distanceUnit = UnitGroup.UNITS_DISTANCE.getDefaultUnit();
                                final Unit velocityUnit = UnitGroup.UNITS_VELOCITY.getDefaultUnit();
                                final Unit flightTimeUnit = UnitGroup.UNITS_FLIGHT_TIME.getDefaultUnit();
-                               
+
                                PdfPTable labelTable = new PdfPTable(2);
                                labelTable.setWidths(new int[] { 3, 2 });
                                final Paragraph chunk = ITextHelper.createParagraph(stripBrackets(
                                                        theRocket.getMotorConfigurationNameOrDescription(motorId)), PrintUtilities.BOLD);
                                chunk.setLeading(leading);
                                chunk.setSpacingAfter(3f);
-                               
+
                                document.add(chunk);
-                               
+
                                final PdfPCell cell = ITextHelper.createCell(ALTITUDE, 2, 2);
                                cell.setUseBorderPadding(false);
                                cell.setBorderWidthTop(0f);
                                labelTable.addCell(cell);
                                labelTable.addCell(ITextHelper.createCell(distanceUnit.toStringUnit(flight.getMaxAltitude()), 2, 2));
-                               
+
                                labelTable.addCell(ITextHelper.createCell(FLIGHT_TIME, 2, 2));
                                labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getFlightTime()), 2, 2));
-                               
+
                                labelTable.addCell(ITextHelper.createCell(TIME_TO_APOGEE, 2, 2));
                                labelTable.addCell(ITextHelper.createCell(flightTimeUnit.toStringUnit(flight.getTimeToApogee()), 2, 2));
-                               
+
                                labelTable.addCell(ITextHelper.createCell(VELOCITY_OFF_PAD, 2, 2));
                                labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getLaunchRodVelocity()), 2, 2));
-                               
+
                                labelTable.addCell(ITextHelper.createCell(MAX_VELOCITY, 2, 2));
                                labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getMaxVelocity()), 2, 2));
-                               
+
                                labelTable.addCell(ITextHelper.createCell(DEPLOYMENT_VELOCITY, 2,2));
                                labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getDeploymentVelocity()),2,2));
-                               
+
                                labelTable.addCell(ITextHelper.createCell(LANDING_VELOCITY, 2, 2));
                                labelTable.addCell(ITextHelper.createCell(velocityUnit.toStringUnit(flight.getGroundHitVelocity()), 2, 2));
-                               
+
                                //Add the table to the parent; have to wrap it in a cell
                                PdfPCell c = new PdfPCell(labelTable);
                                c.setBorder(PdfPCell.RIGHT);
@@ -487,8 +485,36 @@ public class DesignReport {
                        }
                }
        }
-       
-       /**
+
+    /**
+     * Locate the simulation based on the motor id.  Copy the simulation and execute it, then return the resulting
+     * flight data.
+     *
+     * @param motorId     the motor id corresponding to the simulation to find
+     * @param simulations the list of simulations currently associated with the rocket
+     *
+     * @return the flight data from the simulation for the specified motor id, or null if not found
+     */
+    private FlightData findSimulation(final String motorId, List<Simulation> simulations) {
+        // Perform flight simulation
+        FlightData flight = null;
+        try {
+            for (int i = 0; i < simulations.size(); i++) {
+                Simulation simulation =  simulations.get(i);
+                if (simulation.getOptions().getMotorConfigurationID().equals(motorId)) {
+                    simulation = simulation.copy();
+                    simulation.simulate();
+                    flight = simulation.getSimulatedData();
+                    break;
+                }
+            }
+        } catch (SimulationException e1) {
+            // Ignore
+        }
+        return flight;
+    }
+
+    /**
         * Strip [] brackets from a string.
         *
         * @param target the original string
@@ -498,7 +524,7 @@ public class DesignReport {
        private String stripBrackets(String target) {
                return stripLeftBracket(stripRightBracket(target));
        }
-       
+
        /**
         * Strip [ from a string.
         *
@@ -509,7 +535,7 @@ public class DesignReport {
        private String stripLeftBracket(String target) {
                return target.replace("[", "");
        }
-       
+
        /**
         * Strip ] from a string.
         *
@@ -520,5 +546,5 @@ public class DesignReport {
        private String stripRightBracket(String target) {
                return target.replace("]", "");
        }
-       
+
 }
index f0be174dc002d3c5e9dafe6aa1de1d72f34c870c..64b617ab14e3ad0bceff16aaaceed79d9892a230 100644 (file)
@@ -9,8 +9,13 @@ import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
 
-import javax.swing.*;
-import java.awt.*;
+import javax.swing.JPanel;
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.RenderingHints;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Path2D;
 import java.awt.image.BufferedImage;
@@ -24,10 +29,10 @@ import java.util.Map;
 
 /**
  * This is the core Swing representation of a fin marking guide.  It can handle multiple fin sets on the same or
- * different body tubes. One marking guide will be created for any body tube that has a finset.  If a tube has
- * multiple finsets, then they are combined onto one marking guide. It also includes launch lug marking line(s) if lugs
- * are present. If (and only if) a launch lug exists, then the word 'Front' is affixed to the leading edge of the
- * guide to give orientation.
+ * different body tubes. One marking guide will be created for any body tube that has a finset.  If a tube has multiple
+ * finsets, then they are combined onto one marking guide. It also includes launch lug marking line(s) if lugs are
+ * present. If (and only if) a launch lug exists, then the word 'Front' is affixed to the leading edge of the guide to
+ * give orientation.
  * <p/>
  */
 public class FinMarkingGuide extends JPanel {
@@ -42,6 +47,13 @@ public class FinMarkingGuide extends JPanel {
      */
     private static final int ARROW_SIZE = 10;
 
+    /**
+     * Typical thickness of a piece of printer paper (~20-24 lb paper). Wrapping paper around a tube results in the
+     * radius being increased by the thickness of the paper. The smaller the tube, the more pronounced this becomes as a
+     * percentage of circumference.  Using 1/10mm as an approximation here.
+     */
+    private static final double PAPER_THICKNESS_IN_METERS = PrintUnit.MILLIMETERS.toMeters(0.1d);
+
     /**
      * The default guide width in inches.
      */
@@ -89,6 +101,7 @@ public class FinMarkingGuide extends JPanel {
      * Initialize the marking guide class by iterating over a rocket and finding all finsets.
      *
      * @param component the root rocket component - this is iterated to find all finset and launch lugs
+     *
      * @return a map of body tubes to lists of finsets and launch lugs.
      */
     private Map<BodyTube, java.util.List<ExternalComponent>> init(Rocket component) {
@@ -103,7 +116,8 @@ public class FinMarkingGuide extends JPanel {
             RocketComponent next = iter.next();
             if (next instanceof BodyTube) {
                 current = (BodyTube) next;
-            } else if (next instanceof FinSet || next instanceof LaunchLug) {
+            }
+            else if (next instanceof FinSet || next instanceof LaunchLug) {
                 java.util.List<ExternalComponent> list = results.get(current);
                 if (list == null && current != null) {
                     list = new ArrayList<ExternalComponent>();
@@ -198,9 +212,11 @@ public class FinMarkingGuide extends JPanel {
      *
      *                              |<-------- width ----------->|
      *
-     * yLLOffset is computed from the difference between the base rotation of the fin and the radial direction of the lug.
+     * yLLOffset is computed from the difference between the base rotation of the fin and the radial direction of the
+     * lug.
      *
-     * Note: There is a current limitation that a tube with multiple launch lugs may not render the lug lines correctly.
+     * Note: There is a current limitation that a tube with multiple launch lugs may not render the lug lines
+     * correctly.
      * </pre>
      *
      * @param g the Graphics context
@@ -224,13 +240,15 @@ public class FinMarkingGuide extends JPanel {
         int width = (int) PrintUnit.INCHES.toPoints(DEFAULT_GUIDE_WIDTH);
 
         int column = 0;
+
         for (BodyTube next : markingGuideItems.keySet()) {
-            double circumferenceInPoints = PrintUnit.METERS.toPoints(next.getOuterRadius() * TWO_PI);
+            double circumferenceInPoints = PrintUnit.METERS.toPoints((next.getOuterRadius() + PAPER_THICKNESS_IN_METERS) *
+                    TWO_PI);
             List<ExternalComponent> componentList = markingGuideItems.get(next);
             //Don't draw the lug if there are no fins.
             if (hasFins(componentList)) {
 
-                drawMarkingGuide(g2, x, y, (int) (circumferenceInPoints), width);
+                drawMarkingGuide(g2, x, y, (int) Math.ceil(circumferenceInPoints), width);
 
                 //Sort so that fins always precede lugs
                 sort(componentList);
@@ -258,7 +276,8 @@ public class FinMarkingGuide extends JPanel {
                                 baseRotation += TWO_PI / finCount;
                             }
                             offset = computeYOffset(y, circumferenceInPoints, baseSpacing, baseYOrigin, finRadial, baseRotation);
-                        } else {
+                        }
+                        else {
                             //baseYOrigin is the distance from the top of the marking guide to the first fin of the first fin set.
                             //This measurement is used to base all subsequent finsets and lugs off of.
                             baseYOrigin = baseSpacing / 2;
@@ -274,15 +293,17 @@ public class FinMarkingGuide extends JPanel {
                             if (fin > 0) {
                                 offset += baseSpacing;
                                 yLastFin = offset;
-                            } else {
+                            }
+                            else {
                                 yFirstFin = offset;
                             }
                             drawDoubleArrowLine(g2, x, offset, x + width, offset);
-                         //   if (hasMultipleComponents) {
-                                g2.drawString(externalComponent.getName(), x + (width / 3), offset - 2);
-                         //   }
+                            //   if (hasMultipleComponents) {
+                            g2.drawString(externalComponent.getName(), x + (width / 3), offset - 2);
+                            //   }
                         }
-                    } else if (externalComponent instanceof LaunchLug) {
+                    }
+                    else if (externalComponent instanceof LaunchLug) {
                         LaunchLug lug = (LaunchLug) externalComponent;
                         double yLLOffset = (lug.getRadialDirection() - finRadial) / TWO_PI;
                         //The placement of the lug line must respect the boundary of the outer marking guide.  In order
@@ -290,7 +311,8 @@ public class FinMarkingGuide extends JPanel {
                         //between their rotational directions.
                         if (yLLOffset < 0) {
                             yLLOffset = yLLOffset * circumferenceInPoints + yLastFin;
-                        } else {
+                        }
+                        else {
                             yLLOffset = yLLOffset * circumferenceInPoints + yFirstFin;
                         }
                         drawDoubleArrowLine(g2, x, (int) yLLOffset, x + width, (int) yLLOffset);
@@ -308,7 +330,8 @@ public class FinMarkingGuide extends JPanel {
                 if (column % 2 == 0) {
                     x = MARGIN;
                     y += circumferenceInPoints + MARGIN;
-                } else {
+                }
+                else {
                     x += MARGIN + width;
                 }
             }
@@ -318,12 +341,13 @@ public class FinMarkingGuide extends JPanel {
     /**
      * Compute the y offset for the next fin line.
      *
-     * @param y                       the top margin
-     * @param circumferenceInPoints   the circumference (height) of the guide
-     * @param baseSpacing             the circumference / fin count
-     * @param baseYOrigin             the offset from the top of the guide to the first fin of the first fin set drawn
-     * @param prevBaseRotation        the rotation of the previous finset
-     * @param baseRotation            the rotation of the current finset
+     * @param y                     the top margin
+     * @param circumferenceInPoints the circumference (height) of the guide
+     * @param baseSpacing           the circumference / fin count
+     * @param baseYOrigin           the offset from the top of the guide to the first fin of the first fin set drawn
+     * @param prevBaseRotation      the rotation of the previous finset
+     * @param baseRotation          the rotation of the current finset
+     *
      * @return number of points from the top of the marking guide to the line to be drawn
      */
     private int computeYOffset(int y, double circumferenceInPoints, double baseSpacing, double baseYOrigin, double prevBaseRotation, double baseRotation) {
@@ -332,9 +356,11 @@ public class FinMarkingGuide extends JPanel {
         //If the fin line would be off the top of the marking guide, then readjust.
         if (baseYOrigin + finRadialDifference * circumferenceInPoints < 0) {
             offset = (int) (baseYOrigin + baseSpacing + finRadialDifference * circumferenceInPoints) + y;
-        } else if (baseYOrigin - finRadialDifference * circumferenceInPoints > 0) {
+        }
+        else if (baseYOrigin - finRadialDifference * circumferenceInPoints > 0) {
             offset = (int) (finRadialDifference * circumferenceInPoints + baseYOrigin) + y;
-        } else {
+        }
+        else {
             offset = (int) (finRadialDifference * circumferenceInPoints - baseYOrigin) + y;
         }
         return offset;
@@ -344,6 +370,7 @@ public class FinMarkingGuide extends JPanel {
      * Determines if the list contains a FinSet.
      *
      * @param list a list of ExternalComponent
+     *
      * @return true if the list contains at least one FinSet
      */
     private boolean hasFins(List<ExternalComponent> list) {
@@ -381,7 +408,8 @@ public class FinMarkingGuide extends JPanel {
      * @param g2     the graphics context
      * @param x      the starting x coordinate
      * @param y      the starting y coordinate
-     * @param length the length, or height, in print units of the marking guide; should be equivalent to the outer tube circumference
+     * @param length the length, or height, in print units of the marking guide; should be equivalent to the outer tube
+     *               circumference
      * @param width  the width of the marking guide in print units; somewhat arbitrary
      */
     private void drawMarkingGuide(Graphics2D g2, int x, int y, int length, int width) {
@@ -407,14 +435,15 @@ public class FinMarkingGuide extends JPanel {
     }
 
     /**
-     * Draw a vertical string indicating the front of the rocket.  This is necessary when a launch lug exists to
-     * give proper orientation of the guide (assuming that the lug is asymmetrically positioned with respect to a fin).
+     * Draw a vertical string indicating the front of the rocket.  This is necessary when a launch lug exists to give
+     * proper orientation of the guide (assuming that the lug is asymmetrically positioned with respect to a fin).
      *
      * @param g2      the graphics context
      * @param x       the starting x coordinate
      * @param y       the starting y coordinate
      * @param spacing the space between fin lines
-     * @param length  the length, or height, in print units of the marking guide; should be equivalent to the outer tube circumference
+     * @param length  the length, or height, in print units of the marking guide; should be equivalent to the outer tube
+     *                circumference
      * @param width   the width of the marking guide in print units; somewhat arbitrary
      */
     private void drawFrontIndication(Graphics2D g2, int x, int y, int spacing, int length, int width) {
@@ -451,6 +480,4 @@ public class FinMarkingGuide extends JPanel {
         g2.fillPolygon(new int[]{x1, x1 + ARROW_SIZE, x1 + ARROW_SIZE, x1},
                 new int[]{y1, y1 - ARROW_SIZE / 2, y1 + ARROW_SIZE / 2, y1}, 4);
     }
-
-
-}
+}
\ No newline at end of file
index 0b2b6f9521ed320b3688e776402f6712de4cda0d..4565054392f5a63b06bb426be850611ae774e3d8 100644 (file)
@@ -3,6 +3,9 @@
  */
 package net.sf.openrocket.gui.print;
 
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
 import com.itextpdf.text.Chunk;
 import com.itextpdf.text.Document;
 import com.itextpdf.text.DocumentException;
@@ -10,19 +13,24 @@ import com.itextpdf.text.Font;
 import com.itextpdf.text.Paragraph;
 import com.itextpdf.text.Phrase;
 import com.itextpdf.text.Rectangle;
+import com.itextpdf.text.pdf.BaseFont;
 import com.itextpdf.text.pdf.PdfContentByte;
 import com.itextpdf.text.pdf.PdfPCell;
 import com.itextpdf.text.pdf.PdfPTable;
 import com.itextpdf.text.pdf.PdfWriter;
 
-import java.awt.*;
-import java.awt.image.BufferedImage;
-
 /**
  * A bunch of helper methods for creating iText components.
  */
 public final class ITextHelper {
 
+       public static BaseFont getBaseFont(){
+               try {
+               return BaseFont.createFont("/dejavu-font/DejaVuSerif.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
+               } catch (Exception ex ) {
+                       throw new RuntimeException(ex);
+               }
+       }
     /**
      * Create a cell for an iText table.
      *
index 456495f384e3cc910d9f6798d795fb11405f2875..5bfd924c81b159689794b134180c0a282015854d 100644 (file)
@@ -22,29 +22,31 @@ public enum OpenRocketPrintable {
        NOSE_CONE_TEMPLATE("OpenRocketPrintable.Noseconetemplates", false, 3),
        // Transition Templates
        TRANSITION_TEMPLATE("OpenRocketPrintable.Transitiontemplates", false, 4),
+       // Centering Ring Templates
+       CENTERING_RING_TEMPLATE("OpenRocketPrintable.Centeringringtemplates", false, 5),
        // Finset shape
-       FIN_TEMPLATE("OpenRocketPrintable.Fintemplates", true, 5),
+       FIN_TEMPLATE("OpenRocketPrintable.Fintemplates", true, 6),
        // Fin marking guide.
-       FIN_MARKING_GUIDE("OpenRocketPrintable.Finmarkingguide", false, 6);
-       
+       FIN_MARKING_GUIDE("OpenRocketPrintable.Finmarkingguide", false, 7);
+
 
        private static final Translator trans = Application.getTranslator();
-       
+
        /**
         * The description - will be displayed in the JTree.
         */
        private String description;
-       
+
        /**
         * Flag that indicates if the enum value is different depending upon stage.
         */
        private boolean stageSpecific;
-       
+
        /**
         * The order of the item as it appears in the printed document.
         */
        private int order;
-       
+
        /**
         * Constructor.
         *
@@ -57,7 +59,7 @@ public enum OpenRocketPrintable {
                stageSpecific = staged;
                order = idx;
        }
-       
+
        /**
         * Get the description of this printable.
         *
@@ -66,7 +68,7 @@ public enum OpenRocketPrintable {
        public String getDescription() {
                return trans.get(description);
        }
-       
+
        /**
         * Answers if this enum value has different meaning depending upon the stage.
         *
@@ -75,7 +77,7 @@ public enum OpenRocketPrintable {
        public boolean isStageSpecific() {
                return stageSpecific;
        }
-       
+
        /**
         * Answer the print order.  This is relative to other enum values.  No two enum values will have the same print
         * order value.
@@ -85,7 +87,7 @@ public enum OpenRocketPrintable {
        public int getPrintOrder() {
                return order;
        }
-       
+
        /**
         * Look up an enum value based on the description.
         *
@@ -102,7 +104,7 @@ public enum OpenRocketPrintable {
                }
                return null;
        }
-       
+
        /**
         * Get a list of ordered enum values that do not have stage affinity.
         *
index d3d07410570570791288f481d48ff3e4b3aa21f0..1908fa281d88251cebf39c837fe872eedc093188 100644 (file)
@@ -36,7 +36,7 @@ public enum PaperSize {
        }
        
        
-
+       
        //////////////////////////
        
        private static final LogHelper log = Application.getLogger();
@@ -181,7 +181,7 @@ public enum PaperSize {
                        return null;
                }
                
-               country = country.toUpperCase();
+               country = country.toUpperCase(Locale.ENGLISH);
                for (String c : letterCountries) {
                        if (c.equals(country)) {
                                return LETTER;
index 69e4df057b2e1d392be51a167c2d4524009bebe7..2e62df2a2cf403da5c85b72be9c7f3106ce3a0cf 100644 (file)
@@ -12,8 +12,11 @@ import com.itextpdf.text.pdf.PdfBoolean;
 import com.itextpdf.text.pdf.PdfName;
 import com.itextpdf.text.pdf.PdfWriter;
 import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.gui.print.components.Rule;
+import net.sf.openrocket.gui.print.visitor.CenteringRingStrategy;
 import net.sf.openrocket.gui.print.visitor.FinMarkingGuideStrategy;
 import net.sf.openrocket.gui.print.visitor.FinSetPrintStrategy;
+import net.sf.openrocket.gui.print.visitor.PageFitPrintStrategy;
 import net.sf.openrocket.gui.print.visitor.PartsDetailVisitorStrategy;
 import net.sf.openrocket.gui.print.visitor.TransitionStrategy;
 
@@ -27,103 +30,136 @@ import java.util.Set;
  * file.
  */
 public class PrintController {
-       
-       /**
-        * Print the selected components to a PDF document.
-        *
-        * @param doc         the OR document
-        * @param toBePrinted the user chosen items to print
-        * @param outputFile  the file being written to
-        * @param settings    the print settings
-        */
-       public void print(OpenRocketDocument doc, Iterator<PrintableContext> toBePrinted, OutputStream outputFile,
-                                               PrintSettings settings) {
-               
-               Document idoc = new Document(getSize(settings));
-               PdfWriter writer = null;
-               try {
-                       writer = PdfWriter.getInstance(idoc, outputFile);
-                       writer.setStrictImageSequence(true);
-                       
-                       writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE);
-                       writer.addViewerPreference(PdfName.PICKTRAYBYPDFSIZE, PdfBoolean.PDFTRUE);
-                       try {
-                               idoc.open();
-                               Thread.sleep(1000);
-                       } catch (InterruptedException e) {
-                       }
-                       while (toBePrinted.hasNext()) {
-                               PrintableContext printableContext = toBePrinted.next();
-                               
-                               Set<Integer> stages = printableContext.getStageNumber();
-                               
-                               switch (printableContext.getPrintable()) {
-                               case DESIGN_REPORT:
-                                       DesignReport dp = new DesignReport(doc, idoc);
-                                       dp.writeToDocument(writer);
-                                       idoc.newPage();
-                                       break;
-                               case FIN_TEMPLATE:
-                                       final FinSetPrintStrategy finWriter = new FinSetPrintStrategy(idoc,
-                                                                                                                                                                                       writer,
-                                                                                                                                                                                       stages);
-                                       finWriter.writeToDocument(doc.getRocket());
-                                       break;
-                               case PARTS_DETAIL:
-                                       final PartsDetailVisitorStrategy detailVisitor = new PartsDetailVisitorStrategy(idoc,
-                                                                                                                                                                                                               writer,
-                                                                                                                                                                                                               stages);
-                                       detailVisitor.writeToDocument(doc.getRocket());
-                                       detailVisitor.close();
-                                       idoc.newPage();
-                                       break;
-                case TRANSITION_TEMPLATE:
-                    final TransitionStrategy tranWriter = new TransitionStrategy(idoc, writer, stages);
-                    tranWriter.writeToDocument(doc.getRocket(), false);
-                    idoc.newPage();
-                    break;
-
-                case NOSE_CONE_TEMPLATE:
-                    final TransitionStrategy coneWriter = new TransitionStrategy(idoc, writer, stages);
-                    coneWriter.writeToDocument(doc.getRocket(), true);
-                    idoc.newPage();
-                    break;
-
-                case FIN_MARKING_GUIDE:
-                    final FinMarkingGuideStrategy fmg = new FinMarkingGuideStrategy(idoc, writer);
-                    fmg.writeToDocument(doc.getRocket());
-                    idoc.newPage();
-                    break;
+
+    /**
+     * Print the selected components to a PDF document.
+     *
+     * @param doc         the OR document
+     * @param toBePrinted the user chosen items to print
+     * @param outputFile  the file being written to
+     * @param settings    the print settings
+     * @param rotation    the angle the rocket figure is rotated
+     */
+    public void print(OpenRocketDocument doc, Iterator<PrintableContext> toBePrinted, OutputStream outputFile,
+                      PrintSettings settings, double rotation) {
+
+        Document idoc = new Document(getSize(settings));
+        PdfWriter writer = null;
+        try {
+            writer = PdfWriter.getInstance(idoc, outputFile);
+            writer.setStrictImageSequence(true);
+
+            writer.addViewerPreference(PdfName.PRINTSCALING, PdfName.NONE);
+            writer.addViewerPreference(PdfName.PICKTRAYBYPDFSIZE, PdfBoolean.PDFTRUE);
+            try {
+                idoc.open();
+                Thread.sleep(1000);
+            }
+            catch (InterruptedException e) {
+            }
+
+            // Used to combine multiple components onto fewer sheets of paper
+            PageFitPrintStrategy pageFitPrint = new PageFitPrintStrategy(idoc, writer);
+
+            boolean addRule = false;
+
+            while (toBePrinted.hasNext()) {
+                PrintableContext printableContext = toBePrinted.next();
+
+                Set<Integer> stages = printableContext.getStageNumber();
+
+                switch (printableContext.getPrintable()) {
+                    case DESIGN_REPORT:
+                        DesignReport dp = new DesignReport(doc, idoc, rotation);
+                        dp.writeToDocument(writer);
+                        idoc.newPage();
+                        break;
+
+                    case FIN_TEMPLATE:
+                        final FinSetPrintStrategy finWriter = new FinSetPrintStrategy(idoc, writer, stages, pageFitPrint);
+                        finWriter.writeToDocument(doc.getRocket());
+                        addRule = true;
+                        break;
+
+                    case PARTS_DETAIL:
+                        final PartsDetailVisitorStrategy detailVisitor = new PartsDetailVisitorStrategy(idoc, writer, stages);
+                        detailVisitor.writeToDocument(doc.getRocket());
+                        detailVisitor.close();
+                        idoc.newPage();
+                        break;
+
+                    case TRANSITION_TEMPLATE:
+                        final TransitionStrategy tranWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint);
+                        if (tranWriter.writeToDocument(doc.getRocket(), false)) {
+                            addRule = true;
+                        }
+                        break;
+
+                    case NOSE_CONE_TEMPLATE:
+                        final TransitionStrategy coneWriter = new TransitionStrategy(idoc, writer, stages, pageFitPrint);
+                        if (coneWriter.writeToDocument(doc.getRocket(), true)) {
+                            addRule = true;
+                        }
+                        break;
+
+                    case CENTERING_RING_TEMPLATE:
+                        final CenteringRingStrategy crWriter = new CenteringRingStrategy(idoc, writer, stages,
+                                pageFitPrint);
+                        crWriter.writeToDocument(doc.getRocket());
+                        addRule = true;
+                        break;
+
+                    case FIN_MARKING_GUIDE:
+                        final FinMarkingGuideStrategy fmg = new FinMarkingGuideStrategy(idoc, writer);
+                        fmg.writeToDocument(doc.getRocket());
+                        idoc.newPage();
+                        addRule = true;
+                        break;
+                }
+            }
+
+            if (addRule) {
+                //Add a ruler to the output.
+                pageFitPrint.addComponent(new Rule(Rule.Orientation.BOTTOM));
+            }
+
+            // Write out parts that we are going to combine onto single sheets of paper
+            pageFitPrint.writeToDocument(doc.getRocket());
+            idoc.newPage();
+
+            //Stupid iText throws a really nasty exception if there is no data when close is called.
+            if (writer.getCurrentDocumentSize() <= 140) {
+                writer.setPageEmpty(false);
+            }
+            writer.close();
+            idoc.close();
+        }
+        catch (DocumentException e) {
+        }
+        catch (ExceptionConverter ec) {
+        }
+        finally {
+            if (outputFile != null) {
+                try {
+                    outputFile.close();
+                }
+                catch (IOException e) {
                 }
-                       }
-                       //Stupid iText throws a really nasty exception if there is no data when close is called.
-                       if (writer.getCurrentDocumentSize() <= 140) {
-                               writer.setPageEmpty(false);
-                       }
-                       writer.close();
-                       idoc.close();
-               } catch (DocumentException e) {
-               } catch (ExceptionConverter ec) {
-               } finally {
-                       if (outputFile != null) {
-                               try {
-                                       outputFile.close();
-                               } catch (IOException e) {
-                               }
-                       }
-               }
-       }
-       
-       /**
-        * Get the correct paper size from the print settings.
-        * 
-        * @param settings      the print settings
-        * @return                      the paper size
-        */
-       private Rectangle getSize(PrintSettings settings) {
-               PaperSize size = settings.getPaperSize();
-               PaperOrientation orientation = settings.getPaperOrientation();
-               return orientation.orient(size.getSize());
-       }
-       
+            }
+        }
+    }
+
+    /**
+     * Get the correct paper size from the print settings.
+     *
+     * @param settings the print settings
+     *
+     * @return the paper size
+     */
+    private Rectangle getSize(PrintSettings settings) {
+        PaperSize size = settings.getPaperSize();
+        PaperOrientation orientation = settings.getPaperOrientation();
+        return orientation.orient(size.getSize());
+    }
+
 }
index 3f4655c6a1871a2b245f12fc94ccb62a8a2bedf3..648e7231ba58e1d669db7f4269a7843547431824 100644 (file)
@@ -31,4 +31,8 @@ public class PrintFigure extends RocketFigure {
                this.scale = theScale; //dpi/0.0254*scaling;
                updateFigure();
        }
+
+    public double getFigureHeightPx() {
+        return this.figureHeightPx;
+    }
 }
index c603f2f970c3dd4520bff50b99d5d7c8f7382d2a..734e433bd3c6e8bfd84a6edaf90e97cc4bbe335a 100644 (file)
@@ -7,12 +7,20 @@ package net.sf.openrocket.gui.print;
  * Utilities for print units.
  */
 public enum PrintUnit {
+    FOOT {
+        public double toInches(double d) { return d*12; }
+        public double toMillis(double d) { return d/FEET_PER_MM; }
+        public double toCentis(double d) { return d/(FEET_PER_MM*TEN); }
+        public double toMeters(double d) { return d/(FEET_PER_MM*TEN*TEN*TEN); }
+        public double toPoints(double d) { return (d * POINTS_PER_INCH * 12); }
+        public double convert(double d, PrintUnit u) { return u.toInches(d)/12; }
+    },
     INCHES {
         public double toInches(double d) { return d; }
         public double toMillis(double d) { return d/INCHES_PER_MM; }
         public double toCentis(double d) { return d/(INCHES_PER_MM*TEN); }
         public double toMeters(double d) { return d/(INCHES_PER_MM*TEN*TEN*TEN); }
-        public long   toPoints(double d) { return (long)(d * POINTS_PER_INCH); }
+        public double toPoints(double d) { return (d * POINTS_PER_INCH); }
         public double convert(double d, PrintUnit u) { return u.toInches(d); }
     },
     MILLIMETERS {
@@ -20,7 +28,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d; }
         public double toCentis(double d) { return d/TEN; }
         public double toMeters(double d) { return d/(TEN*TEN*TEN); }
-        public long   toPoints(double d) { return INCHES.toPoints(toInches(d)); }
+        public double toPoints(double d) { return INCHES.toPoints(toInches(d)); }
         public double convert(double d, PrintUnit u) { return u.toMillis(d); }
     },
     CENTIMETERS {
@@ -28,7 +36,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d * TEN; }
         public double toCentis(double d) { return d; }
         public double toMeters(double d) { return d/(TEN*TEN); }
-        public long   toPoints(double d) { return INCHES.toPoints(toInches(d)); }
+        public double toPoints(double d) { return INCHES.toPoints(toInches(d)); }
         public double convert(double d, PrintUnit u) { return u.toCentis(d); }
     },
     METERS {
@@ -36,7 +44,7 @@ public enum PrintUnit {
         public double toMillis(double d) { return d * TEN * TEN * TEN; }
         public double toCentis(double d) { return d * TEN * TEN; }
         public double toMeters(double d) { return d; }
-        public long   toPoints(double d) { return INCHES.toPoints(toInches(d)); }
+        public double toPoints(double d) { return INCHES.toPoints(toInches(d)); }
         public double convert(double d, PrintUnit u) { return u.toMeters(d); }
     },
     POINTS {
@@ -44,19 +52,20 @@ public enum PrintUnit {
         public double toMillis(double d) { return d/(POINTS_PER_INCH * INCHES_PER_MM); }
         public double toCentis(double d) { return toMillis(d)/TEN; }
         public double toMeters(double d) { return toMillis(d)/(TEN*TEN*TEN); }
-        public long   toPoints(double d) { return (long)d; }
+        public double toPoints(double d) { return d; }
         public double convert(double d, PrintUnit u) { return u.toPoints(d); }
     };
 
     // Handy constants for conversion methods
     public static final double INCHES_PER_MM = 0.0393700787d;
+    public static final double FEET_PER_MM = INCHES_PER_MM /12;
     public static final double MM_PER_INCH = 1.0d/INCHES_PER_MM;
     public static final long TEN = 10;
     /**
      * PPI is Postscript Point and is a standard of 72.  Java2D also uses this internally as a pixel-per-inch, so pixels
      * and points are for the most part interchangeable (unless the defaults are changed), which makes translating
      * between the screen and a print job easier.
-     * 
+     *
      * Not to be confused with Dots-Per-Inch, which is printer and print mode dependent.
      */
     public static final int POINTS_PER_INCH = 72;
@@ -151,7 +160,7 @@ public enum PrintUnit {
      * overflow, or <tt>Long.MAX_VALUE</tt> if it would positively overflow.
      * @see #convert
      */
-    public long toPoints(double length) {
+    public double toPoints(double length) {
         throw new AbstractMethodError();
     }
 
index 7f096efcf03da2c8888056788fe1c80c34db0941..3e8af1439f1acb7dc420992da0bbadd9b243f655 100644 (file)
@@ -34,12 +34,12 @@ public class PrintUtilities implements Printable {
        public static final int NORMAL_FONT_SIZE = Font.DEFAULTSIZE - 3;
        public static final int SMALL_FONT_SIZE = NORMAL_FONT_SIZE - 3;
        
-       public static final Font BOLD = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE, Font.BOLD);
-       public static final Font BIG_BOLD = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE + 3, Font.BOLD);
-       public static final Font BOLD_UNDERLINED = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE,
+       public static final Font BOLD = new Font(ITextHelper.getBaseFont(), NORMAL_FONT_SIZE, Font.BOLD);
+       public static final Font BIG_BOLD = new Font(ITextHelper.getBaseFont(), NORMAL_FONT_SIZE + 3, Font.BOLD);
+       public static final Font BOLD_UNDERLINED = new Font(ITextHelper.getBaseFont(), NORMAL_FONT_SIZE,
                                                                                                                Font.BOLD | Font.UNDERLINE);
-       public static final Font NORMAL = new Font(Font.FontFamily.HELVETICA, NORMAL_FONT_SIZE);
-       public static final Font SMALL = new Font(Font.FontFamily.HELVETICA, SMALL_FONT_SIZE);
+       public static final Font NORMAL = new Font(ITextHelper.getBaseFont(), NORMAL_FONT_SIZE);
+       public static final Font SMALL = new Font(ITextHelper.getBaseFont(), SMALL_FONT_SIZE);
        
 
        private Component componentToBePrinted;
diff --git a/core/src/net/sf/openrocket/gui/print/PrintableCenteringRing.java b/core/src/net/sf/openrocket/gui/print/PrintableCenteringRing.java
new file mode 100644 (file)
index 0000000..00c4e89
--- /dev/null
@@ -0,0 +1,196 @@
+package net.sf.openrocket.gui.print;
+
+import net.sf.openrocket.gui.print.visitor.CenteringRingStrategy;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.ClusterConfiguration;
+import net.sf.openrocket.rocketcomponent.InnerTube;
+import net.sf.openrocket.util.ArrayList;
+import net.sf.openrocket.util.Coordinate;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.Ellipse2D;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class creates a renderable centering ring.  It depends only on AWT/Swing and can be called from other actors
+ * (like iText handlers) to render the centering ring on different graphics contexts.
+ */
+public class PrintableCenteringRing extends AbstractPrintable<CenteringRing> {
+    /**
+     * If the component to be drawn is a centering ring, save a reference to it.
+     */
+    private CenteringRing target;
+
+    /**
+     * The line length of the cross hairs.
+     */
+    private final int lineLength = 10;
+
+    /**
+     * A set of the inner 'holes'.  At least one, but will have many if clustered.
+     */
+    private Set<CenteringRingStrategy.Dimension> innerCenterPoints = new HashSet<CenteringRingStrategy.Dimension>();
+
+    /**
+     * Construct a simple, non-clustered, printable centering ring, or if the motor mount represents a clustered
+     * configuration then get the cluster points to create the centering ring.
+     *
+     * @param theRing       the component to print
+     * @param theMotorMount the motor mount if clustered, else null
+     */
+    private PrintableCenteringRing(CenteringRing theRing, InnerTube theMotorMount) {
+        super(false, theRing);
+        if (theMotorMount == null || theMotorMount.getClusterConfiguration().equals(ClusterConfiguration.SINGLE)) {
+            //Single motor.
+            final float v = (float) PrintUnit.METERS.toPoints(target.getOuterRadius());
+            innerCenterPoints.add(
+                    new CenteringRingStrategy.Dimension(v, v,
+                            (float) PrintUnit.METERS.toPoints((target.getInnerRadius()))));
+        }
+        else {
+            List<Coordinate> coords = theMotorMount.getClusterPoints();
+            List<Coordinate> points = new ArrayList<Coordinate>();
+            for (Coordinate coordinate : coords) {
+                points.add(coordinate.setX(theMotorMount.getOuterRadius()));
+            }
+            populateCenterPoints(points);
+        }
+    }
+
+    /**
+     * Constructor for a clustered centering ring.  This version is for a "split cluster", where each motor mount tube
+     * is a distinct entity.
+     *
+     * @param theRing        the centering ring component
+     * @param theMotorMounts a list of the motor mount tubes that are physically supported by the centering ring
+     */
+    private PrintableCenteringRing(CenteringRing theRing, List<InnerTube> theMotorMounts) {
+        super(false, theRing);
+        List<Coordinate> points = new ArrayList<Coordinate>();
+        //Transform the radial positions of the tubes.
+        for (InnerTube it : theMotorMounts) {
+            if (it.getClusterCount() > 1) {
+                List<Coordinate> c = it.getClusterPoints();
+                for (Coordinate coordinate : c) {
+                    points.add(coordinate.setX(it.getOuterRadius()));
+                }
+            }
+            else {
+                double y = it.getRadialShiftY();
+                double z = it.getRadialShiftZ();
+                Coordinate coordinate = new Coordinate(it.getOuterRadius(), y, z);
+                points.add(coordinate);
+            }
+        }
+        populateCenterPoints(points);
+    }
+
+    /**
+     * Factory method to create a printable centering ring.
+     *
+     * @param theRing        the component to print
+     * @param theMotorMounts the motor mount if clustered, else null
+     */
+    public static PrintableCenteringRing create(CenteringRing theRing, List<InnerTube> theMotorMounts) {
+        if (theMotorMounts == null) {
+            return new PrintableCenteringRing(theRing, (InnerTube) null);
+        }
+        else if (theMotorMounts.size() <= 1) {
+            return new PrintableCenteringRing(theRing, theMotorMounts.isEmpty() ? null : theMotorMounts.get(0));
+        }
+        else {
+            return new PrintableCenteringRing(theRing, theMotorMounts);
+        }
+    }
+
+    /**
+     * Initialize the set of center points for each motor mount tube, based on the tube coordinates.
+     *
+     * @param theCoords the list of tube coordinates; each coordinate is in the OR units (meters) and must be
+     *                  transformed to the printing (points) coordinate system
+     */
+    private void populateCenterPoints(final List<Coordinate> theCoords) {
+        float radius = (float) PrintUnit.METERS.toPoints(target.getOuterRadius());
+        for (Coordinate coordinate : theCoords) {
+            innerCenterPoints.add(new CenteringRingStrategy.Dimension(
+                    (float) PrintUnit.METERS.toPoints(coordinate.y) + radius, //center point x
+                    (float) PrintUnit.METERS.toPoints(coordinate.z) + radius, //center point y
+                    (float) PrintUnit.METERS.toPoints(coordinate.x)));        //radius of motor mount
+        }
+    }
+
+    /**
+     * @param component the centering ring component
+     */
+    @Override
+    protected void init(final CenteringRing component) {
+
+        target = component;
+
+        double radius = target.getOuterRadius();
+        setSize((int) PrintUnit.METERS.toPoints(2 * radius),
+                (int) PrintUnit.METERS.toPoints(2 * radius));
+    }
+
+    /**
+     * Draw a centering ring.
+     *
+     * @param g2 the graphics context
+     */
+    @Override
+    protected void draw(Graphics2D g2) {
+        double radius = PrintUnit.METERS.toPoints(target.getOuterRadius());
+
+        Color original = g2.getBackground();
+        Shape outerCircle = new Ellipse2D.Double(0, 0, radius * 2, radius * 2);
+        g2.setColor(Color.lightGray);
+        g2.fill(outerCircle);
+        g2.setColor(Color.black);
+        g2.draw(outerCircle);
+
+        for (CenteringRingStrategy.Dimension next : innerCenterPoints) {
+            drawInnerCircle(g2, next.getWidth(), next.getHeight(), next.getBreadth());
+        }
+        g2.setColor(original);
+    }
+
+    /**
+     * Draw one inner circle, representing the motor mount tube, with cross hairs in the center.
+     *
+     * @param g2         the graphics context
+     * @param theCenterX the center x in points
+     * @param theCenterY the center y in points
+     */
+    private void drawInnerCircle(final Graphics2D g2, final double theCenterX, final double theCenterY,
+                                 final double innerRadius) {
+        Shape innerCircle = new Ellipse2D.Double(theCenterX - innerRadius, theCenterY - innerRadius, innerRadius * 2, innerRadius * 2);
+        g2.setColor(Color.white);
+        g2.fill(innerCircle);
+        g2.setColor(Color.black);
+        g2.draw(innerCircle);
+
+        drawCross(g2, (int) theCenterX, (int) theCenterY, lineLength, lineLength);
+    }
+
+    /**
+     * Draw the center cross-hair.
+     *
+     * @param g      the graphics context
+     * @param x      the x coordinate of the center point
+     * @param y      the y coordinate of the center point
+     * @param width  the width in pixels of the horizontal hair
+     * @param height the width in pixels of the vertical hair
+     */
+    private void drawCross(Graphics g, int x, int y, int width, int height) {
+        g.setColor(Color.black);
+        ((Graphics2D) g).setStroke(thinStroke);
+        g.drawLine(x - width / 2, y, x + width / 2, y);
+        g.drawLine(x, y - height / 2, x, y + height / 2);
+    }
+
+}
diff --git a/core/src/net/sf/openrocket/gui/print/PrintableComponent.java b/core/src/net/sf/openrocket/gui/print/PrintableComponent.java
new file mode 100644 (file)
index 0000000..de345fb
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * PrintableComponent.java
+ */
+package net.sf.openrocket.gui.print;
+
+import javax.swing.JPanel;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+
+/**
+ * Common interface for components we want to print. Used by PageFitPrintStrategy
+ *
+ * @author Jason Blood <dyster2000@gmail.com>
+ */
+public class PrintableComponent extends JPanel implements Printable, Comparable<PrintableComponent> {
+
+    /**
+     * The printing offsets.
+     */
+    private int offsetX = 0;
+    private int offsetY = 0;
+
+    /**
+     * Constructor.
+     */
+    public PrintableComponent() {
+       super(false);
+    }
+
+    /**
+     * From the java.awt.print.Printable interface.
+     * <p/>
+     * Prints the page at the specified index into the specified {@link java.awt.Graphics} context in the specified
+     * format. A <code>PrinterJob</code> calls the <code>Printable</code> interface to request that a page be rendered
+     * into the context specified by <code>graphics</code>.  The format of the page to be drawn is specified by
+     * <code>pageFormat</code>.  The zero based index of the requested page is specified by <code>pageIndex</code>. If
+     * the requested page does not exist then this method returns NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned. The
+     * <code>Graphics</code> class or subclass implements the {@link java.awt.print.PrinterGraphics} interface to
+     * provide additional information.  If the <code>Printable</code> object aborts the print job then it throws a
+     * {@link java.awt.print.PrinterException}.
+     * <p/>
+     * Note: This is not currently used in OpenRocket.  It's only here for reference.
+     *
+     * @param graphics   the context into which the page is drawn
+     * @param pageFormat the size and orientation of the page being drawn
+     * @param pageIndex  the zero based index of the page to be drawn
+     *
+     * @return PAGE_EXISTS if the page is rendered successfully or NO_SUCH_PAGE if <code>pageIndex</code> specifies a
+     *         non-existent page.
+     *
+     * @throws java.awt.print.PrinterException
+     *          thrown when the print job is terminated.
+     */
+    @Override
+    public int print (final Graphics graphics, final PageFormat pageFormat, final int pageIndex)
+            throws PrinterException {
+
+        Graphics2D g2d = (Graphics2D) graphics;
+        PrintUtilities.translateToJavaOrigin(g2d, pageFormat);
+        PrintUtilities.disableDoubleBuffering(this);
+        paint(g2d);
+        PrintUtilities.enableDoubleBuffering(this);
+        return Printable.PAGE_EXISTS;
+    }
+
+       /**
+        * Set the offset this component will be printed to the page.
+        * @param x     X offset to print at.
+        * @param y     Y offset to print at.
+        */
+       public void setPrintOffset(int x, int y) {
+        offsetX = x;
+        offsetY = y;
+       }
+
+       /**
+        * Get the X offset this component will be printed to the page.
+        * @return X offset to print at.
+        */
+       public int getOffsetX() {
+               return offsetX;
+       }
+
+       /**
+        * Get the Y offset this component will be printed to the page.
+        * @return Y offset to print at.
+        */
+       public int getOffsetY() {
+               return offsetY;
+       }
+
+
+    /**
+     * Compares this object with the specified object for order.  Returns a negative integer, zero, or a positive integer
+     * as this object is less than, equal to, or greater than the specified object.
+     *
+     * Bin packing theory says that trying to fit the biggest items first may have a better outcome. So this is sorted
+     * in size descending order, with width taking precedence over height.
+     *
+     * @param other the object to be compared.
+     *
+     * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the
+     *         specified object.
+     *
+     * @throws NullPointerException if the specified object is null
+     * @throws ClassCastException   if the specified object's type prevents it from being compared to this object.
+     */
+    @Override
+    public int compareTo(final PrintableComponent other) {
+        int widthDiff = other.getWidth() - getWidth();
+        if (widthDiff > 0) {
+            return 1;
+        }
+        else if (widthDiff < 0) {
+            return -1;
+        }
+        return other.getHeight() - getHeight();
+    }
+}
index cf07cb13e02f96519f249efdccd5e231dc10b996..8e5389b2bd3cf7072efc339414dcf92c56db6716 100644 (file)
@@ -6,34 +6,25 @@ package net.sf.openrocket.gui.print;
 import net.sf.openrocket.rocketcomponent.FinSet;
 import net.sf.openrocket.util.Coordinate;
 
-import javax.swing.*;
-import java.awt.*;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
 import java.awt.geom.GeneralPath;
 import java.awt.image.BufferedImage;
-import java.awt.print.PageFormat;
-import java.awt.print.Printable;
-import java.awt.print.PrinterException;
 
 /**
  * This class allows for a FinSet to be printable.  It does so by decorating an existing finset (which will not be
  * modified) and rendering it within a JPanel.  The JPanel is not actually visualized on a display, but instead renders
  * it to a print device.
  */
-public class PrintableFinSet extends JPanel implements Printable {
+public class PrintableFinSet extends PrintableComponent {
 
     /**
      * The object that represents the shape (outline) of the fin.  This gets drawn onto the Swing component.
      */
     protected GeneralPath polygon = null;
 
-    /**
-     * The X margin.
-     */
-    private final int marginX = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
-    /**
-     * The Y margin.
-     */
-    private final int marginY = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
     /**
      * The minimum X coordinate.
      */
@@ -58,9 +49,7 @@ public class PrintableFinSet extends JPanel implements Printable {
      * @param points an array of points.
      */
     public PrintableFinSet (Coordinate[] points) {
-        super(false);
         init(points);
-        setBackground(Color.white);
     }
 
     /**
@@ -77,8 +66,8 @@ public class PrintableFinSet extends JPanel implements Printable {
         int maxY = 0;
 
         for (Coordinate point : points) {
-            final long x = PrintUnit.METERS.toPoints(point.x);
-            final long y = PrintUnit.METERS.toPoints(point.y);
+            final long x = (long)PrintUnit.METERS.toPoints(point.x);
+            final long y = (long)PrintUnit.METERS.toPoints(point.y);
             minX = (int) Math.min(x, minX);
             minY = (int) Math.min(y, minY);
             maxX = (int) Math.max(x, maxX);
@@ -90,60 +79,6 @@ public class PrintableFinSet extends JPanel implements Printable {
         setSize(maxX - minX, maxY - minY);
     }
 
-    /**
-     * Get the X-axis margin value.
-     *
-     * @return margin, in points
-     */
-    protected double getMarginX () {
-        return marginX;
-    }
-
-    /**
-     * Get the Y-axis margin value.
-     *
-     * @return margin, in points
-     */
-    protected double getMarginY () {
-        return marginY;
-    }
-
-    /**
-     * From the java.awt.print.Printable interface.
-     * <p/>
-     * Prints the page at the specified index into the specified {@link java.awt.Graphics} context in the specified
-     * format. A <code>PrinterJob</code> calls the <code>Printable</code> interface to request that a page be rendered
-     * into the context specified by <code>graphics</code>.  The format of the page to be drawn is specified by
-     * <code>pageFormat</code>.  The zero based index of the requested page is specified by <code>pageIndex</code>. If
-     * the requested page does not exist then this method returns NO_SUCH_PAGE; otherwise PAGE_EXISTS is returned. The
-     * <code>Graphics</code> class or subclass implements the {@link java.awt.print.PrinterGraphics} interface to
-     * provide additional information.  If the <code>Printable</code> object aborts the print job then it throws a
-     * {@link java.awt.print.PrinterException}.
-     * <p/>
-     * Note: This is not currently used in OpenRocket.  It's only here for reference.
-     *
-     * @param graphics   the context into which the page is drawn
-     * @param pageFormat the size and orientation of the page being drawn
-     * @param pageIndex  the zero based index of the page to be drawn
-     *
-     * @return PAGE_EXISTS if the page is rendered successfully or NO_SUCH_PAGE if <code>pageIndex</code> specifies a
-     *         non-existent page.
-     *
-     * @throws java.awt.print.PrinterException
-     *          thrown when the print job is terminated.
-     */
-    @Override
-    public int print (final Graphics graphics, final PageFormat pageFormat, final int pageIndex)
-            throws PrinterException {
-
-        Graphics2D g2d = (Graphics2D) graphics;
-        PrintUtilities.translateToJavaOrigin(g2d, pageFormat);
-        PrintUtilities.disableDoubleBuffering(this);
-        paint(g2d);
-        PrintUtilities.enableDoubleBuffering(this);
-        return Printable.PAGE_EXISTS;
-    }
-
     /**
      * Returns a generated image of the fin set.  May then be used wherever AWT images can be used, or converted to
      * another image/picture format and used accordingly.
@@ -151,17 +86,17 @@ public class PrintableFinSet extends JPanel implements Printable {
      * @return an awt image of the fin set
      */
     public Image createImage () {
-        int width = getWidth() + marginX;
-        int height = getHeight() + marginY;
-        // Create a buffered image in which to draw 
+        int width = getWidth();
+        int height = getHeight();
+        // Create a buffered image in which to draw
         BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        // Create a graphics contents on the buffered image 
+        // Create a graphics contents on the buffered image
         Graphics2D g2d = bufferedImage.createGraphics();
-        // Draw graphics 
+        // Draw graphics
         g2d.setBackground(Color.white);
         g2d.clearRect(0, 0, width, height);
         paintComponent(g2d);
-        // Graphics context no longer needed so dispose it 
+        // Graphics context no longer needed so dispose it
         g2d.dispose();
         return bufferedImage;
     }
@@ -174,13 +109,15 @@ public class PrintableFinSet extends JPanel implements Printable {
      * @param g the Java2D graphics context
      */
     @Override
-    public void paintComponent (Graphics g) {
-        super.paintComponent(g);
+    public void paintComponent(Graphics g) {
         Graphics2D g2d = (Graphics2D) g;
 
         int x = 0;
         int y = 0;
 
+        int marginX = this.getOffsetX();
+        int marginY = this.getOffsetY();
+
         // The minimum X/Y can be negative (primarily only Y due to fin tabs; rarely (never) X, but protect both anyway).
         if (minX < marginX) {
             x = marginX + Math.abs(minX);
@@ -195,5 +132,4 @@ public class PrintableFinSet extends JPanel implements Printable {
         g2d.setPaint(TemplateProperties.getLineColor());
         g2d.draw(polygon);
     }
-
 }
index 78afe6f052cb747358eb60d05b986a69412ea3f9..2cfdfa688efdb0b6a0b7422106c080983bde18b2 100644 (file)
@@ -1,54 +1,54 @@
 package net.sf.openrocket.gui.print;
 
+import net.sf.openrocket.gui.rocketfigure.TransitionShapes;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.util.Transformation;
+
 import java.awt.Graphics2D;
 import java.awt.Rectangle;
 import java.awt.Shape;
 
-import net.sf.openrocket.gui.rocketfigure.TransitionShapes;
-import net.sf.openrocket.rocketcomponent.NoseCone;
-import net.sf.openrocket.rocketcomponent.Transition;
-import net.sf.openrocket.util.Transformation;
+public class PrintableNoseCone extends AbstractPrintable<NoseCone> {
 
-public class PrintableNoseCone extends AbstractPrintableTransition {
-       
        /**
         * If the component to be drawn is a nose cone, save a reference to it.
         */
        private NoseCone target;
-       
+
        /**
         * Construct a printable nose cone.
         *
         * @param noseCone the component to print
         */
-       public PrintableNoseCone(Transition noseCone) {
+       public PrintableNoseCone(NoseCone noseCone) {
                super(false, noseCone);
        }
-       
+
        @Override
-       protected void init(Transition component) {
-               
-               target = (NoseCone) component;
+       protected void init(NoseCone component) {
+
+               target = component;
                double radius = target.getForeRadius();
                if (radius < target.getAftRadius()) {
                        radius = target.getAftRadius();
                }
-               setSize((int) PrintUnit.METERS.toPoints(2 * radius) + marginX,
-                               (int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + marginY);
+               setSize((int) PrintUnit.METERS.toPoints(2 * radius) + 4,
+                               (int) PrintUnit.METERS.toPoints(target.getLength() + target.getAftShoulderLength()) + 4);
        }
-       
+
        /**
-        * Draw a nose cone.
+        * Draw a nose cone.  Presumes that the graphics context has already had the x/y position translated based on
+     * where it should be drawn.
         *
         * @param g2 the graphics context
         */
        @Override
        protected void draw(Graphics2D g2) {
                Shape[] shapes = TransitionShapes.getShapesSide(target, Transformation.rotate_x(0d), PrintUnit.METERS.toPoints(1));
-               
+
                if (shapes != null && shapes.length > 0) {
                        Rectangle r = shapes[0].getBounds();
-                       g2.translate(marginX + r.getHeight() / 2, marginY);
+                       g2.translate(r.getHeight() / 2, 0);
                        g2.rotate(Math.PI / 2);
                        for (Shape shape : shapes) {
                                g2.draw(shape);
index a70703daf9bf8ddfde945d30d12682b3182a8b44..41a9958a1ddc079de9cc5174b749e7478b4a2602 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.gui.print;
 
+import net.sf.openrocket.rocketcomponent.Transition;
+
 import java.awt.BasicStroke;
 import java.awt.Graphics2D;
 import java.awt.geom.Arc2D;
@@ -8,8 +10,6 @@ import java.awt.geom.Line2D;
 import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
 
-import net.sf.openrocket.rocketcomponent.Transition;
-
 /**
  * This class allows for a Transition to be printable.  It does so by decorating an existing transition (which will not be
  * modified) and rendering it within a JPanel.  The JPanel is not actually visualized on a display, but instead renders
@@ -18,8 +18,8 @@ import net.sf.openrocket.rocketcomponent.Transition;
  * Note: Currently nose cones are only supported by drawing the 2D projection of the profile.  A more useful approach
  * may be to draw a myriahedral projection that can be cut out and bent to form the shape.
  */
-public class PrintableTransition extends AbstractPrintableTransition {
-       
+public class PrintableTransition extends AbstractPrintable<Transition> {
+
        /**
         * Dashed array value.
         */
@@ -31,38 +31,38 @@ public class PrintableTransition extends AbstractPrintableTransition {
                        BasicStroke.CAP_BUTT,
                        BasicStroke.JOIN_MITER,
                        10.0f, dash1, 0.0f);
-       
+
        /**
         * The layout is an outer arc, an inner arc, and two lines one either endpoints that connect the arcs.
         * Most of the math involves transposing geometric cartesian coordinates to the Java AWT coordinate system.
         */
        private Path2D gp;
-       
+
        /**
         * The glue tab.
         */
        private Path2D glueTab1;
-       
+
        /**
         * The alignment marks.
         */
        private Line2D tick1, tick2;
-       
+
        /**
         * The x coordinates for the two ticks drawn at theta degrees.
         */
        private int tick3X, tick4X;
-       
+
        /**
         * The angle, in degrees.
         */
        private float theta;
-       
+
        /**
         * The x,y coordinates for where the virtual circle center is located.
         */
        private int circleCenterX, circleCenterY;
-       
+
        /**
         * Constructor.
         *
@@ -71,13 +71,20 @@ public class PrintableTransition extends AbstractPrintableTransition {
        public PrintableTransition(Transition transition) {
                super(false, transition);
        }
-       
+
+    /**
+     * Compute the basic values of each arc of the transition/shroud.  This is adapted from
+     * <a href="http://www.rocketshoppe.com/info/Transitions.pdf">The Properties of
+     * Model Rocket Body Tube Transitions, by J.R. Brohm</a>
+     *
+     * @param component the component
+     */
        @Override
        protected void init(Transition component) {
-               
+
                double r1 = component.getAftRadius();
                double r2 = component.getForeRadius();
-               
+
                //Regardless of orientation, we have the convention of R1 as the smaller radius.  Flip if different.
                if (r1 > r2) {
                        r1 = r2;
@@ -87,19 +94,19 @@ public class PrintableTransition extends AbstractPrintableTransition {
                double v = r2 - r1;
                double tmp = Math.sqrt(v * v + len * len);
                double factor = tmp / v;
-               
+
                theta = (float) (360d * v / tmp);
-               
+
                int r1InPoints = (int) PrintUnit.METERS.toPoints(r1 * factor);
                int r2InPoints = (int) PrintUnit.METERS.toPoints(r2 * factor);
-               
-               int x = marginX;
+
+               int x = 0;
                int tabOffset = 35;
-               int y = tabOffset + marginY;
-               
+               int y = tabOffset;
+
                Arc2D.Double outerArc = new Arc2D.Double();
                Arc2D.Double innerArc = new Arc2D.Double();
-               
+
                //If the arcs are more than 3/4 of a circle, then assume the height (y) is the same as the radius of the bigger arc.
                if (theta >= 270) {
                        y += r2InPoints;
@@ -110,23 +117,23 @@ public class PrintableTransition extends AbstractPrintableTransition {
                        double thetaRads = Math.toRadians(theta - 180);
                        y += (int) ((Math.cos(thetaRads) * r2InPoints) * Math.tan(thetaRads));
                }
-               
+
                circleCenterY = y;
                circleCenterX = r2InPoints + x;
-               
+
                //Create the larger arc.
                outerArc.setArcByCenter(circleCenterX, circleCenterY, r2InPoints, 180, theta, Arc2D.OPEN);
-               
+
                //Create the smaller arc.
                innerArc.setArcByCenter(circleCenterX, circleCenterY, r1InPoints, 180, theta, Arc2D.OPEN);
-               
+
                //Create the line between the start of the larger arc and the start of the smaller arc.
                Path2D.Double line = new Path2D.Double();
                line.setWindingRule(Path2D.WIND_NON_ZERO);
                line.moveTo(x, y);
                final int width = r2InPoints - r1InPoints;
                line.lineTo(width + x, y);
-               
+
                //Create the line between the endpoint of the larger arc and the endpoint of the smaller arc.
                Path2D.Double closingLine = new Path2D.Double();
                closingLine.setWindingRule(Path2D.WIND_NON_ZERO);
@@ -134,21 +141,21 @@ public class PrintableTransition extends AbstractPrintableTransition {
                closingLine.moveTo(innerArcEndPoint.getX(), innerArcEndPoint.getY());
                Point2D outerArcEndPoint = outerArc.getEndPoint();
                closingLine.lineTo(outerArcEndPoint.getX(), outerArcEndPoint.getY());
-               
+
                //Add all shapes to the polygon path.
                gp = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
                gp.append(line, false);
                gp.append(outerArc, false);
                gp.append(closingLine, false);
                gp.append(innerArc, false);
-               
+
                //Create the glue tab.
                glueTab1 = new Path2D.Float(GeneralPath.WIND_EVEN_ODD, 4);
                glueTab1.moveTo(x, y);
                glueTab1.lineTo(x + tabOffset, y - tabOffset);
                glueTab1.lineTo(width + x - tabOffset, y - tabOffset);
                glueTab1.lineTo(width + x, y);
-               
+
                //Create tick marks for alignment, 1/4 of the width in from either edge
                int fromEdge = width / 4;
                final int tickLength = 8;
@@ -156,13 +163,13 @@ public class PrintableTransition extends AbstractPrintableTransition {
                tick1 = new Line2D.Float(x + fromEdge, y, x + fromEdge, y + tickLength);
                //Upper right
                tick2 = new Line2D.Float(x + width - fromEdge, y, x + width - fromEdge, y + tickLength);
-               
+
                tick3X = r2InPoints - fromEdge;
                tick4X = r1InPoints + fromEdge;
-               
+
                setSize(gp.getBounds().width, gp.getBounds().height + tabOffset);
        }
-       
+
        /**
         * Draw alignment marks on an angle.
         *
@@ -179,7 +186,7 @@ public class PrintableTransition extends AbstractPrintableTransition {
                g2.rotate(Math.toRadians(theta));
                g2.translate(-x, -y);
        }
-       
+
        /**
         * Draw a transition.
         *
@@ -199,9 +206,9 @@ public class PrintableTransition extends AbstractPrintableTransition {
                                circleCenterY,
                                new Line2D.Float(-tick4X, 0, -tick4X, -8),
                                theta);
-               
+
                g2.setStroke(dashed);
                g2.draw(glueTab1);
        }
-       
+
 }
diff --git a/core/src/net/sf/openrocket/gui/print/components/Rule.java b/core/src/net/sf/openrocket/gui/print/components/Rule.java
new file mode 100644 (file)
index 0000000..b26d652
--- /dev/null
@@ -0,0 +1,274 @@
+package net.sf.openrocket.gui.print.components;
+
+import net.sf.openrocket.gui.print.PrintUnit;
+import net.sf.openrocket.gui.print.PrintableComponent;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+
+/**
+ * This class creates a Swing ruler.  The ruler has both vertical and horizontal rules, as well as divisions for both
+ * inches and centimeters.
+ */
+public class Rule extends PrintableComponent {
+
+    public static enum Orientation {
+        TOP,
+        BOTTOM
+    }
+
+    public static final int TINIEST_TICK_LENGTH = 3;
+    public static final int MINOR_TICK_LENGTH = 6;
+    public static final int MID_MAJOR_TICK_LENGTH = 9;
+    public static final int MAJOR_TICK_LENGTH = 14;
+
+    private Orientation orientation;
+
+    /**
+     * Constructor.
+     *
+     * @param theOrientation defines if the horizontal ruler should be on the top or bottom; the vertical is always
+     *                       left justified
+     */
+    public Rule(Orientation theOrientation) {
+        orientation = theOrientation;
+        int dim = (int) PrintUnit.INCHES.toPoints(2) + 32;
+        setSize(dim, dim);
+    }
+
+    /**
+     * Render the component onto a graphics context.
+     *
+     * @param g the opaque graphics context
+     */
+    public void paintComponent(Graphics g) {
+        Graphics2D g2 = (Graphics2D) g;
+
+        double div = PrintUnit.INCHES.toPoints(1) / 8;  //1/8 inch increment
+        final int width = (int) PrintUnit.INCHES.toPoints(2);
+        int x = 20;
+        int y = x + 20;
+        boolean inchOutSide = true;
+
+        g2.translate(getOffsetX(), getOffsetY());
+
+        if (orientation == Orientation.TOP) {
+            Font f = g.getFont();
+            g.setFont(f.deriveFont(f.getSize() - 2f));
+            g.drawString("in  cm", x - MAJOR_TICK_LENGTH, y + width + 20);
+            g.drawString("in", x + width + 4, y + 4);
+            g.drawString("cm", x + width + 4, y + 18);
+            y += 6;
+
+            drawVerticalRule(g2, true, inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8);
+            drawHorizontalRule(g2, true, !inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8);
+            div = PrintUnit.MILLIMETERS.toPoints(1);  //mm increment
+            drawVerticalRule(g2, true, !inchOutSide, x, y, width, 0, 0, div * 5, div * 10);
+            drawHorizontalRule(g2, true, inchOutSide, x, y, width, 0, 0, div * 5, div * 10);
+        }
+        else {
+            Font f = g.getFont();
+            g.setFont(f.deriveFont(f.getSize() - 2f));
+            g.drawString("in  cm", x - MAJOR_TICK_LENGTH, y);
+            g.drawString("cm", x + width + 6, y + width + 4);
+            g.drawString("in", x + width + 6, y + width + 18);
+            y += 6;
+
+            //Draw Inches first, with 1/2", 1/4", and 1/8" tick marks.
+            drawVerticalRule(g2, false, inchOutSide, x, y, width, 0, div * 2, div * 4, div * 8);
+            drawHorizontalRule(g2, true, inchOutSide, x, y + width, width, 0, div * 2, div * 4, div * 8);
+            div = PrintUnit.MILLIMETERS.toPoints(1);  //mm increment
+            //Draw cm (10mm) and 1/2 cm (5mm) marks
+            drawVerticalRule(g2, false, !inchOutSide, x, y, width, 0, 0, div * 5, div * 10);
+            drawHorizontalRule(g2, true, !inchOutSide, x, y + width, width, 0, 0, div * 5, div * 10);
+        }
+    }
+
+    /**
+     * Draw a horizontal ruler.
+     *
+     * @param g              the graphics context
+     * @param vertexAtLeft   true if the horizontal/vertical vertex is oriented to the top
+     * @param drawTicksDown  true if the ruler should draw interval tick marks to the underside of the solid ruler line
+     * @param x              starting x position of the ruler
+     * @param y              starting y position of the rule
+     * @param length         the number of points in length to extend the vertical ruler
+     * @param tinyEveryX     the number of points for each tiny division tick line; if zero or negative tiny will not be
+     *                       drawn
+     * @param minorEveryX    the number of points for each minor division tick line; if zero or negative minor will not
+     *                       be drawn
+     * @param midMajorEveryX the number of points for each mid-major division tick line
+     * @param majorEveryX    the number of points for each major division tick line (this is typically the inch or cm
+     *                       distance in points).
+     */
+    private void drawHorizontalRule(Graphics2D g,
+                                   boolean vertexAtLeft,
+                                   boolean drawTicksDown,
+                                   int x, int y, int length,
+                                   double tinyEveryX,
+                                   double minorEveryX,
+                                   double midMajorEveryX,
+                                   double majorEveryX) {
+
+        //Draw solid horizontal line
+        g.setColor(Color.black);
+        g.drawLine(x, y, x + length, y);
+
+        int tiniest = drawTicksDown ? TINIEST_TICK_LENGTH : -1 * TINIEST_TICK_LENGTH;
+        int minor = drawTicksDown ? MINOR_TICK_LENGTH : -1 * MINOR_TICK_LENGTH;
+        int mid = drawTicksDown ? MID_MAJOR_TICK_LENGTH : -1 * MID_MAJOR_TICK_LENGTH;
+        int major = drawTicksDown ? MAJOR_TICK_LENGTH : -1 * MAJOR_TICK_LENGTH;
+
+        //Draw vertical rule ticks for the horizontal ruler
+        //Draw minor ticks
+        int initial = x;
+        int end = initial + length;
+        double increment = tinyEveryX;
+        boolean lessThanEqual = true;
+        if (!vertexAtLeft) {
+            initial = x + length;
+            end = x;
+            lessThanEqual = false;
+        }
+
+        if (tinyEveryX > 0) {
+            if (!vertexAtLeft) {
+                increment = -1 * increment;
+            }
+            for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) {
+                g.drawLine((int) xtick, y, (int) xtick, y + tiniest);
+            }
+        }
+        //Draw minor ticks
+        if (minorEveryX > 0) {
+            if (!vertexAtLeft) {
+                increment = -1 * minorEveryX;
+            }
+            else {
+                increment = minorEveryX;
+            }
+            for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) {
+                g.drawLine((int) xtick, y, (int) xtick, y + minor);
+            }
+        }
+
+        //Draw mid-major ticks
+        if (midMajorEveryX > 0) {
+            if (!vertexAtLeft) {
+                increment = -1 * midMajorEveryX;
+            }
+            else {
+                increment = midMajorEveryX;
+            }
+            for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) {
+                g.drawLine((int) xtick, y, (int) xtick, y + mid);
+            }
+        }
+        if (!vertexAtLeft) {
+            increment = -1 * majorEveryX;
+        }
+        else {
+            increment = majorEveryX;
+        }
+        //Draw major ticks
+        for (double xtick = initial; lessThanEqual ? (xtick <= end) : (xtick >= end); xtick += increment) {
+            g.drawLine((int) xtick, y, (int) xtick, y + major);
+        }
+
+    }
+
+    /**
+     * Draw a vertical ruler.
+     *
+     * @param g              the graphics context
+     * @param vertexAtTop    true if the horizontal/vertical vertex is oriented to the top
+     * @param drawTicksRight true if the ruler should draw interval tick marks to the right side of the solid ruler
+     *                       line
+     * @param x              starting x position of the ruler
+     * @param y              starting y position of the rule
+     * @param length         the number of points in length to extend the vertical ruler
+     * @param tinyEveryY     the number of points for each tiny division tick line; if zero or negative tiny will not be
+     *                       drawn
+     * @param minorEveryY    the number of points for each minor division tick line; if zero or negative minor will not
+     *                       be drawn
+     * @param midMajorEveryY the number of points for each mid-major division tick line
+     * @param majorEveryY    the number of points for each major division tick line (this is typically the inch or cm
+     *                       distance in points).
+     */
+    private void drawVerticalRule(Graphics2D g,
+                                 boolean vertexAtTop,
+                                 boolean drawTicksRight, int x, int y, int length,
+                                 double tinyEveryY,
+                                 double minorEveryY,
+                                 double midMajorEveryY,
+                                 double majorEveryY) {
+
+        int tiniest = drawTicksRight ? TINIEST_TICK_LENGTH : -1 * TINIEST_TICK_LENGTH;
+        int minor = drawTicksRight ? MINOR_TICK_LENGTH : -1 * MINOR_TICK_LENGTH;
+        int mid = drawTicksRight ? MID_MAJOR_TICK_LENGTH : -1 * MID_MAJOR_TICK_LENGTH;
+        int major = drawTicksRight ? MAJOR_TICK_LENGTH : -1 * MAJOR_TICK_LENGTH;
+
+        //Draw solid vertical line
+        g.setColor(Color.black);
+        g.drawLine(x, y, x, y + length);
+
+        //Draw horizontal rule ticks for the vertical ruler
+        //Draw tiny ticks
+        int initial = y;
+        int end = initial + length;
+        double increment = tinyEveryY;
+        boolean lessThanEqual = true;
+        if (!vertexAtTop) {
+            initial = y + length;
+            end = y;
+            lessThanEqual = false;
+        }
+
+        if (tinyEveryY > 0) {
+            if (!vertexAtTop) {
+                increment = -1 * increment;
+            }
+            for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) {
+                g.drawLine(x, (int) tick, x - tiniest, (int) tick);
+            }
+        }
+
+        //Draw minor ticks
+        if (minorEveryY > 0) {
+            if (!vertexAtTop) {
+                increment = -1 * minorEveryY;
+            }
+            else {
+                increment = minorEveryY;
+            }
+            for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) {
+                g.drawLine(x, (int) tick, x - minor, (int) tick);
+            }
+        }
+
+        //Draw mid-major ticks
+        if (!vertexAtTop) {
+            increment = -1 * midMajorEveryY;
+        }
+        else {
+            increment = midMajorEveryY;
+        }
+        for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) {
+            g.drawLine(x, (int) tick, x - mid, (int) tick);
+        }
+
+        //Draw major ticks
+        if (!vertexAtTop) {
+            increment = -1 * majorEveryY;
+        }
+        else {
+            increment = majorEveryY;
+        }
+        for (double tick = initial; lessThanEqual ? (tick <= end) : (tick >= end); tick += increment) {
+            g.drawLine(x, (int) tick, x - major, (int) tick);
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/core/src/net/sf/openrocket/gui/print/visitor/CenteringRingStrategy.java b/core/src/net/sf/openrocket/gui/print/visitor/CenteringRingStrategy.java
new file mode 100644 (file)
index 0000000..1df7569
--- /dev/null
@@ -0,0 +1,270 @@
+package net.sf.openrocket.gui.print.visitor;
+
+import com.itextpdf.text.Document;
+import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.Rectangle;
+import com.itextpdf.text.pdf.PdfWriter;
+import net.sf.openrocket.gui.print.AbstractPrintable;
+import net.sf.openrocket.gui.print.ITextHelper;
+import net.sf.openrocket.gui.print.PrintUnit;
+import net.sf.openrocket.gui.print.PrintableCenteringRing;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.rocketcomponent.InnerTube;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.ArrayList;
+
+import java.awt.image.BufferedImage;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A strategy for printing a centering ring to iText.
+ */
+public class CenteringRingStrategy {
+
+    /**
+     * The logger.
+     */
+    private static final LogHelper log = Application.getLogger();
+
+    /**
+     * The iText document.
+     */
+    protected Document document;
+
+    /**
+     * The direct iText writer.
+     */
+    protected PdfWriter writer;
+
+    /**
+     * The stages selected.
+     */
+    protected Set<Integer> stages;
+
+    /**
+     * Strategy for fitting multiple components onto a page.
+     */
+    protected PageFitPrintStrategy pageFitPrint;
+
+    /**
+     * Constructor.
+     *
+     * @param doc              The iText document
+     * @param theWriter        The direct iText writer
+     * @param theStagesToVisit The stages to be visited by this strategy
+     */
+    public CenteringRingStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit, PageFitPrintStrategy pageFit) {
+        document = doc;
+        writer = theWriter;
+        stages = theStagesToVisit;
+        pageFitPrint = pageFit;
+    }
+
+    /**
+     * Recurse through the given rocket component.
+     *
+     * @param root the root component; all children will be visited recursively
+     */
+    public void writeToDocument(final RocketComponent root) {
+        List<RocketComponent> rc = root.getChildren();
+        goDeep(rc);
+    }
+
+
+    /**
+     * Recurse through the given rocket component.
+     *
+     * @param theRc an array of rocket components; all children will be visited recursively
+     */
+    protected void goDeep(final List<RocketComponent> theRc) {
+        for (RocketComponent rocketComponent : theRc) {
+            if (rocketComponent instanceof CenteringRing) {
+                render((CenteringRing) rocketComponent);
+            }
+            else if (rocketComponent.getChildCount() > 0) {
+                goDeep(rocketComponent.getChildren());
+            }
+        }
+    }
+
+    /**
+     * Find the inner tubes that are physically supported by the given centering ring.  Note that this only looks for
+     * motor mount tubes that are siblings to the centering ring.
+     *
+     * @param rc the centering ring, for which all motor mount tubes that run through it are located.
+     *
+     * @return the list of tubes found
+     */
+    private List<InnerTube> findMotorMount(CenteringRing rc) {
+        RocketComponent parent = rc.getParent();
+        List<RocketComponent> siblings = parent.getChildren();
+
+        List<InnerTube> mounts = new ArrayList<InnerTube>();
+        for (RocketComponent rocketComponents : siblings) {
+            if (rocketComponents != rc) {
+                if (rocketComponents instanceof InnerTube) {
+                    InnerTube it = (InnerTube) rocketComponents;
+                    if (overlaps(rc, it)) {
+                        mounts.add(it);
+                    }
+                }
+            }
+        }
+
+        return mounts;
+    }
+
+    /**
+     * Determine if the centering ring physically overlaps with the inner tube.
+     *
+     * @param one the centering ring
+     * @param two the inner body tube
+     *
+     * @return true if the two physically intersect, from which we infer that the centering ring supports the tube
+     */
+    private boolean overlaps(CenteringRing one, InnerTube two) {
+        final double crTopPosition = one.asPositionValue(RocketComponent.Position.ABSOLUTE, one.getParent());
+        final double mmTopPosition = two.asPositionValue(RocketComponent.Position.ABSOLUTE, two.getParent());
+        final double crBottomPosition = one.getLength() + crTopPosition;
+        final double mmBottomPosition = two.getLength() + mmTopPosition;
+
+        if (crTopPosition >= mmTopPosition && crTopPosition <= mmBottomPosition) {
+            return true;
+        }
+        if (crBottomPosition >= mmTopPosition && crBottomPosition <= mmBottomPosition) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * The core behavior of this visitor.
+     *
+     * @param component the object to extract info about; a graphical image of the centering ring shape is drawn to the
+     *                  document
+     */
+    private void render(final CenteringRing component) {
+        try {
+            AbstractPrintable pfs;
+            pfs = PrintableCenteringRing.create(component, findMotorMount(component));
+
+            java.awt.Dimension size = pfs.getSize();
+            final Dimension pageSize = getPageSize();
+            if (fitsOnOnePage(pageSize, size.getWidth(), size.getHeight())) {
+                pageFitPrint.addComponent(pfs);
+            }
+            else {
+                int off = (int) (PrintUnit.POINTS_PER_INCH * 0.3f);
+                pfs.setPrintOffset(off, off);
+                BufferedImage image = (BufferedImage) pfs.createImage();
+                ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
+                        document, writer, image);
+                document.newPage();
+            }
+        }
+        catch (DocumentException e) {
+            log.error("Could not render the centering ring.", e);
+        }
+    }
+
+    /**
+     * Determine if the image will fit on the given page.
+     *
+     * @param pageSize the page size
+     * @param wImage   the width of the thing to be printed
+     * @param hImage   the height of the thing to be printed
+     *
+     * @return true if the thing to be printed will fit on a single page
+     */
+    private boolean fitsOnOnePage(Dimension pageSize, double wImage, double hImage) {
+        double wPage = pageSize.getWidth();
+        double hPage = pageSize.getHeight();
+
+        int wRatio = (int) Math.ceil(wImage / wPage);
+        int hRatio = (int) Math.ceil(hImage / hPage);
+
+        return wRatio <= 1.0d && hRatio <= 1.0d;
+    }
+
+    /**
+     * Get the dimensions of the paper page.
+     *
+     * @return an internal Dimension
+     */
+    protected Dimension getPageSize() {
+        return new Dimension(document.getPageSize().getWidth(),
+                document.getPageSize().getHeight());
+    }
+
+    /**
+     * Convenience class to model a dimension.
+     */
+    public static class Dimension {
+        /**
+         * Width, in points.
+         */
+        public float width;
+        /**
+         * Height, in points.
+         */
+        public float height;
+        /**
+         * Breadth, in points.
+         */
+        public float breadth = 0f;
+
+        /**
+         * Constructor.
+         *
+         * @param w width
+         * @param h height
+         */
+        public Dimension(float w, float h) {
+            width = w;
+            height = h;
+        }
+
+        /**
+         * Constructor.
+         *
+         * @param w width
+         * @param h height
+         * @param b breadth; optionally used to represent radius
+         */
+        public Dimension(float w, float h, float b) {
+            width = w;
+            height = h;
+            breadth = b;
+        }
+
+        /**
+         * Get the width.
+         *
+         * @return the width
+         */
+        public float getWidth() {
+            return width;
+        }
+
+        /**
+         * Get the height.
+         *
+         * @return the height
+         */
+        public float getHeight() {
+            return height;
+        }
+
+        /**
+         * Get the breadth.
+         *
+         * @return the breadth
+         */
+        public float getBreadth() {
+            return breadth;
+        }
+    }
+}
index 80e15a216763fd034bf15a0c098fa2d0e6ef3101..3870490831217061986a4c16b7d60aa70f6be8fe 100644 (file)
@@ -6,16 +6,15 @@ package net.sf.openrocket.gui.print.visitor;
 import com.itextpdf.text.Document;
 import com.itextpdf.text.DocumentException;
 import com.itextpdf.text.Rectangle;
-import com.itextpdf.text.pdf.PdfContentByte;
 import com.itextpdf.text.pdf.PdfWriter;
 import net.sf.openrocket.gui.print.ITextHelper;
+import net.sf.openrocket.gui.print.PrintUnit;
 import net.sf.openrocket.gui.print.PrintableFinSet;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.rocketcomponent.FinSet;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.startup.Application;
 
-import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.util.List;
 import java.util.Set;
@@ -45,6 +44,11 @@ public class FinSetPrintStrategy {
      */
     protected Set<Integer> stages;
 
+    /**
+     * Strategy for fitting multiple components onto a page.
+     */
+       protected PageFitPrintStrategy pageFitPrint;
+
     /**
      * Constructor.
      *
@@ -52,10 +56,11 @@ public class FinSetPrintStrategy {
      * @param theWriter        The direct iText writer
      * @param theStages        The stages to be printed by this strategy
      */
-    public FinSetPrintStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStages) {
+    public FinSetPrintStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStages, PageFitPrintStrategy pageFit) {
         document = doc;
         writer = theWriter;
         stages = theStages;
+        pageFitPrint = pageFit;
     }
 
     /**
@@ -98,14 +103,16 @@ public class FinSetPrintStrategy {
                 java.awt.Dimension finSize = pfs.getSize();
                 final Dimension pageSize = getPageSize();
                 if (fitsOnOnePage(pageSize, finSize.getWidth(), finSize.getHeight())) {
-                    printOnOnePage(pfs);
+                                       pageFitPrint.addComponent(pfs);
                 }
                 else {
+                    int off = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
+                    pfs.setPrintOffset(off, off);
                     BufferedImage image = (BufferedImage) pfs.createImage();
                     ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
                             document, writer, image);
+                    document.newPage();
                 }
-                document.newPage();
             }
             catch (DocumentException e) {
                 log.error("Could not render fin.", e);
@@ -153,19 +160,6 @@ public class FinSetPrintStrategy {
         return wRatio <= 1.0d && hRatio <= 1.0d;
     }
 
-    /**
-     * Print the fin set.
-     *
-     * @param thePfs the printable fin set
-     */
-    private void printOnOnePage (final PrintableFinSet thePfs) {
-        Dimension d = getPageSize();
-        PdfContentByte cb = writer.getDirectContent();
-        Graphics2D g2 = cb.createGraphics(d.width, d.height);
-        thePfs.print(g2);
-        g2.dispose();
-    }
-
     /**
      * Get the dimensions of the paper page.
      *
diff --git a/core/src/net/sf/openrocket/gui/print/visitor/PageFitPrintStrategy.java b/core/src/net/sf/openrocket/gui/print/visitor/PageFitPrintStrategy.java
new file mode 100644 (file)
index 0000000..10ca735
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * PageFitPrintStrategy.java
+ */
+package net.sf.openrocket.gui.print.visitor;
+
+import com.itextpdf.text.Document;
+import com.itextpdf.text.pdf.PdfContentByte;
+import com.itextpdf.text.pdf.PdfWriter;
+import net.sf.openrocket.gui.print.PrintUnit;
+import net.sf.openrocket.gui.print.PrintableComponent;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.startup.Application;
+
+import java.awt.Graphics2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.ListIterator;
+import java.util.Set;
+
+/**
+ * A strategy for drawing multiple rocket components onto as few pages as possible.
+ *
+ * @author Jason Blood <dyster2000@gmail.com>
+ */
+public class PageFitPrintStrategy {
+
+    /**
+     * The logger.
+     */
+    private static final LogHelper log = Application.getLogger();
+
+    /**
+     * The iText document.
+     */
+    protected Document document;
+
+    /**
+     * The direct iText writer.
+     */
+    protected PdfWriter writer;
+
+    /**
+     * The stages selected.
+     */
+    protected Set<Integer> stages;
+
+       protected ArrayList<PrintableComponent> componentToPrint;
+
+    /**
+     * Constructor.
+     *
+     * @param doc              The iText document
+     * @param theWriter        The direct iText writer
+     */
+    public PageFitPrintStrategy(Document doc, PdfWriter theWriter) {
+        document = doc;
+        writer = theWriter;
+       componentToPrint = new ArrayList<PrintableComponent>();
+    }
+
+    /**
+     * Add a component we want to print.
+     *
+     * @param component The component to add for printing
+     */
+    public void addComponent(PrintableComponent component) {
+               componentToPrint.add(component);
+    }
+
+    /**
+     * Recurse through the given rocket component.
+     *
+     * @param root the root component; all children will be printed recursively
+     */
+    public void writeToDocument (final RocketComponent root) {
+        fitPrintComponents();
+    }
+
+    /**
+     * Iterate through the components to print fitting them onto pages as best possible.
+     */
+    private void fitPrintComponents() {
+       final Dimension pageSize = getPageSize();
+        double wPage = pageSize.getWidth();
+        double hPage = pageSize.getHeight();
+        int marginX = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
+        int marginY = (int)(PrintUnit.POINTS_PER_INCH * 0.3f);
+        PdfContentByte cb = writer.getDirectContent();
+
+        Collections.sort(componentToPrint);
+
+       while (componentToPrint.size() > 0) {
+               int pageY = marginY;
+               Boolean anyAddedToRow;
+
+            Graphics2D g2 = cb.createGraphics(pageSize.width, pageSize.height);
+
+               do {
+                       // Fill the row
+                       int rowX = marginX;
+                       int rowY = pageY;
+                       ListIterator<PrintableComponent> entry = componentToPrint.listIterator();
+                       anyAddedToRow = false;
+
+                       while (entry.hasNext()) {
+                               PrintableComponent component = entry.next();
+                               java.awt.Dimension dim = component.getSize();
+                               if ((rowX + dim.width + marginX < wPage) && (rowY + dim.height + marginY < hPage)) {
+                                       component.setPrintOffset(rowX, rowY);
+                                       rowX += dim.width + marginX;
+                                       if (rowY + dim.height + marginY > pageY) {
+                                               pageY = rowY + dim.height + marginY;
+                        }
+                                       entry.remove();
+                                       component.print(g2);
+                                       anyAddedToRow = true;
+                               }
+                       }
+                pageY += marginY;
+               } while (anyAddedToRow);
+
+               g2.dispose();
+               document.newPage();
+       }
+    }
+
+    /**
+     * Get the dimensions of the paper page.
+     *
+     * @return an internal Dimension
+     */
+    protected Dimension getPageSize () {
+        return new Dimension(document.getPageSize().getWidth(),
+                             document.getPageSize().getHeight());
+    }
+
+    /**
+     * Convenience class to model a dimension.
+     */
+    class Dimension {
+        /** Width, in points. */
+        public float width;
+        /** Height, in points. */
+        public float height;
+
+        /**
+         * Constructor.
+         * @param w width
+         * @param h height
+         */
+        public Dimension (float w, float h) {
+            width = w;
+            height = h;
+        }
+
+        /**
+         * Get the width.
+         *
+         * @return  the width
+         */
+        public float getWidth () {
+            return width;
+        }
+
+        /**
+         * Get the height.
+         *
+         * @return the height
+         */
+        public float getHeight () {
+            return height;
+        }
+    }
+}
index cdeb9247c17742590137596438842d2892884c3f..c155d0cdef0ebc61b908ce2b0d1c529e96248518 100644 (file)
@@ -3,27 +3,54 @@
  */
 package net.sf.openrocket.gui.print.visitor;
 
-import com.itextpdf.text.*;
-import com.itextpdf.text.pdf.PdfPCell;
-import com.itextpdf.text.pdf.PdfPTable;
-import com.itextpdf.text.pdf.PdfWriter;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.ImageIcon;
+
 import net.sf.openrocket.gui.main.ComponentIcons;
 import net.sf.openrocket.gui.print.ITextHelper;
 import net.sf.openrocket.gui.print.PrintUtilities;
 import net.sf.openrocket.gui.print.PrintableFinSet;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.material.Material;
-import net.sf.openrocket.rocketcomponent.*;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.rocketcomponent.BodyComponent;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.Bulkhead;
+import net.sf.openrocket.rocketcomponent.Coaxial;
+import net.sf.openrocket.rocketcomponent.ExternalComponent;
+import net.sf.openrocket.rocketcomponent.FinSet;
+import net.sf.openrocket.rocketcomponent.InnerTube;
+import net.sf.openrocket.rocketcomponent.LaunchLug;
+import net.sf.openrocket.rocketcomponent.MassObject;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.rocketcomponent.Parachute;
+import net.sf.openrocket.rocketcomponent.RadiusRingComponent;
+import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.rocketcomponent.RingComponent;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.ShockCord;
+import net.sf.openrocket.rocketcomponent.Stage;
+import net.sf.openrocket.rocketcomponent.Streamer;
+import net.sf.openrocket.rocketcomponent.Transition;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
-import net.sf.openrocket.util.Coordinate;
 
-import javax.swing.*;
-import java.text.NumberFormat;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
+import com.itextpdf.text.Chunk;
+import com.itextpdf.text.Document;
+import com.itextpdf.text.DocumentException;
+import com.itextpdf.text.Element;
+import com.itextpdf.text.Font;
+import com.itextpdf.text.Image;
+import com.itextpdf.text.Paragraph;
+import com.itextpdf.text.Phrase;
+import com.itextpdf.text.Rectangle;
+import com.itextpdf.text.pdf.PdfPCell;
+import com.itextpdf.text.pdf.PdfPTable;
+import com.itextpdf.text.pdf.PdfWriter;
+import com.itextpdf.text.pdf.draw.VerticalPositionMark;
 
 /**
  * A visitor strategy for creating documentation about parts details.
@@ -142,7 +169,7 @@ public class PartsDetailVisitorStrategy {
         else if (component instanceof LaunchLug) {
             LaunchLug ll = (LaunchLug) component;
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
 
             grid.addCell(createMaterialCell(ll.getMaterial()));
             grid.addCell(createOuterInnerDiaCell(ll));
@@ -152,7 +179,7 @@ public class PartsDetailVisitorStrategy {
         else if (component instanceof NoseCone) {
             NoseCone nc = (NoseCone) component;
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(nc.getMaterial()));
             grid.addCell(ITextHelper.createCell(nc.getType().getName(), PdfPCell.BOTTOM));
             grid.addCell(createLengthCell(component.getLength()));
@@ -163,13 +190,13 @@ public class PartsDetailVisitorStrategy {
         else if (component instanceof Transition) {
             Transition tran = (Transition) component;
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(tran.getMaterial()));
 
             Chunk fore = new Chunk(FORE_DIAMETER + toLength(tran.getForeRadius() * 2));
-            fore.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+            fore.setFont(PrintUtilities.NORMAL);
             Chunk aft = new Chunk(AFT_DIAMETER + toLength(tran.getAftRadius() * 2));
-            aft.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+            aft.setFont(PrintUtilities.NORMAL);
             final PdfPCell cell = ITextHelper.createCell();
             cell.addElement(fore);
             cell.addElement(aft);
@@ -183,7 +210,7 @@ public class PartsDetailVisitorStrategy {
         else if (component instanceof BodyTube) {
             BodyTube bt = (BodyTube) component;
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(bt.getMaterial()));
             grid.addCell(createOuterInnerDiaCell(bt));
             grid.addCell(createLengthCell(component.getLength()));
@@ -203,7 +230,7 @@ public class PartsDetailVisitorStrategy {
         else if (component instanceof ExternalComponent) {
             ExternalComponent ext = (ExternalComponent) component;
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
 
             grid.addCell(createMaterialCell(ext.getMaterial()));
             grid.addCell(ITextHelper.createCell());
@@ -216,7 +243,7 @@ public class PartsDetailVisitorStrategy {
         else if (component instanceof InnerTube) {
             InnerTube it = (InnerTube) component;
             grid.addCell(iconToImage(component));
-            final PdfPCell pCell = createNameCell(component.getName(), true);
+            final PdfPCell pCell = createNameCell(component.getName(), true, component.getPresetComponent());
             grid.addCell(pCell);
             grid.addCell(createMaterialCell(it.getMaterial()));
             grid.addCell(createOuterInnerDiaCell(it));
@@ -229,7 +256,7 @@ public class PartsDetailVisitorStrategy {
         else if (component instanceof RadiusRingComponent) {
             RadiusRingComponent rrc = (RadiusRingComponent) component;
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(rrc.getMaterial()));
             if (component instanceof Bulkhead) {
                 grid.addCell(createDiaCell(rrc.getOuterRadius()*2));
@@ -245,7 +272,7 @@ public class PartsDetailVisitorStrategy {
         else if (component instanceof RingComponent) {
             RingComponent ring = (RingComponent) component;
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(ring.getMaterial()));
             grid.addCell(createOuterInnerDiaCell(ring));
             grid.addCell(createLengthCell(component.getLength()));
@@ -260,7 +287,7 @@ public class PartsDetailVisitorStrategy {
             cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
             cell.setPaddingBottom(12f);
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(ring.getMaterial()));
             grid.addCell(cell);
             grid.addCell(createLengthCell(ring.getCordLength()));
@@ -272,14 +299,19 @@ public class PartsDetailVisitorStrategy {
             cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
             cell.setPaddingBottom(12f);
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(chute.getMaterial()));
+//            if (chute.hasSpillHole()) {
+//                grid.addCell(createOuterInnerDiaCell(chute.getDiameter()/2, chute.getSpillHoleDiameter()/2));
+//        }
+//        else {
             grid.addCell(createDiaCell(chute.getDiameter()));
+//        }
             grid.addCell(createLengthCell(component.getLength()));
             grid.addCell(createMassCell(component.getMass()));
 
             grid.addCell(iconToImage(null));
-            grid.addCell(createNameCell(SHROUD_LINES, true));
+            grid.addCell(createNameCell(SHROUD_LINES, true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(chute.getLineMaterial()));
             grid.addCell(createLinesCell(chute.getLineCount()));
             grid.addCell(createLengthCell(chute.getLineLength()));
@@ -291,7 +323,7 @@ public class PartsDetailVisitorStrategy {
             cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
             cell.setPaddingBottom(12f);
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(ring.getMaterial()));
             grid.addCell(createStrip(ring));
             grid.addCell(createLengthCell(component.getLength()));
@@ -303,7 +335,7 @@ public class PartsDetailVisitorStrategy {
             cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
             cell.setPaddingBottom(12f);
             grid.addCell(iconToImage(component));
-            grid.addCell(createNameCell(component.getName(), true));
+            grid.addCell(createNameCell(component.getName(), true, component.getPresetComponent()));
             grid.addCell(createMaterialCell(device.getMaterial()));
             grid.addCell(cell);
             grid.addCell(createLengthCell(component.getLength()));
@@ -315,7 +347,7 @@ public class PartsDetailVisitorStrategy {
             cell.setPaddingBottom(12f);
 
             grid.addCell(iconToImage(component));
-            final PdfPCell nameCell = createNameCell(component.getName(), true);
+            final PdfPCell nameCell = createNameCell(component.getName(), true, component.getPresetComponent());
             nameCell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
             nameCell.setPaddingBottom(12f);
             grid.addCell(nameCell);
@@ -355,17 +387,17 @@ public class PartsDetailVisitorStrategy {
         result.setVerticalAlignment(Element.ALIGN_TOP);
         result.setBorder(Rectangle.BOTTOM);
         Chunk c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append(DIAMETER);
         p.add(c);
 
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
+        c.setFont(PrintUtilities.SMALL);
         c.append(OUTER);
         p.add(c);
 
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append(" " + toLength(diameter));
         p.add(c);
         result.addElement(p);
@@ -385,12 +417,12 @@ public class PartsDetailVisitorStrategy {
         result.setVerticalAlignment(Element.ALIGN_TOP);
         result.setBorder(Rectangle.BOTTOM);
         Chunk c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append(LENGTH);
         p.add(c);
 
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append(" " + toLength(component.getStripLength()));
         p.add(c);
         result.addElement(p);
@@ -398,12 +430,12 @@ public class PartsDetailVisitorStrategy {
         Phrase pw = new Phrase();
         pw.setLeading(14f);
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append(WIDTH);
         pw.add(c);
 
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append("  " + toLength(component.getStripWidth()));
         pw.add(c);
         result.addElement(pw);
@@ -415,29 +447,56 @@ public class PartsDetailVisitorStrategy {
      * Create a PDF cell that documents both an outer and an inner diameter of a component.
      *
      * @param component  a component that is a Coaxial
+     *
      * @return  the PDF cell that has the outer and inner diameters documented
      */
     private PdfPCell createOuterInnerDiaCell (final Coaxial component) {
+        return createOuterInnerDiaCell(component, INNER);
+    }
+
+    /**
+     * Create a PDF cell that documents both an outer and an inner diameter of a component.
+     *
+     * @param component  a component that is a Coaxial
+     * @param innerLabel the label to use for the inner label subscript
+     *
+     * @return  the PDF cell that has the outer and inner diameters documented
+     */
+    private PdfPCell createOuterInnerDiaCell (final Coaxial component, final String innerLabel) {
+        return createOuterInnerDiaCell(component.getOuterRadius(), component.getInnerRadius(), innerLabel);
+    }
+
+    /**
+     * Create a PDF cell that documents both an outer and an inner diameter of a component.
+     *
+     * @param outerRadius the outer radius
+     * @param innerRadius the inner radius
+     * @param innerLabel the label to use for the inner label subscript
+     *
+     * @return  the PDF cell that has the outer and inner diameters documented
+     */
+    private PdfPCell createOuterInnerDiaCell (final double outerRadius, final double innerRadius, final String innerLabel) {
+
         PdfPCell result = new PdfPCell();
         Phrase p = new Phrase();
         p.setLeading(12f);
         result.setVerticalAlignment(Element.ALIGN_TOP);
         result.setBorder(Rectangle.BOTTOM);
         Chunk c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append(DIAMETER);
         p.add(c);
 
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
+        c.setFont(PrintUtilities.SMALL);
         c.append(OUTER);
         p.add(c);
 
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-        c.append(" " + toLength(component.getOuterRadius() * 2));
+        c.setFont(PrintUtilities.NORMAL);
+        c.append(" " + toLength(outerRadius * 2));
         p.add(c);
-        createInnerDiaCell(component, result);
+        createInnerDiaCell(innerRadius, result, innerLabel);
         result.addElement(p);
         return result;
     }
@@ -445,25 +504,26 @@ public class PartsDetailVisitorStrategy {
     /**
      * Add inner diameter data to a cell.
      *
-     * @param component  a component that is a Coaxial
+     * @param innerRadius the inner radius
      * @param cell       the PDF cell to add the inner diameter data to
+     * @param innerLabel the label to use for the inner label subscript
      */
-    private void createInnerDiaCell (final Coaxial component, PdfPCell cell) {
+    private void createInnerDiaCell (final double innerRadius, PdfPCell cell, final String innerLabel) {
         Phrase p = new Phrase();
         p.setLeading(14f);
         Chunk c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append(DIAMETER);
         p.add(c);
 
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
-        c.append(INNER);
+        c.setFont(PrintUtilities.SMALL);
+        c.append(innerLabel);
         p.add(c);
 
         c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
-        c.append("  " + toLength(component.getInnerRadius() * 2));
+        c.setFont(PrintUtilities.NORMAL);
+        c.append("  " + toLength(innerRadius * 2));
         p.add(c);
         cell.addElement(p);
     }
@@ -478,8 +538,6 @@ public class PartsDetailVisitorStrategy {
         Image img = null;
         java.awt.Image awtImage = new PrintableFinSet(theFinSet).createImage();
 
-        Collection<Coordinate> x = theFinSet.getComponentBounds();
-
         try {
             img = Image.getInstance(writer, awtImage, 0.25f);
         }
@@ -544,18 +602,49 @@ public class PartsDetailVisitorStrategy {
      * @return a PdfPCell that is formatted with the string <code>v</code>
      */
     protected PdfPCell createNameCell (String v, boolean withIndent) {
+        return createNameCell(v, withIndent, null);
+    }
+
+    /**
+     * Create a cell formatted for a name (or any string for that matter).
+     *
+     * @param v  the string to format into a PDF cell
+     * @param withIndent  if true, then an indention is made scaled to the level of the part in the parent hierarchy
+     * @param preset  the component's preset, if it has one
+     *
+     * @return a PdfPCell that is formatted with the string <code>v</code>
+     */
+    protected PdfPCell createNameCell (String v, boolean withIndent, ComponentPreset preset) {
         PdfPCell result = new PdfPCell();
+        result.setColspan(2);
         result.setBorder(Rectangle.BOTTOM);
+        Paragraph para = new Paragraph();
+        para.setLeading(12f, 0);
         Chunk c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
+        Chunk tab1 =
+          new Chunk(new VerticalPositionMark(), (level - 2) * 10, true);
+
         if (withIndent) {
-            for (int x = 0; x < (level - 2) * 10; x++) {
-                c.append(" ");
-            }
+            para.add(new Chunk(tab1));
         }
         c.append(v);
-        result.setColspan(2);
-        result.addElement(c);
+        para.add(c);
+
+        //Add the preset's manufacturer and part no in a subscript font.
+        if (preset != null) {
+            para.add(Chunk.NEWLINE);
+            c = new Chunk();
+            if (withIndent) {
+                para.add(new Chunk(tab1));
+            }
+            c.setFont(PrintUtilities.SMALL);
+            StringBuffer sb = new StringBuffer();
+            sb.append(preset.getManufacturer()).append(" ").append(preset.getPartNo());
+            c.append(sb.toString());
+            para.add(c);
+        }
+        result.addElement(para);
         return result;
     }
 
@@ -571,11 +660,11 @@ public class PartsDetailVisitorStrategy {
         cell.setLeading(13f, 0);
 
         Chunk c = new Chunk();
-        c.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.NORMAL_FONT_SIZE));
+        c.setFont(PrintUtilities.NORMAL);
         c.append(toMaterialName(material));
         cell.addElement(c);
         Chunk density = new Chunk();
-        density.setFont(new Font(Font.FontFamily.HELVETICA, PrintUtilities.SMALL_FONT_SIZE));
+        density.setFont(PrintUtilities.SMALL);
         density.append(toMaterialDensity(material));
         cell.addElement(density);
         return cell;
@@ -624,7 +713,7 @@ public class PartsDetailVisitorStrategy {
      */
     protected String toLength (double length) {
         final Unit defaultUnit = UnitGroup.UNITS_LENGTH.getDefaultUnit();
-        return NumberFormat.getNumberInstance().format(defaultUnit.toUnit(length)) + defaultUnit.toString();
+        return defaultUnit.toStringUnit(length);
     }
 
     /**
@@ -636,7 +725,7 @@ public class PartsDetailVisitorStrategy {
      */
     protected String toMass (double mass) {
         final Unit defaultUnit = UnitGroup.UNITS_MASS.getDefaultUnit();
-        return NumberFormat.getNumberInstance().format(defaultUnit.toUnit(mass)) + defaultUnit.toString();
+        return defaultUnit.toStringUnit(mass);
     }
 
     /**
index 1988ab8a31a67ca409b5501c8f454426170971e1..b6f1ee04265a7dc63492f79175edc21a6a100e2e 100644 (file)
@@ -3,10 +3,10 @@ package net.sf.openrocket.gui.print.visitor;
 import com.itextpdf.text.Document;
 import com.itextpdf.text.DocumentException;
 import com.itextpdf.text.Rectangle;
-import com.itextpdf.text.pdf.PdfContentByte;
 import com.itextpdf.text.pdf.PdfWriter;
-import net.sf.openrocket.gui.print.AbstractPrintableTransition;
+import net.sf.openrocket.gui.print.AbstractPrintable;
 import net.sf.openrocket.gui.print.ITextHelper;
+import net.sf.openrocket.gui.print.PrintUnit;
 import net.sf.openrocket.gui.print.PrintableNoseCone;
 import net.sf.openrocket.gui.print.PrintableTransition;
 import net.sf.openrocket.logging.LogHelper;
@@ -15,7 +15,6 @@ import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.Transition;
 import net.sf.openrocket.startup.Application;
 
-import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.util.List;
 import java.util.Set;
@@ -45,6 +44,11 @@ public class TransitionStrategy {
      */
     protected Set<Integer> stages;
 
+    /**
+     * Strategy for fitting multiple components onto a page.
+     */
+    protected PageFitPrintStrategy pageFitPrint;
+
     /**
      * Constructor.
      *
@@ -52,10 +56,11 @@ public class TransitionStrategy {
      * @param theWriter        The direct iText writer
      * @param theStagesToVisit The stages to be visited by this strategy
      */
-    public TransitionStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit) {
+    public TransitionStrategy(Document doc, PdfWriter theWriter, Set<Integer> theStagesToVisit, PageFitPrintStrategy pageFit) {
         document = doc;
         writer = theWriter;
         stages = theStagesToVisit;
+        pageFitPrint = pageFit;
     }
 
     /**
@@ -63,10 +68,12 @@ public class TransitionStrategy {
      *
      * @param root      the root component; all children will be visited recursively
      * @param noseCones nose cones are a special form of a transition; if true, then print nose cones
+     *
+     * @return true if a transition/nosecone was rendered
      */
-    public void writeToDocument(final RocketComponent root, boolean noseCones) {
+    public boolean writeToDocument(final RocketComponent root, boolean noseCones) {
         List<RocketComponent> rc = root.getChildren();
-        goDeep(rc, noseCones);
+        return goDeep(rc, noseCones);
     }
 
 
@@ -75,47 +82,62 @@ public class TransitionStrategy {
      *
      * @param theRc     an array of rocket components; all children will be visited recursively
      * @param noseCones nose cones are a special form of a transition; if true, then print nose cones
+     *
+     * @return true if a transition/nosecone was rendered
      */
-    protected void goDeep(final List<RocketComponent> theRc, boolean noseCones) {
+    protected boolean goDeep(final List<RocketComponent> theRc, boolean noseCones) {
         for (RocketComponent rocketComponent : theRc) {
             if (rocketComponent instanceof NoseCone) {
                 if (noseCones) {
-                    render((Transition) rocketComponent);
+                    return render((Transition) rocketComponent);
                 }
-            } else if (rocketComponent instanceof Transition && !noseCones) {
-                render((Transition) rocketComponent);
-            } else if (rocketComponent.getChildCount() > 0) {
-                goDeep(rocketComponent.getChildren(), noseCones);
+            }
+            else if (rocketComponent instanceof Transition && !noseCones) {
+                return render((Transition) rocketComponent);
+            }
+            else if (rocketComponent.getChildCount() > 0) {
+                return goDeep(rocketComponent.getChildren(), noseCones);
             }
         }
+        return false;
     }
 
     /**
      * The core behavior of this visitor.
      *
-     * @param component the object to extract info about; a graphical image of the transition shape is drawn to the document
+     * @param component the object to extract info about; a graphical image of the transition shape is drawn to the
+     *                  document
+     *
+     * @return true, always
      */
-    private void render(final Transition component) {
+    private boolean render(final Transition component) {
         try {
-            AbstractPrintableTransition pfs;
+            AbstractPrintable pfs;
             if (component instanceof NoseCone) {
-                pfs = new PrintableNoseCone(component);
-            } else {
+                pfs = new PrintableNoseCone((NoseCone) component);
+            }
+            else {
                 pfs = new PrintableTransition(component);
             }
 
             java.awt.Dimension size = pfs.getSize();
             final Dimension pageSize = getPageSize();
             if (fitsOnOnePage(pageSize, size.getWidth(), size.getHeight())) {
-                printOnOnePage(pfs);
-            } else {
+                pageFitPrint.addComponent(pfs);
+            }
+            else {
+                int off = (int) (PrintUnit.POINTS_PER_INCH * 0.3f);
+                pfs.setPrintOffset(off, off);
                 BufferedImage image = (BufferedImage) pfs.createImage();
                 ITextHelper.renderImageAcrossPages(new Rectangle(pageSize.getWidth(), pageSize.getHeight()),
                         document, writer, image);
+                document.newPage();
             }
-        } catch (DocumentException e) {
+        }
+        catch (DocumentException e) {
             log.error("Could not render the transition.", e);
         }
+        return true;
     }
 
     /**
@@ -124,6 +146,7 @@ public class TransitionStrategy {
      * @param pageSize the page size
      * @param wImage   the width of the thing to be printed
      * @param hImage   the height of the thing to be printed
+     *
      * @return true if the thing to be printed will fit on a single page
      */
     private boolean fitsOnOnePage(Dimension pageSize, double wImage, double hImage) {
@@ -136,20 +159,6 @@ public class TransitionStrategy {
         return wRatio <= 1.0d && hRatio <= 1.0d;
     }
 
-    /**
-     * Print the transition.
-     *
-     * @param theTransition the printable transition
-     */
-    private void printOnOnePage(final AbstractPrintableTransition theTransition) {
-        Dimension d = getPageSize();
-        PdfContentByte cb = writer.getDirectContent();
-        Graphics2D g2 = cb.createGraphics(d.width, d.height);
-        theTransition.print(g2);
-        g2.dispose();
-        document.newPage();
-    }
-
     /**
      * Get the dimensions of the paper page.
      *
index 0f08be213a67770443bf123493bbfb368af84114..cd5b9490ea6c31d49a3088f65085fc59f1578a99 100644 (file)
@@ -235,8 +235,8 @@ public class FinPointFigure extends AbstractScaleFigure {
                double y0 = p.y / EXTRA_SCALE;
                double delta = BOX_SIZE / scale;
                
-               System.out.println("Point: " + x0 + "," + y0);
-               System.out.println("delta: " + (BOX_SIZE / scale));
+               //System.out.println("Point: " + x0 + "," + y0);
+               //System.out.println("delta: " + (BOX_SIZE / scale));
                
                Coordinate[] points = finset.getFinPoints();
                for (int i = 1; i < points.length; i++) {
@@ -249,7 +249,7 @@ public class FinPointFigure extends AbstractScaleFigure {
                        
                        double u = Math.abs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1)) /
                                                MathUtil.hypot(x2 - x1, y2 - y1);
-                       System.out.println("Distance of segment " + i + " is " + u);
+                       //System.out.println("Distance of segment " + i + " is " + u);
                        if (u < delta)
                                return i;
                }
index 854eb17a1b4ad1555b0d01345ff1f782bb3ef3ef..bd63d8ba1c01500178f0481fb275752d1131df6e 100644 (file)
@@ -77,7 +77,7 @@ public class RocketFigure extends AbstractScaleFigure {
        private double minX = 0, maxX = 0, maxR = 0;
        // Figure width and height in SI-units and pixels
        private double figureWidth = 0, figureHeight = 0;
-       private int figureWidthPx = 0, figureHeightPx = 0;
+       protected int figureWidthPx = 0, figureHeightPx = 0;
        
        private AffineTransform g2transformation = null;
        
index cf458724344b770483d96a12decd627fff37285e..2cef70809bbab6a969e2a4aee1e17f269514fcfa 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.gui.scalefigure;
 
 
+import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.Font;
 import java.awt.Point;
@@ -18,6 +19,7 @@ import java.util.concurrent.ThreadFactory;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
+import javax.swing.ButtonGroup;
 import javax.swing.JComboBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -43,6 +45,7 @@ import net.sf.openrocket.gui.components.BasicSlider;
 import net.sf.openrocket.gui.components.StageSelector;
 import net.sf.openrocket.gui.components.UnitSelector;
 import net.sf.openrocket.gui.configdialog.ComponentConfigDialog;
+import net.sf.openrocket.gui.figure3d.RocketFigure3d;
 import net.sf.openrocket.gui.figureelements.CGCaret;
 import net.sf.openrocket.gui.figureelements.CPCaret;
 import net.sf.openrocket.gui.figureelements.Caret;
@@ -59,6 +62,8 @@ import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.rocketcomponent.RocketComponent;
 import net.sf.openrocket.rocketcomponent.SymmetricComponent;
 import net.sf.openrocket.simulation.FlightData;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.simulation.customexpression.CustomExpressionSimulationListener;
 import net.sf.openrocket.simulation.listeners.SimulationListener;
 import net.sf.openrocket.simulation.listeners.system.ApogeeEndListener;
 import net.sf.openrocket.simulation.listeners.system.InterruptListener;
@@ -74,45 +79,57 @@ import net.sf.openrocket.util.StateChangeListener;
  * A JPanel that contains a RocketFigure and buttons to manipulate the figure. 
  * 
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ * @author Bill Kuker <bkuker@billkuker.com>
  */
 public class RocketPanel extends JPanel implements TreeSelectionListener, ChangeSource {
-       
+       private static final long serialVersionUID = 1L;
+
        private static final Translator trans = Application.getTranslator();
+
+       private boolean is3d;
        private final RocketFigure figure;
+       private final RocketFigure3d figure3d;
+
+
        private final ScaleScrollPane scrollPane;
-       
+
+       private final JPanel figureHolder;
+
        private JLabel infoMessage;
-       
+
        private TreeSelectionModel selectionModel = null;
-       
+
+       private BasicSlider rotationSlider;
+       ScaleSelector scaleSelector;
+
 
        /* Calculation of CP and CG */
        private AerodynamicCalculator aerodynamicCalculator;
        private MassCalculator massCalculator;
-       
+
 
        private final OpenRocketDocument document;
        private final Configuration configuration;
-       
+
        private Caret extraCP = null;
        private Caret extraCG = null;
        private RocketInfo extraText = null;
-       
+
 
        private double cpAOA = Double.NaN;
        private double cpTheta = Double.NaN;
        private double cpMach = Double.NaN;
        private double cpRoll = Double.NaN;
-       
+
        // The functional ID of the rocket that was simulated
        private int flightDataFunctionalID = -1;
        private String flightDataMotorID = null;
-       
+
 
        private SimulationWorker backgroundSimulationWorker = null;
-       
+
        private List<EventListener> listeners = new ArrayList<EventListener>();
-       
+
 
        /**
         * The executor service used for running the background simulations.
@@ -123,32 +140,37 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
        static {
                backgroundSimulationExecutor = Executors.newFixedThreadPool(SwingPreferences.getMaxThreadCount(),
                                new ThreadFactory() {
-                                       private ThreadFactory factory = Executors.defaultThreadFactory();
-                                       
-                                       @Override
-                                       public Thread newThread(Runnable r) {
-                                               Thread t = factory.newThread(r);
-                                               t.setDaemon(true);
-                                               t.setPriority(Thread.MIN_PRIORITY);
-                                               return t;
-                                       }
-                               });
+                       private ThreadFactory factory = Executors.defaultThreadFactory();
+
+                       @Override
+                       public Thread newThread(Runnable r) {
+                               Thread t = factory.newThread(r);
+                               t.setDaemon(true);
+                               t.setPriority(Thread.MIN_PRIORITY);
+                               return t;
+                       }
+               });
        }
-       
-       
+
+
        public RocketPanel(OpenRocketDocument document) {
-               
+
                this.document = document;
                configuration = document.getDefaultConfiguration();
-               
+
                // TODO: FUTURE: calculator selection
                aerodynamicCalculator = new BarrowmanCalculator();
                massCalculator = new BasicMassCalculator();
-               
+
                // Create figure and custom scroll pane
                figure = new RocketFigure(configuration);
-               
+               figure3d = new RocketFigure3d(configuration);
+
+               figureHolder = new JPanel(new BorderLayout());
+
                scrollPane = new ScaleScrollPane(figure) {
+                       private static final long serialVersionUID = 1L;
+
                        @Override
                        public void mouseClicked(MouseEvent event) {
                                handleMouseClick(event);
@@ -156,31 +178,77 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                };
                scrollPane.getViewport().setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
                scrollPane.setFitting(true);
-               
+
                createPanel();
-               
+
+               is3d = true;
+               go2D();
+
                configuration.addChangeListener(new StateChangeListener() {
                        @Override
                        public void stateChanged(EventObject e) {
                                // System.out.println("Configuration changed, calling updateFigure");
                                updateExtras();
-                               figure.updateFigure();
+                               updateFigures();
+                       }
+               });
+
+               figure3d.addComponentSelectionListener(new RocketFigure3d.ComponentSelectionListener() {
+                       @Override
+                       public void componentClicked(RocketComponent clicked[], MouseEvent event) {
+                               handleComponentClick(clicked, event);
                        }
                });
        }
-       
-       
+
+       private void updateFigures() {
+               if (!is3d)
+                       figure.updateFigure();
+               else
+                       figure3d.updateFigure();
+       }
+
+       private void go3D() {
+               if (is3d)
+                       return;
+               is3d = true;
+               figureHolder.remove(scrollPane);
+               figureHolder.add(figure3d, BorderLayout.CENTER);
+               rotationSlider.setEnabled(false);
+               scaleSelector.setEnabled(false);
+
+               revalidate();
+               figureHolder.revalidate();
+
+               figure3d.repaint();
+       }
+
+       private void go2D() {
+               if (!is3d)
+                       return;
+               is3d = false;
+               figureHolder.remove(figure3d);
+               figureHolder.add(scrollPane, BorderLayout.CENTER);
+               rotationSlider.setEnabled(true);
+               scaleSelector.setEnabled(true);
+               revalidate();
+               figureHolder.revalidate();
+               figure.repaint();
+       }
+
        /**
         * Creates the layout and components of the panel.
         */
        private void createPanel() {
                setLayout(new MigLayout("", "[shrink][grow]", "[shrink][shrink][grow][shrink]"));
-               
+
                setPreferredSize(new Dimension(800, 300));
-               
+
 
                //// Create toolbar
-               
+
+               ButtonGroup bg = new ButtonGroup();
+
                // Side/back buttons
                FigureTypeAction action = new FigureTypeAction(RocketFigure.TYPE_SIDE);
                //// Side view
@@ -188,27 +256,48 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                //// Side view
                action.putValue(Action.SHORT_DESCRIPTION, trans.get("RocketPanel.FigTypeAct.ttip.Sideview"));
                JToggleButton toggle = new JToggleButton(action);
+               bg.add(toggle);
                add(toggle, "spanx, split");
-               
+
                action = new FigureTypeAction(RocketFigure.TYPE_BACK);
                //// Back view
                action.putValue(Action.NAME, trans.get("RocketPanel.FigTypeAct.Backview"));
                //// Back view
                action.putValue(Action.SHORT_DESCRIPTION, trans.get("RocketPanel.FigTypeAct.ttip.Backview"));
                toggle = new JToggleButton(action);
+               bg.add(toggle);
                add(toggle, "gap rel");
-               
+
+               //// 3d Toggle
+               final JToggleButton toggle3d = new JToggleButton(new AbstractAction("3D") {
+                       private static final long serialVersionUID = 1L;
+                       {
+                               putValue(Action.NAME, "3D");//TODO
+                               putValue(Action.SHORT_DESCRIPTION, "3D"); //TODO
+                       }
+                       @Override
+                       public void actionPerformed(ActionEvent e) {
+                               if ( ((JToggleButton)e.getSource()).isSelected() ){
+                                       go3D();
+                               } else {
+                                       go2D();
+                               }
+                       }
+               });
+               bg.add(toggle3d);
+               toggle3d.setEnabled(RocketFigure3d.is3dEnabled());
+               add(toggle3d, "gap rel");
 
                // Zoom level selector
-               ScaleSelector scaleSelector = new ScaleSelector(scrollPane);
+               scaleSelector = new ScaleSelector(scrollPane);
                add(scaleSelector);
-               
+
 
 
                // Stage selector
                StageSelector stageSelector = new StageSelector(configuration);
                add(stageSelector, "");
-               
+
 
 
                // Motor configuration selector
@@ -217,55 +306,55 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                label.setHorizontalAlignment(JLabel.RIGHT);
                add(label, "growx, right");
                add(new JComboBox(new MotorConfigurationModel(configuration)), "wrap");
-               
+
 
 
 
 
                // Create slider and scroll pane
-               
+
                DoubleModel theta = new DoubleModel(figure, "Rotation",
                                UnitGroup.UNITS_ANGLE, 0, 2 * Math.PI);
                UnitSelector us = new UnitSelector(theta, true);
                us.setHorizontalAlignment(JLabel.CENTER);
                add(us, "alignx 50%, growx");
-               
+
                // Add the rocket figure
-               add(scrollPane, "grow, spany 2, wmin 300lp, hmin 100lp, wrap");
-               
+               add(figureHolder, "grow, spany 2, wmin 300lp, hmin 100lp, wrap");
+
 
                // Add rotation slider
                // Minimum size to fit "360deg"
                JLabel l = new JLabel("360" + Chars.DEGREE);
                Dimension d = l.getPreferredSize();
-               
-               add(new BasicSlider(theta.getSliderModel(0, 2 * Math.PI), JSlider.VERTICAL, true),
+
+               add(rotationSlider = new BasicSlider(theta.getSliderModel(0, 2 * Math.PI), JSlider.VERTICAL, true),
                                "ax 50%, wrap, width " + (d.width + 6) + "px:null:null, growy");
-               
+
 
                //// <html>Click to select &nbsp;&nbsp; Shift+click to select other &nbsp;&nbsp; Double-click to edit &nbsp;&nbsp; Click+drag to move
                infoMessage = new JLabel(trans.get("RocketPanel.lbl.infoMessage"));
                infoMessage.setFont(new Font("Sans Serif", Font.PLAIN, 9));
                add(infoMessage, "skip, span, gapleft 25, wrap");
-               
+
 
                addExtras();
        }
-       
-       
+
+
 
        public RocketFigure getFigure() {
                return figure;
        }
-       
+
        public AerodynamicCalculator getAerodynamicCalculator() {
                return aerodynamicCalculator;
        }
-       
+
        public Configuration getConfiguration() {
                return configuration;
        }
-       
+
        /**
         * Get the center of pressure figure element.
         * 
@@ -274,7 +363,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
        public Caret getExtraCP() {
                return extraCP;
        }
-       
+
        /**
         * Get the center of gravity figure element.
         * 
@@ -283,7 +372,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
        public Caret getExtraCG() {
                return extraCG;
        }
-       
+
        /**
         * Get the extra text figure element.
         * 
@@ -292,7 +381,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
        public RocketInfo getExtraText() {
                return extraText;
        }
-       
+
        public void setSelectionModel(TreeSelectionModel m) {
                if (selectionModel != null) {
                        selectionModel.removeTreeSelectionListener(this);
@@ -301,8 +390,8 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                selectionModel.addTreeSelectionListener(this);
                valueChanged((TreeSelectionEvent) null); // updates FigureParameters
        }
-       
-       
+
+
 
        /**
         * Return the angle of attack used in CP calculation.  NaN signifies the default value
@@ -312,7 +401,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
        public double getCPAOA() {
                return cpAOA;
        }
-       
+
        /**
         * Set the angle of attack to be used in CP calculation.  A value of NaN signifies that
         * the default AOA (zero) should be used.
@@ -324,14 +413,14 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        return;
                cpAOA = aoa;
                updateExtras();
-               figure.updateFigure();
+               updateFigures();
                fireChangeEvent();
        }
-       
+
        public double getCPTheta() {
                return cpTheta;
        }
-       
+
        public void setCPTheta(double theta) {
                if (MathUtil.equals(theta, cpTheta) ||
                                (Double.isNaN(theta) && Double.isNaN(cpTheta)))
@@ -340,50 +429,50 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                if (!Double.isNaN(theta))
                        figure.setRotation(theta);
                updateExtras();
-               figure.updateFigure();
+               updateFigures();
                fireChangeEvent();
        }
-       
+
        public double getCPMach() {
                return cpMach;
        }
-       
+
        public void setCPMach(double mach) {
                if (MathUtil.equals(mach, cpMach) ||
                                (Double.isNaN(mach) && Double.isNaN(cpMach)))
                        return;
                cpMach = mach;
                updateExtras();
-               figure.updateFigure();
+               updateFigures();
                fireChangeEvent();
        }
-       
+
        public double getCPRoll() {
                return cpRoll;
        }
-       
+
        public void setCPRoll(double roll) {
                if (MathUtil.equals(roll, cpRoll) ||
                                (Double.isNaN(roll) && Double.isNaN(cpRoll)))
                        return;
                cpRoll = roll;
                updateExtras();
-               figure.updateFigure();
+               updateFigures();
                fireChangeEvent();
        }
-       
-       
+
+
 
        @Override
        public void addChangeListener(EventListener listener) {
                listeners.add(0, listener);
        }
-       
+
        @Override
        public void removeChangeListener(EventListener listener) {
                listeners.remove(listener);
        }
-       
+
        protected void fireChangeEvent() {
                EventObject e = new EventObject(this);
                for (EventListener l : listeners) {
@@ -392,8 +481,8 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        }
                }
        }
-       
-       
+
+
 
 
        /**
@@ -406,7 +495,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
         * the next component. Otherwise select the first component in the list. 
         */
        public static final int CYCLE_SELECTION_MODIFIER = InputEvent.SHIFT_DOWN_MASK;
-       
+
        private void handleMouseClick(MouseEvent event) {
                if (event.getButton() != MouseEvent.BUTTON1)
                        return;
@@ -414,13 +503,18 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                Point p1 = scrollPane.getViewport().getViewPosition();
                int x = p0.x + p1.x;
                int y = p0.y + p1.y;
-               
+
                RocketComponent[] clicked = figure.getComponentsByPoint(x, y);
-               
+
+               handleComponentClick(clicked, event);
+       }
+
+       private void handleComponentClick(RocketComponent[] clicked, MouseEvent event){
+
                // If no component is clicked, do nothing
                if (clicked.length == 0)
                        return;
-               
+
                // Check whether the currently selected component is in the clicked components.
                TreePath path = selectionModel.getSelectionPath();
                if (path != null) {
@@ -437,7 +531,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                                }
                        }
                }
-               
+
                // Currently selected component not clicked
                if (path == null) {
                        if (event.isShiftDown() && event.getClickCount() == 1 && clicked.length > 1) {
@@ -446,18 +540,18 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                                path = ComponentTreeModel.makeTreePath(clicked[0]);
                        }
                }
-               
+
                // Set selection and check for double-click
                selectionModel.setSelectionPath(path);
                if (event.getClickCount() == 2) {
                        RocketComponent component = (RocketComponent) path.getLastPathComponent();
-                       
+
                        ComponentConfigDialog.showDialog(SwingUtilities.getWindowAncestor(this),
                                        document, component);
                }
        }
-       
-       
+
+
 
 
        /**
@@ -465,15 +559,15 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
         * the CP and CG carets.
         */
        private WarningSet warnings = new WarningSet();
-       
+
        private void updateExtras() {
                Coordinate cp, cg;
                double cpx, cgx;
-               
+
                // TODO: MEDIUM: User-definable conditions
                FlightConditions conditions = new FlightConditions(configuration);
                warnings.clear();
-               
+
                if (!Double.isNaN(cpMach)) {
                        conditions.setMach(cpMach);
                        extraText.setMach(cpMach);
@@ -481,20 +575,20 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        conditions.setMach(Application.getPreferences().getDefaultMach());
                        extraText.setMach(Application.getPreferences().getDefaultMach());
                }
-               
+
                if (!Double.isNaN(cpAOA)) {
                        conditions.setAOA(cpAOA);
                } else {
                        conditions.setAOA(0);
                }
                extraText.setAOA(cpAOA);
-               
+
                if (!Double.isNaN(cpRoll)) {
                        conditions.setRollRate(cpRoll);
                } else {
                        conditions.setRollRate(0);
                }
-               
+
                if (!Double.isNaN(cpTheta)) {
                        conditions.setTheta(cpTheta);
                        cp = aerodynamicCalculator.getCP(configuration, conditions, warnings);
@@ -502,21 +596,24 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        cp = aerodynamicCalculator.getWorstCP(configuration, conditions, warnings);
                }
                extraText.setTheta(cpTheta);
-               
+
 
                cg = massCalculator.getCG(configuration, MassCalcType.LAUNCH_MASS);
                //              System.out.println("CG computed as "+cg+ " CP as "+cp);
-               
+
                if (cp.weight > 0.000001)
                        cpx = cp.x;
                else
                        cpx = Double.NaN;
-               
+
                if (cg.weight > 0.000001)
                        cgx = cg.x;
                else
                        cgx = Double.NaN;
-               
+
+               figure3d.setCG(cg);
+               figure3d.setCP(cp);
+
                // Length bound is assumed to be tight
                double length = 0, diameter = 0;
                Collection<Coordinate> bounds = configuration.getBounds();
@@ -530,7 +627,7 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        }
                        length = maxX - minX;
                }
-               
+
                for (RocketComponent c : configuration) {
                        if (c instanceof SymmetricComponent) {
                                double d1 = ((SymmetricComponent) c).getForeRadius() * 2;
@@ -538,31 +635,31 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                                diameter = MathUtil.max(diameter, d1, d2);
                        }
                }
-               
+
                extraText.setCG(cgx);
                extraText.setCP(cpx);
                extraText.setLength(length);
                extraText.setDiameter(diameter);
                extraText.setMass(cg.weight);
                extraText.setWarnings(warnings);
-               
+
 
                if (figure.getType() == RocketFigure.TYPE_SIDE && length > 0) {
-                       
+
                        // TODO: LOW: Y-coordinate and rotation
                        extraCP.setPosition(cpx * RocketFigure.EXTRA_SCALE, 0);
                        extraCG.setPosition(cgx * RocketFigure.EXTRA_SCALE, 0);
-                       
+
                } else {
-                       
+
                        extraCP.setPosition(Double.NaN, Double.NaN);
                        extraCG.setPosition(Double.NaN, Double.NaN);
-                       
+
                }
-               
+
 
                ////////  Flight simulation in background
-               
+
                // Check whether to compute or not
                if (!((SwingPreferences) Application.getPreferences()).computeFlightInBackground()) {
                        extraText.setFlightData(null);
@@ -570,38 +667,38 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        stopBackgroundSimulation();
                        return;
                }
-               
+
                // Check whether data is already up to date
                if (flightDataFunctionalID == configuration.getRocket().getFunctionalModID() &&
                                flightDataMotorID == configuration.getMotorConfigurationID()) {
                        return;
                }
-               
+
                flightDataFunctionalID = configuration.getRocket().getFunctionalModID();
                flightDataMotorID = configuration.getMotorConfigurationID();
-               
+
                // Stop previous computation (if any)
                stopBackgroundSimulation();
-               
+
                // Check that configuration has motors
                if (!configuration.hasMotors()) {
                        extraText.setFlightData(FlightData.NaN_DATA);
                        extraText.setCalculatingData(false);
                        return;
                }
-               
+
                // Start calculation process
                extraText.setCalculatingData(true);
-               
+
                Rocket duplicate = (Rocket) configuration.getRocket().copy();
                Simulation simulation = ((SwingPreferences)Application.getPreferences()).getBackgroundSimulation(duplicate);
                simulation.getOptions().setMotorConfigurationID(
                                configuration.getMotorConfigurationID());
-               
-               backgroundSimulationWorker = new BackgroundSimulationWorker(simulation);
+
+               backgroundSimulationWorker = new BackgroundSimulationWorker(document, simulation);
                backgroundSimulationExecutor.execute(backgroundSimulationWorker);
        }
-       
+
        /**
         * Cancels the current background simulation worker, if any.
         */
@@ -611,22 +708,26 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        backgroundSimulationWorker = null;
                }
        }
-       
-       
+
+
        /**
         * A SimulationWorker that simulates the rocket flight in the background and
         * sets the results to the extra text when finished.  The worker can be cancelled
         * if necessary.
         */
        private class BackgroundSimulationWorker extends SimulationWorker {
-               
-               public BackgroundSimulationWorker(Simulation sim) {
+
+               private final CustomExpressionSimulationListener exprListener;
+
+               public BackgroundSimulationWorker(OpenRocketDocument doc, Simulation sim) {
                        super(sim);
+                       List<CustomExpression> exprs = doc.getCustomExpressions();
+                       exprListener = new CustomExpressionSimulationListener(exprs);
                }
-               
+
                @Override
                protected FlightData doInBackground() {
-                       
+
                        // Pause a little while to allow faster UI reaction
                        try {
                                Thread.sleep(300);
@@ -634,59 +735,71 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        }
                        if (isCancelled() || backgroundSimulationWorker != this)
                                return null;
-                       
+
                        return super.doInBackground();
                }
-               
+
                @Override
                protected void simulationDone() {
                        // Do nothing if cancelled
                        if (isCancelled() || backgroundSimulationWorker != this)
                                return;
-                       
+
                        backgroundSimulationWorker = null;
                        extraText.setFlightData(simulation.getSimulatedData());
                        extraText.setCalculatingData(false);
                        figure.repaint();
+                       figure3d.repaint();
                }
-               
+
                @Override
                protected SimulationListener[] getExtraListeners() {
                        return new SimulationListener[] {
                                        InterruptListener.INSTANCE,
-                                       ApogeeEndListener.INSTANCE };
+                                       ApogeeEndListener.INSTANCE,
+                                       exprListener};
+
                }
-               
+
                @Override
                protected void simulationInterrupted(Throwable t) {
                        // Do nothing on cancel, set N/A data otherwise
                        if (isCancelled() || backgroundSimulationWorker != this) // Double-check
                                return;
-                       
+
                        backgroundSimulationWorker = null;
                        extraText.setFlightData(FlightData.NaN_DATA);
                        extraText.setCalculatingData(false);
                        figure.repaint();
+                       figure3d.repaint();
                }
        }
-       
-       
+
+
 
        /**
         * Adds the extra data to the figure.  Currently this includes the CP and CG carets.
         */
        private void addExtras() {
-               figure.clearRelativeExtra();
                extraCG = new CGCaret(0, 0);
                extraCP = new CPCaret(0, 0);
                extraText = new RocketInfo(configuration);
                updateExtras();
+
+               figure.clearRelativeExtra();
                figure.addRelativeExtra(extraCP);
                figure.addRelativeExtra(extraCG);
                figure.addAbsoluteExtra(extraText);
+
+
+               figure3d.clearRelativeExtra();
+               //figure3d.addRelativeExtra(extraCP);
+               //figure3d.addRelativeExtra(extraCG);
+               figure3d.addAbsoluteExtra(extraText);
+
        }
-       
-       
+
+
        /**
         * Updates the selection in the FigureParameters and repaints the figure.  
         * Ignores the event itself.
@@ -698,14 +811,16 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
                        figure.setSelection(null);
                        return;
                }
-               
+
                RocketComponent[] components = new RocketComponent[paths.length];
                for (int i = 0; i < paths.length; i++)
                        components[i] = (RocketComponent) paths[i].getLastPathComponent();
                figure.setSelection(components);
+
+               figure3d.setSelection(components);
        }
-       
-       
+
+
 
        /**
         * An <code>Action</code> that shows whether the figure type is the type
@@ -714,29 +829,31 @@ public class RocketPanel extends JPanel implements TreeSelectionListener, Change
         * @author Sampo Niskanen <sampo.niskanen@iki.fi>
         */
        private class FigureTypeAction extends AbstractAction implements StateChangeListener {
+               private static final long serialVersionUID = 1L;
                private final int type;
-               
+
                public FigureTypeAction(int type) {
                        this.type = type;
                        stateChanged(null);
                        figure.addChangeListener(this);
                }
-               
+
                @Override
                public void actionPerformed(ActionEvent e) {
                        boolean state = (Boolean) getValue(Action.SELECTED_KEY);
                        if (state == true) {
                                // This view has been selected
                                figure.setType(type);
+                               go2D();
                                updateExtras();
                        }
                        stateChanged(null);
                }
-               
+
                @Override
                public void stateChanged(EventObject e) {
-                       putValue(Action.SELECTED_KEY, figure.getType() == type);
+                       putValue(Action.SELECTED_KEY, figure.getType() == type && !is3d);
                }
        }
-       
+
 }
index 1e966a05ead4b1bb352f55130225f7b1e1fb4611..fba7aaa794d07ca30d12122481b6a81acf4275f7 100644 (file)
@@ -1,10 +1,12 @@
 package net.sf.openrocket.gui.scalefigure;
 
+import java.awt.Component;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.text.DecimalFormat;
 import java.util.Arrays;
 import java.util.EventObject;
+import java.util.Locale;
 
 import javax.swing.JButton;
 import javax.swing.JComboBox;
@@ -15,18 +17,18 @@ import net.sf.openrocket.gui.util.Icons;
 import net.sf.openrocket.util.StateChangeListener;
 
 public class ScaleSelector extends JPanel {
-
+       
        // Ready zoom settings
        private static final DecimalFormat PERCENT_FORMAT = new DecimalFormat("0.#%");
-
-       private static final double[] ZOOM_LEVELS = { 0.15, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0 }; 
+       
+       private static final double[] ZOOM_LEVELS = { 0.15, 0.25, 0.5, 0.75, 1.0, 1.5, 2.0 };
        private static final String ZOOM_FIT = "Fit";
        private static final String[] ZOOM_SETTINGS;
        static {
-               ZOOM_SETTINGS = new String[ZOOM_LEVELS.length+1];
-               for (int i=0; i<ZOOM_LEVELS.length; i++)
+               ZOOM_SETTINGS = new String[ZOOM_LEVELS.length + 1];
+               for (int i = 0; i < ZOOM_LEVELS.length; i++)
                        ZOOM_SETTINGS[i] = PERCENT_FORMAT.format(ZOOM_LEVELS[i]);
-               ZOOM_SETTINGS[ZOOM_SETTINGS.length-1] = ZOOM_FIT;
+               ZOOM_SETTINGS[ZOOM_SETTINGS.length - 1] = ZOOM_FIT;
        }
        
        
@@ -36,12 +38,13 @@ public class ScaleSelector extends JPanel {
        
        public ScaleSelector(ScaleScrollPane scroll) {
                super(new MigLayout());
-
+               
                this.scrollPane = scroll;
                
                // Zoom out button
                JButton button = new JButton(Icons.ZOOM_OUT);
                button.addActionListener(new ActionListener() {
+                       @Override
                        public void actionPerformed(ActionEvent e) {
                                double scale = scrollPane.getScaling();
                                scale = getPreviousScale(scale);
@@ -49,34 +52,35 @@ public class ScaleSelector extends JPanel {
                        }
                });
                add(button, "gap");
-
+               
                // Zoom level selector
                String[] settings = ZOOM_SETTINGS;
                if (!scrollPane.isFittingAllowed()) {
-                       settings = Arrays.copyOf(settings, settings.length-1);
+                       settings = Arrays.copyOf(settings, settings.length - 1);
                }
                
                zoomSelector = new JComboBox(settings);
                zoomSelector.setEditable(true);
                setZoomText();
                zoomSelector.addActionListener(new ActionListener() {
+                       @Override
                        public void actionPerformed(ActionEvent e) {
                                try {
-                                       String text = (String)zoomSelector.getSelectedItem();
+                                       String text = (String) zoomSelector.getSelectedItem();
                                        text = text.replaceAll("%", "").trim();
-
-                                       if (text.toLowerCase().startsWith(ZOOM_FIT.toLowerCase()) &&
+                                       
+                                       if (text.toLowerCase(Locale.getDefault()).startsWith(ZOOM_FIT.toLowerCase(Locale.getDefault())) &&
                                                        scrollPane.isFittingAllowed()) {
                                                scrollPane.setFitting(true);
                                                setZoomText();
                                                return;
                                        }
-
+                                       
                                        double n = Double.parseDouble(text);
                                        n /= 100;
                                        if (n <= 0.005)
                                                n = 0.005;
-
+                                       
                                        scrollPane.setScaling(n);
                                        setZoomText();
                                } catch (NumberFormatException ignore) {
@@ -91,65 +95,74 @@ public class ScaleSelector extends JPanel {
                                setZoomText();
                        }
                });
-               add(zoomSelector,"gap rel");
-
-
+               add(zoomSelector, "gap rel");
+               
+               
                // Zoom in button
                button = new JButton(Icons.ZOOM_IN);
                button.addActionListener(new ActionListener() {
+                       @Override
                        public void actionPerformed(ActionEvent e) {
                                double scale = scrollPane.getScaling();
                                scale = getNextScale(scale);
                                scrollPane.setScaling(scale);
                        }
                });
-               add(button,"gapleft rel");
-
-       }       
-
+               add(button, "gapleft rel");
+               
+       }
+       
+       
        
-
        private void setZoomText() {
                String text;
                double zoom = scrollPane.getScaling();
                text = PERCENT_FORMAT.format(zoom);
                if (scrollPane.isFitting()) {
-                       text = "Fit ("+text+")";
+                       text = "Fit (" + text + ")";
                }
                if (!text.equals(zoomSelector.getSelectedItem()))
                        zoomSelector.setSelectedItem(text);
        }
        
-
+       
        
        private double getPreviousScale(double scale) {
                int i;
-               for (i=0; i<ZOOM_LEVELS.length-1; i++) {
-                       if (scale > ZOOM_LEVELS[i]+0.05 && scale < ZOOM_LEVELS[i+1]+0.05)
+               for (i = 0; i < ZOOM_LEVELS.length - 1; i++) {
+                       if (scale > ZOOM_LEVELS[i] + 0.05 && scale < ZOOM_LEVELS[i + 1] + 0.05)
                                return ZOOM_LEVELS[i];
                }
-               if (scale > ZOOM_LEVELS[ZOOM_LEVELS.length/2]) {
+               if (scale > ZOOM_LEVELS[ZOOM_LEVELS.length / 2]) {
                        // scale is large, drop to next lowest full 100%
-                       scale = Math.ceil(scale-1.05);
+                       scale = Math.ceil(scale - 1.05);
                        return Math.max(scale, ZOOM_LEVELS[i]);
                }
                // scale is small
-               return scale/1.5;
+               return scale / 1.5;
        }
        
        
        private double getNextScale(double scale) {
                int i;
-               for (i=0; i<ZOOM_LEVELS.length-1; i++) {
-                       if (scale > ZOOM_LEVELS[i]-0.05 && scale < ZOOM_LEVELS[i+1]-0.05)
-                               return ZOOM_LEVELS[i+1];
+               for (i = 0; i < ZOOM_LEVELS.length - 1; i++) {
+                       if (scale > ZOOM_LEVELS[i] - 0.05 && scale < ZOOM_LEVELS[i + 1] - 0.05)
+                               return ZOOM_LEVELS[i + 1];
                }
-               if (scale > ZOOM_LEVELS[ZOOM_LEVELS.length/2]) {
+               if (scale > ZOOM_LEVELS[ZOOM_LEVELS.length / 2]) {
                        // scale is large, give next full 100%
-                       scale = Math.floor(scale+1.05);
+                       scale = Math.floor(scale + 1.05);
                        return scale;
                }
-               return scale*1.5;
+               return scale * 1.5;
+       }
+       
+       @Override
+       public void setEnabled(boolean b){
+               for ( Component c : getComponents() ){
+                       c.setEnabled(b);
+               }
+               super.setEnabled(b);
        }
        
 }
index 1d29b21633840f2a3f1364a981561c0071f304cd..ae2f7bf422ec0c27aae7f85717f718a32c10443c 100644 (file)
@@ -34,12 +34,20 @@ public class CustomFinImporter {
                facing = FacingDirections.UP;
                
                if (!validateImage(pic)) {
-                       throw new LocalizedIOException("CustomFinImport.error.badimage");
+                       throw new LocalizedIOException("CustomFinImport.badFinImage");
                }
-               
+
+               // Load the fin
                points.add(Coordinate.NUL);
                loadFin(pic, points);
-               optimizePoints(points);
+
+               // Optimize the loaded fin
+               int count;
+               do {
+                       count = points.size();
+                       optimizePoints(points);
+               } while (count != points.size());
+
                return points;
        }
        
@@ -52,22 +60,22 @@ public class CustomFinImporter {
                for (int x = 0; x < width; ++x) {
                        for (int y = 0; y < height; ++y) {
                                int pixel = pic.getRGB(x, y) & 0x00FFFFFF; // Clear alpha, we don't care about it
-                               if ((pixel == 0xFFFFFF) || (pixel == 0)) // black or white only
-                               {
-                                       if ((x == 0) || (x == width - 1) || (y == 0)) {
-                                               // Left, right and top must have no black (fin)
-                                               if (pixel == 0)
-                                                       return false;
-                                       } else if (y == height - 1) {
-                                               if (pixel == 0) {
-                                                       bottomEdgeFound = true;
-                                                       if (startX == -1)
-                                                               startX = x;
-                                               }
+                               // Convert to black & white
+                               int red = (pixel & 0x00FF0000) >> 16;  
+                               int green = (pixel & 0x0000FF00) >> 8;  
+                               int blue = (pixel & 0x000000FF);
+                               pixel =  (int)(0.299*red + 0.587*green + 0.114*blue);
+                               if (pixel > 200)
+                                       pixel = 0xFFFFFF; // White
+                               else
+                                       pixel = 0; // Black
+                               pic.setRGB(x, y, pixel);
+                               if (y == height - 1) {
+                                       if (pixel == 0) {
+                                               bottomEdgeFound = true;
+                                               if (startX == -1)
+                                                       startX = x;
                                        }
-                               } else {
-                                       // Found something other than a black or white pixel
-                                       return false;
                                }
                        }
                }
@@ -75,11 +83,11 @@ public class CustomFinImporter {
        }
        
        private void loadFin(BufferedImage pic, ArrayList<Coordinate> points) {
-               boolean calledTurnedAround = false;
                int height = pic.getHeight();
+               Boolean offBottom = false;
                
                currentX = startX;
-               currentY = pic.getHeight() - 1;
+               currentY = height - 1;
                
                do {
                        if (checkLeftIsFin(pic, currentX, currentY))
@@ -90,19 +98,17 @@ public class CustomFinImporter {
                                rotateRight();
                        else {
                                turnAround();
-                               calledTurnedAround = true;
                        }
                        
                        moveForward(pic);
+                       if (currentY < height - 1)
+                               offBottom = true;
                        if (pixelIsFin(pic, currentX, currentY)) {
-                               if (!calledTurnedAround) {
-                                       double x = (currentX - startX) * 0.001;
-                                       double y = (height - currentY - 1) * 0.001;
-                                       points.add(new Coordinate(x, y));
-                               } else
-                                       calledTurnedAround = false;
+                               double x = (currentX - startX) * 0.001;
+                               double y = (height - currentY - 1) * 0.001;
+                               points.add(new Coordinate(x, y));
                        }
-               } while (currentY < height - 1 && currentY >= 0);
+               } while ((!offBottom) || (currentY < height - 1 && currentY >= 0));
        }
        
        private boolean pixelIsFin(BufferedImage pic, int x, int y) {
@@ -210,18 +216,20 @@ public class CustomFinImporter {
                int startIx;
                ListIterator<Coordinate> start, entry, entry2;
                Coordinate startPoint, endPoint, testPoint;
+               Boolean removedSection;
                
                startIx = 0;
                start = points.listIterator();
                startPoint = start.next();
                while ((start.hasNext()) && (startPoint != points.get(points.size() - 1))) {
+                       removedSection = false;
                        entry = points.listIterator(points.size());
                        endPoint = entry.previous();
                        for (; endPoint != startPoint; endPoint = entry.previous()) {
                                entry2 = points.listIterator(start.nextIndex());
                                testPoint = entry2.next();
                                for (; testPoint != endPoint; testPoint = entry2.next()) {
-                                       if (pointDistanceFromLine(startPoint, endPoint, testPoint) > 0.001) {
+                                       if (pointDistanceFromLine(startPoint, endPoint, testPoint) > 0.0008) {
                                                break;
                                        }
                                }
@@ -239,10 +247,11 @@ public class CustomFinImporter {
                                        startIx = nextIx;
                                        start = points.listIterator(startIx);
                                        startPoint = start.next();
+                                       removedSection = true;
                                        break;
                                }
                        }
-                       if (endPoint == startPoint) {
+                       if ((!removedSection) && (endPoint == startPoint)) {
                                startIx = start.nextIndex();
                                if (start.hasNext())
                                        startPoint = start.next();
index 860379ed48bdb4f962cb973e7bdc9f33929eaac4..7fcdc2a4c0c337d42a80f9cb4ef4b5ad7e344372 100644 (file)
@@ -1,69 +1,73 @@
 package net.sf.openrocket.gui.util;
 
-import java.awt.Component;
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-
-import javax.imageio.ImageIO;
-import javax.swing.JOptionPane;
-import javax.swing.filechooser.FileFilter;
-
 import net.sf.openrocket.l10n.L10N;
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
 
+import javax.imageio.ImageIO;
+import javax.swing.*;
+import javax.swing.filechooser.FileFilter;
+import java.awt.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Locale;
+
 /**
  * Helper methods related to user-initiated file manipulation.
  * <p>
  * These methods log the necessary information to the debug log.
-* 
+*
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public final class FileHelper {
        private static final LogHelper log = Application.getLogger();
        private static final Translator trans = Application.getTranslator();
-       
-       
+
+
        // TODO: HIGH: Rename translation keys
-       
+
        /** File filter for any rocket designs (*.ork, *.rkt) */
        public static final FileFilter ALL_DESIGNS_FILTER =
                        new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter1"),
                                        ".ork", ".ork.gz", ".rkt", ".rkt.gz");
-       
+
        /** File filter for OpenRocket designs (*.ork) */
        public static final FileFilter OPENROCKET_DESIGN_FILTER =
                        new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter2"), ".ork", ".ork.gz");
-       
+
        /** File filter for RockSim designs (*.rkt) */
        public static final FileFilter ROCKSIM_DESIGN_FILTER =
                        new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter3"), ".rkt", ".rkt.gz");
-       
+
+       /** File filter for OpenRocket components and presets (*.orc) */
+       public static final FileFilter OPEN_ROCKET_COMPONENT_FILTER =
+                       new SimpleFileFilter(trans.get("BasicFrame.SimpleFileFilter4"), ".orc", ".orc.gz");
+
        /** File filter for PDF files (*.pdf) */
        public static final FileFilter PDF_FILTER =
                        new SimpleFileFilter(trans.get("filetypes.pdf"), ".pdf");
-       
+
        /** File filter for CSV files (*.csv) */
        public static final FileFilter CSV_FILE_FILTER =
                        new SimpleFileFilter(trans.get("SimExpPan.desc"), ".csv");
-       
-       
-       
-       
+
+
+
+
        private FileHelper() {
                // Prevent instantiation
        }
-       
-       
+
+
        public static FileFilter getImageFileFilter() {
                String[] extensions = ImageIO.getReaderFileSuffixes();
                for (int i = 0; i < extensions.length; i++) {
-                       extensions[i] = extensions[i].toLowerCase();
+                       extensions[i] = extensions[i].toLowerCase(Locale.ENGLISH);
                }
                Arrays.sort(extensions);
-               
+
                StringBuilder sb = new StringBuilder();
                sb.append(trans.get("filetypes.images"));
                sb.append(" (");
@@ -74,31 +78,31 @@ public final class FileHelper {
                        }
                }
                sb.append(")");
-               
+
                return new SimpleFileFilter(sb.toString(), extensions);
        }
-       
-       
+
+
        /**
         * Ensure that the provided file has a file extension.  If the file does not have
         * any extension, append the provided extension to it.
-        * 
+        *
         * @param original              the original file
         * @param extension             the extension to append if none exists (without preceding dot)
         * @return                              the resulting file
         */
        public static File ensureExtension(File original, String extension) {
-               
+
                if (original.getName().indexOf('.') < 0) {
                        log.debug(1, "File name does not contain extension, adding '" + extension + "'");
                        String name = original.getAbsolutePath();
                        name = name + "." + extension;
                        return new File(name);
                }
-               
+
                return original;
        }
-       
+
        /**
         * Ensure that the provided file has the given file extension.  This differs from ensureExtension in that this
         * method guarantees that the file will have the extension, whereas ensureExtension only treats the extension
@@ -109,8 +113,8 @@ public final class FileHelper {
         * @return                              the resulting file
         */
        public static File forceExtension(File original, String extension) {
-               
-               if (!original.getName().toLowerCase().endsWith(extension.toLowerCase())) {
+
+               if (!original.getName().toLowerCase(Locale.ENGLISH).endsWith(extension.toLowerCase(Locale.ENGLISH))) {
                        log.debug(1, "File name does not contain extension, adding '" + extension + "'");
                        String name = original.getAbsolutePath();
                        if (extension.startsWith(".")) {
@@ -121,15 +125,15 @@ public final class FileHelper {
                        }
                        return new File(name);
                }
-               
+
                return original;
        }
-       
-       
+
+
        /**
         * Confirm that it is allowed to write to a file.  If the file exists,
         * a confirmation dialog will be presented to the user to ensure overwriting is ok.
-        * 
+        *
         * @param file          the file that is going to be written.
         * @param parent        the parent component for the dialog.
         * @return                      <code>true</code> to write, <code>false</code> to abort.
@@ -148,23 +152,23 @@ public final class FileHelper {
                }
                return true;
        }
-       
-       
+
+
        /**
         * Display an error message to the user that writing a file failed.
-        * 
+        *
         * @param e                     the I/O exception that caused the error.
         * @param parent        the parent component for the dialog.
         */
        public static void errorWriting(IOException e, Component parent) {
-               
+
                log.warn(1, "Error writing to file", e);
                JOptionPane.showMessageDialog(parent,
                                new Object[] {
                                                trans.get("error.writing.desc"),
                                                e.getLocalizedMessage()
                                }, trans.get("error.writing.title"), JOptionPane.ERROR_MESSAGE);
-               
+
        }
-       
+
 }
index 4ee74ba4e83edfc75245c9020ecaf00e26d9ba84..4ac68dcebcad4091b856f7d7a511fcb011d43b17 100644 (file)
@@ -348,6 +348,26 @@ public class GUIUtil {
        }
        
        
+       public static void setAutomaticColumnTableWidths(JTable table, int max) {
+               int columns = table.getColumnCount();
+               int widths[] = new int[columns];
+               Arrays.fill(widths, 1);
+               
+               for (int row = 0; row < table.getRowCount(); row++) {
+                       for (int col = 0; col < columns; col++) {
+                               Object value = table.getValueAt(row, col);
+                               //System.out.println("row=" + row + " col=" + col + " : " + value);
+                               widths[col] = Math.max(widths[col], value == null ? 0 : value.toString().length());
+                       }
+               }
+               
+               
+               for (int col = 0; col < columns; col++) {
+                       System.err.println("Setting column " + col + " to width " + widths[col]);
+                       table.getColumnModel().getColumn(col).setPreferredWidth(Math.min(widths[col], max) * 100);
+               }
+       }
+       
        /**
         * Changes the style of the font of the specified border.
         * 
@@ -362,10 +382,10 @@ public class GUIUtil {
                 */
                Font font = border.getTitleFont();
                if (font == null) {
-                       log.error("Border font is null, reverting to JLabel font");
+                       log.warn("JRE bug workaround : Border font is null, reverting to JLabel font");
                        font = new JLabel().getFont();
                        if (font == null) {
-                               log.error("JLabel font is null, not modifying font");
+                               log.warn("JRE bug workaround : JLabel font is null, not modifying font");
                                return;
                        }
                }
index 8f304b6324a9cb2b056e343b7936b733dabae96a..0fa2b67c57ad55f59ec6c75262fb56b60b502d61 100644 (file)
@@ -73,6 +73,13 @@ public class Icons {
        public static final Icon PREFERENCES = loadImageIcon("pix/icons/preferences.png", "Preferences");
        
        public static final Icon DELETE = loadImageIcon("pix/icons/delete.png", "Delete");
+       public static final Icon EDIT = loadImageIcon("pix/icons/pencil.png", "Edit");
+       public static final Icon UP = loadImageIcon("pix/icons/up.png", "Up");
+       public static final Icon DOWN = loadImageIcon("pix/icons/down.png", "Down");
+       
+       public static final Icon NOT_FAVORITE = loadImageIcon("pix/icons/star_silver.png", "Not favorite");
+       public static final Icon FAVORITE = loadImageIcon("pix/icons/star_gold.png", "Favorite");
+       
        
        static {
                log.debug("Icons loaded");
index 39ded917956f48ffca6e2c54935d56918a0a0ce6..e895b9299d490c46d9b33aca661ab460e60314d9 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.gui.util;
 
 import java.io.File;
+import java.util.Locale;
 
 import javax.swing.filechooser.FileFilter;
 
@@ -12,7 +13,7 @@ import javax.swing.filechooser.FileFilter;
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public class SimpleFileFilter extends FileFilter implements java.io.FileFilter {
-
+       
        private final String description;
        private final boolean acceptDir;
        private final String[] extensions;
@@ -25,11 +26,11 @@ public class SimpleFileFilter extends FileFilter implements java.io.FileFilter {
         * @param description   the description of this file filter.
         * @param extensions    an array of extensions that match this filter.
         */
-       public SimpleFileFilter(String description, String ... extensions) {
+       public SimpleFileFilter(String description, String... extensions) {
                this(description, true, extensions);
        }
        
-
+       
        /**
         * Create filter that accepts files with the provided extensions.
         * 
@@ -37,12 +38,12 @@ public class SimpleFileFilter extends FileFilter implements java.io.FileFilter {
         * @param acceptDir             whether to accept directories
         * @param extensions    an array of extensions that match this filter.
         */
-       public SimpleFileFilter(String description, boolean acceptDir, String ... extensions) {
+       public SimpleFileFilter(String description, boolean acceptDir, String... extensions) {
                this.description = description;
                this.acceptDir = acceptDir;
                this.extensions = new String[extensions.length];
-               for (int i=0; i<extensions.length; i++) {
-                       String ext = extensions[i].toLowerCase();
+               for (int i = 0; i < extensions.length; i++) {
+                       String ext = extensions[i].toLowerCase(Locale.ENGLISH);
                        if (ext.charAt(0) == '.') {
                                this.extensions[i] = ext;
                        } else {
@@ -60,18 +61,18 @@ public class SimpleFileFilter extends FileFilter implements java.io.FileFilter {
                        return acceptDir;
                
                String filename = file.getName();
-               filename = filename.toLowerCase();
-               for (String ext: extensions) {
+               filename = filename.toLowerCase(Locale.ENGLISH);
+               for (String ext : extensions) {
                        if (filename.endsWith(ext))
                                return true;
                }
                
                return false;
        }
-
+       
        @Override
        public String getDescription() {
                return description;
        }
-
+       
 }
index 45f2e0dc2944d074d5f4d5153ed819f5258bf2b6..61e6be857657536c10f4a30291040b7ec7a040fc 100644 (file)
@@ -5,6 +5,7 @@ import java.awt.Dimension;
 import java.awt.Point;
 import java.io.File;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -17,6 +18,7 @@ import net.sf.openrocket.arch.SystemInfo;
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.rocketcomponent.Rocket;
 import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.RK4SimulationStepper;
@@ -32,17 +34,17 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        
        private static final String SPLIT_CHARACTER = "|";
        
-
+       
        private static final List<Locale> SUPPORTED_LOCALES;
        static {
                List<Locale> list = new ArrayList<Locale>();
-               for (String lang : new String[] { "en", "de", "es", "fr", "it", "ru" }) {
+               for (String lang : new String[] { "en", "de", "es", "fr", "it", "ru", "cs", "pl" }) {
                        list.add(new Locale(lang));
                }
                SUPPORTED_LOCALES = Collections.unmodifiableList(list);
        }
        
-
+       
        /**
         * Whether to use the debug-node instead of the normal node.
         */
@@ -62,9 +64,9 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
         */
        private static final String NODENAME = (DEBUG ? "OpenRocket-debug" : "OpenRocket");
        
-       private  final Preferences PREFNODE;
+       private final Preferences PREFNODE;
+       
        
-
        public SwingPreferences() {
                Preferences root = Preferences.userRoot();
                if (DEBUG && CLEARPREFS) {
@@ -79,13 +81,13 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
                PREFNODE = root.node(NODENAME);
        }
        
-
-
+       
+       
        
        //////////////////////
        
-
-
+       
+       
        /**
         * Store the current OpenRocket version into the preferences to allow for preferences migration.
         */
@@ -106,9 +108,9 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        }
        
        @Override
-       public String getString( String directory, String key, String defaultValue ) {
+       public String getString(String directory, String key, String defaultValue) {
                Preferences p = PREFNODE.node(directory);
-               return p.get(key,defaultValue);
+               return p.get(key, defaultValue);
        }
        
        /**
@@ -128,12 +130,12 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        }
        
        @Override
-       public void putString(String directory, String key, String value ) {
+       public void putString(String directory, String key, String value) {
                Preferences p = PREFNODE.node(directory);
-               if ( value == null ) {
+               if (value == null) {
                        p.remove(key);
                } else {
-                       p.put(key,value);
+                       p.put(key, value);
                }
                storeVersion();
        }
@@ -163,29 +165,29 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        }
        
        @Override
-       public int getInt( String key, int defaultValue ) {
+       public int getInt(String key, int defaultValue) {
                return PREFNODE.getInt(key, defaultValue);
        }
        
        @Override
-       public void putInt( String key , int value ) {
-               PREFNODE.putInt(key, value );
+       public void putInt(String key, int value) {
+               PREFNODE.putInt(key, value);
                storeVersion();
        }
        
        @Override
        public double getDouble(String key, double defaultValue) {
-               return PREFNODE.getDouble(key,  defaultValue );
+               return PREFNODE.getDouble(key, defaultValue);
        }
-
+       
        @Override
        public void putDouble(String key, double value) {
-               PREFNODE.putDouble(key,value);
+               PREFNODE.putDouble(key, value);
                storeVersion();
        }
-
-
-
+       
+       
+       
        /**
         * Return a preferences object for the specified node name.
         * 
@@ -199,7 +201,7 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        
        //////////////////
        
-
+       
        public static List<Locale> getSupportedLocales() {
                return SUPPORTED_LOCALES;
        }
@@ -328,8 +330,8 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        }
        
        
-
-
+       
+       
        public Dimension getWindowSize(Class<?> c) {
                int x, y;
                String pref = PREFNODE.node("windows").get("size." + c.getCanonicalName(), null);
@@ -370,9 +372,9 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
         * you can pass (java.awt.Color) null to the second argument to
         * disambiguate
         */
-       public Color getColor( String key, Color defaultValue ) {
+       public Color getColor(String key, Color defaultValue) {
                net.sf.openrocket.util.Color c = super.getColor(key, (net.sf.openrocket.util.Color) null);
-               if ( c == null ) {
+               if (c == null) {
                        return defaultValue;
                }
                return ColorConversion.toAwtColor(c);
@@ -381,9 +383,9 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        /**
         * 
         */
-       public void putColor( String key, Color value ) {
+       public void putColor(String key, Color value) {
                net.sf.openrocket.util.Color c = ColorConversion.fromAwtColor(value);
-               super.putColor(key,  c); 
+               super.putColor(key, c);
        }
        
        ////  Printing
@@ -407,7 +409,7 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        }
        
        
-
+       
        /////////  Export variables
        
        public boolean isExportSelected(FlightDataType type) {
@@ -421,7 +423,7 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        }
        
        
-
+       
        /////////  Default unit storage
        
        public void loadDefaultUnits() {
@@ -457,10 +459,10 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
        }
        
        
-
+       
        ////  Material storage
        
-
+       
        /**
         * Add a user-defined material to the preferences.  The preferences are
         * first checked for an existing material matching the provided one using
@@ -468,10 +470,11 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
         * 
         * @param m             the material to add.
         */
+       @Override
        public void addUserMaterial(Material m) {
                Preferences prefs = PREFNODE.node("userMaterials");
                
-
+               
                // Check whether material already exists
                if (getUserMaterials().contains(m)) {
                        return;
@@ -495,6 +498,7 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
         * 
         * @param m             the material to remove.
         */
+       @Override
        public void removeUserMaterial(Material m) {
                Preferences prefs = PREFNODE.node("userMaterials");
                
@@ -527,6 +531,7 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
         * 
         * @return      a set of all user-defined materials.
         */
+       @Override
        public Set<Material> getUserMaterials() {
                Preferences prefs = PREFNODE.node("userMaterials");
                
@@ -553,7 +558,27 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
                return materials;
        }
        
+       @Override
+       public void setComponentFavorite(ComponentPreset preset, ComponentPreset.Type type, boolean favorite) {
+               Preferences prefs = PREFNODE.node("favoritePresets").node(type.name());
+               if (favorite) {
+                       prefs.putBoolean(preset.preferenceKey(), true);
+               } else {
+                       prefs.remove(preset.preferenceKey());
+               }
+       }
        
+       @Override
+       public Set<String> getComponentFavorites(ComponentPreset.Type type) {
+               Preferences prefs = PREFNODE.node("favoritePresets").node(type.name());
+               Set<String> collection = new HashSet<String>();
+               try {
+                       collection.addAll(Arrays.asList(prefs.keys()));
+               } catch (BackingStoreException bex) {
+                       
+               }
+               return collection;
+       }
        ////  Helper methods
        
 }
index b4212dc95acf3a6bca69295f0ed49a0b8b6be62e..6281b6e8011ae89b0a67d1e1abe226891aed89f9 100644 (file)
@@ -15,7 +15,7 @@ import net.sf.openrocket.util.BugException;
  */
 public class ClassBasedTranslator implements Translator {
        
-
+       
        private final Translator translator;
        private final String className;
        
@@ -41,7 +41,7 @@ public class ClassBasedTranslator implements Translator {
        }
        
        
-
+       
        @Override
        public String get(String key) {
                String classKey = className + "." + key;
@@ -63,7 +63,20 @@ public class ClassBasedTranslator implements Translator {
        }
        
        
-
+       
+       @Override
+       public String get(String base, String text) {
+               return translator.get(base, text);
+       }
+       
+       @Override
+       public String getBaseText(String base, String translation) {
+               return translator.getBaseText(base, translation);
+       }
+       
+       
+       
+       
        private static String getStackClass(int levels) {
                TraceException trace = new TraceException();
                StackTraceElement stack[] = trace.getStackTrace();
@@ -82,11 +95,10 @@ public class ClassBasedTranslator implements Translator {
        }
        
        
-
-
+       
+       
        // For unit testing purposes
        String getClassName() {
                return className;
        }
-       
 }
index 5a2bf5920876a3c3b913f98727d3afd111856a13..ccf72e58b766877f5f63f9f0f6be38b2afd3ebf8 100644 (file)
@@ -22,7 +22,7 @@ public class DebugTranslator implements Translator {
        }
        
        
-
+       
        @Override
        public String get(String key) {
                if (translator != null) {
@@ -31,4 +31,22 @@ public class DebugTranslator implements Translator {
                return "[" + key + "]";
        }
        
+       
+       
+       @Override
+       public String get(String base, String text) {
+               return "[" + base + ":" + text + "]";
+       }
+       
+       
+       
+       @Override
+       public String getBaseText(String base, String translation) {
+               if (translation.startsWith("[" + base + ":") && translation.endsWith("]")) {
+                       return translation.substring(base.length() + 2, translation.length() - 1);
+               }
+               return translation;
+       }
+       
+       
 }
index dd916b6cde240c9464ea57bee78be6b291981695..1287822cc938ffaf7e2703587af1ae54ebb2a71c 100644 (file)
@@ -29,7 +29,7 @@ public class ExceptionSuppressingTranslator implements Translator {
        }
        
        
-
+       
        @Override
        public String get(String key) {
                try {
@@ -42,7 +42,18 @@ public class ExceptionSuppressingTranslator implements Translator {
        }
        
        
-
+       @Override
+       public String get(String base, String text) {
+               return translator.get(base, text);
+       }
+       
+       
+       @Override
+       public String getBaseText(String base, String translation) {
+               return translator.getBaseText(base, translation);
+       }
+       
+       
        private static synchronized void handleError(String key, MissingResourceException e) {
                if (!errorReported) {
                        errorReported = true;
@@ -50,4 +61,6 @@ public class ExceptionSuppressingTranslator implements Translator {
                }
        }
        
+       
+       
 }
index 878b3c41c3b5e64868045fc3e99d1585f3f9c889..3303292d3897eb7f35211140dbc82ff25bf67126 100644 (file)
@@ -1,8 +1,13 @@
 package net.sf.openrocket.l10n;
 
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map;
 import java.util.regex.Pattern;
 
+import net.sf.openrocket.util.Chars;
+
 /**
  * Helper methods for localization needs.
  * 
@@ -10,6 +15,12 @@ import java.util.regex.Pattern;
  */
 public final class L10N {
        
+       /**
+        * Unicode character normalization map.  This is used because Android does
+        * not support the java.text.Normalize class.
+        */
+       private static final Map<Character, String> NORMALIZATION_MAP;
+       
        private L10N() {
                // Prevent instantiation
        }
@@ -54,4 +65,339 @@ public final class L10N {
                return l;
        }
        
+       
+       public static String normalize(String text) {
+               text = unicodeNormalize(text);
+               text = text.toLowerCase();
+               text = text.replaceAll("\\s+", " ");
+               text = text.trim();
+               
+               StringBuilder sb = new StringBuilder(text.length());
+               for (char c : text.toCharArray()) {
+                       if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) {
+                               sb.append(c);
+                       } else if (c == ' ' || c == '/' || c == Chars.FRACTION) {
+                               sb.append('_');
+                       }
+               }
+               text = sb.toString();
+               
+               text = text.replaceAll("^_+", "");
+               text = text.replaceAll("_+$", "");
+               
+               return text;
+       }
+       
+       private static String unicodeNormalize(String text) {
+               StringBuilder sb = new StringBuilder(text.length());
+               for (char c : text.toCharArray()) {
+                       String s = NORMALIZATION_MAP.get(c);
+                       if (s != null) {
+                               sb.append(s);
+                       } else {
+                               sb.append(c);
+                       }
+               }
+               return sb.toString();
+       }
+       
+       
+       static {
+               /*
+                * This list is generated using the L10NGenerator utility.
+                */
+               Map<Character, String> m = new HashMap<Character, String>();
+               m.put('\u00aa', "a");
+               m.put('\u00b2', "2");
+               m.put('\u00b3', "3");
+               m.put('\u00b9', "1");
+               m.put('\u00ba', "o");
+               m.put('\u00bc', "1/4");
+               m.put('\u00bd', "1/2");
+               m.put('\u00be', "3/4");
+               m.put('\u00c0', "A");
+               m.put('\u00c1', "A");
+               m.put('\u00c2', "A");
+               m.put('\u00c3', "A");
+               m.put('\u00c4', "A");
+               m.put('\u00c5', "A");
+               m.put('\u00c7', "C");
+               m.put('\u00c8', "E");
+               m.put('\u00c9', "E");
+               m.put('\u00ca', "E");
+               m.put('\u00cb', "E");
+               m.put('\u00cc', "I");
+               m.put('\u00cd', "I");
+               m.put('\u00ce', "I");
+               m.put('\u00cf', "I");
+               m.put('\u00d1', "N");
+               m.put('\u00d2', "O");
+               m.put('\u00d3', "O");
+               m.put('\u00d4', "O");
+               m.put('\u00d5', "O");
+               m.put('\u00d6', "O");
+               m.put('\u00d9', "U");
+               m.put('\u00da', "U");
+               m.put('\u00db', "U");
+               m.put('\u00dc', "U");
+               m.put('\u00dd', "Y");
+               m.put('\u00e0', "a");
+               m.put('\u00e1', "a");
+               m.put('\u00e2', "a");
+               m.put('\u00e3', "a");
+               m.put('\u00e4', "a");
+               m.put('\u00e5', "a");
+               m.put('\u00e7', "c");
+               m.put('\u00e8', "e");
+               m.put('\u00e9', "e");
+               m.put('\u00ea', "e");
+               m.put('\u00eb', "e");
+               m.put('\u00ec', "i");
+               m.put('\u00ed', "i");
+               m.put('\u00ee', "i");
+               m.put('\u00ef', "i");
+               m.put('\u00f1', "n");
+               m.put('\u00f2', "o");
+               m.put('\u00f3', "o");
+               m.put('\u00f4', "o");
+               m.put('\u00f5', "o");
+               m.put('\u00f6', "o");
+               m.put('\u00f9', "u");
+               m.put('\u00fa', "u");
+               m.put('\u00fb', "u");
+               m.put('\u00fc', "u");
+               m.put('\u00fd', "y");
+               m.put('\u00ff', "y");
+               m.put('\u0100', "A");
+               m.put('\u0101', "a");
+               m.put('\u0102', "A");
+               m.put('\u0103', "a");
+               m.put('\u0104', "A");
+               m.put('\u0105', "a");
+               m.put('\u0106', "C");
+               m.put('\u0107', "c");
+               m.put('\u0108', "C");
+               m.put('\u0109', "c");
+               m.put('\u010a', "C");
+               m.put('\u010b', "c");
+               m.put('\u010c', "C");
+               m.put('\u010d', "c");
+               m.put('\u010e', "D");
+               m.put('\u010f', "d");
+               m.put('\u0112', "E");
+               m.put('\u0113', "e");
+               m.put('\u0114', "E");
+               m.put('\u0115', "e");
+               m.put('\u0116', "E");
+               m.put('\u0117', "e");
+               m.put('\u0118', "E");
+               m.put('\u0119', "e");
+               m.put('\u011a', "E");
+               m.put('\u011b', "e");
+               m.put('\u011c', "G");
+               m.put('\u011d', "g");
+               m.put('\u011e', "G");
+               m.put('\u011f', "g");
+               m.put('\u0120', "G");
+               m.put('\u0121', "g");
+               m.put('\u0122', "G");
+               m.put('\u0123', "g");
+               m.put('\u0124', "H");
+               m.put('\u0125', "h");
+               m.put('\u0128', "I");
+               m.put('\u0129', "i");
+               m.put('\u012a', "I");
+               m.put('\u012b', "i");
+               m.put('\u012c', "I");
+               m.put('\u012d', "i");
+               m.put('\u012e', "I");
+               m.put('\u012f', "i");
+               m.put('\u0130', "I");
+               m.put('\u0132', "IJ");
+               m.put('\u0133', "ij");
+               m.put('\u0134', "J");
+               m.put('\u0135', "j");
+               m.put('\u0136', "K");
+               m.put('\u0137', "k");
+               m.put('\u0139', "L");
+               m.put('\u013a', "l");
+               m.put('\u013b', "L");
+               m.put('\u013c', "l");
+               m.put('\u013d', "L");
+               m.put('\u013e', "l");
+               m.put('\u013f', "L");
+               m.put('\u0140', "l");
+               m.put('\u0143', "N");
+               m.put('\u0144', "n");
+               m.put('\u0145', "N");
+               m.put('\u0146', "n");
+               m.put('\u0147', "N");
+               m.put('\u0148', "n");
+               m.put('\u0149', "n");
+               m.put('\u014c', "O");
+               m.put('\u014d', "o");
+               m.put('\u014e', "O");
+               m.put('\u014f', "o");
+               m.put('\u0150', "O");
+               m.put('\u0151', "o");
+               m.put('\u0154', "R");
+               m.put('\u0155', "r");
+               m.put('\u0156', "R");
+               m.put('\u0157', "r");
+               m.put('\u0158', "R");
+               m.put('\u0159', "r");
+               m.put('\u015a', "S");
+               m.put('\u015b', "s");
+               m.put('\u015c', "S");
+               m.put('\u015d', "s");
+               m.put('\u015e', "S");
+               m.put('\u015f', "s");
+               m.put('\u0160', "S");
+               m.put('\u0161', "s");
+               m.put('\u0162', "T");
+               m.put('\u0163', "t");
+               m.put('\u0164', "T");
+               m.put('\u0165', "t");
+               m.put('\u0168', "U");
+               m.put('\u0169', "u");
+               m.put('\u016a', "U");
+               m.put('\u016b', "u");
+               m.put('\u016c', "U");
+               m.put('\u016d', "u");
+               m.put('\u016e', "U");
+               m.put('\u016f', "u");
+               m.put('\u0170', "U");
+               m.put('\u0171', "u");
+               m.put('\u0172', "U");
+               m.put('\u0173', "u");
+               m.put('\u0174', "W");
+               m.put('\u0175', "w");
+               m.put('\u0176', "Y");
+               m.put('\u0177', "y");
+               m.put('\u0178', "Y");
+               m.put('\u0179', "Z");
+               m.put('\u017a', "z");
+               m.put('\u017b', "Z");
+               m.put('\u017c', "z");
+               m.put('\u017d', "Z");
+               m.put('\u017e', "z");
+               m.put('\u017f', "s");
+               m.put('\u01a0', "O");
+               m.put('\u01a1', "o");
+               m.put('\u01af', "U");
+               m.put('\u01b0', "u");
+               m.put('\u01c4', "DZ");
+               m.put('\u01c5', "Dz");
+               m.put('\u01c6', "dz");
+               m.put('\u01c7', "LJ");
+               m.put('\u01c8', "Lj");
+               m.put('\u01c9', "lj");
+               m.put('\u01ca', "NJ");
+               m.put('\u01cb', "Nj");
+               m.put('\u01cc', "nj");
+               m.put('\u01cd', "A");
+               m.put('\u01ce', "a");
+               m.put('\u01cf', "I");
+               m.put('\u01d0', "i");
+               m.put('\u01d1', "O");
+               m.put('\u01d2', "o");
+               m.put('\u01d3', "U");
+               m.put('\u01d4', "u");
+               m.put('\u01d5', "U");
+               m.put('\u01d6', "u");
+               m.put('\u01d7', "U");
+               m.put('\u01d8', "u");
+               m.put('\u01d9', "U");
+               m.put('\u01da', "u");
+               m.put('\u01db', "U");
+               m.put('\u01dc', "u");
+               m.put('\u01de', "A");
+               m.put('\u01df', "a");
+               m.put('\u01e0', "A");
+               m.put('\u01e1', "a");
+               m.put('\u01e6', "G");
+               m.put('\u01e7', "g");
+               m.put('\u01e8', "K");
+               m.put('\u01e9', "k");
+               m.put('\u01ea', "O");
+               m.put('\u01eb', "o");
+               m.put('\u01ec', "O");
+               m.put('\u01ed', "o");
+               m.put('\u01f0', "j");
+               m.put('\u01f1', "DZ");
+               m.put('\u01f2', "Dz");
+               m.put('\u01f3', "dz");
+               m.put('\u01f4', "G");
+               m.put('\u01f5', "g");
+               m.put('\u01f8', "N");
+               m.put('\u01f9', "n");
+               m.put('\u01fa', "A");
+               m.put('\u01fb', "a");
+               m.put('\u0200', "A");
+               m.put('\u0201', "a");
+               m.put('\u0202', "A");
+               m.put('\u0203', "a");
+               m.put('\u0204', "E");
+               m.put('\u0205', "e");
+               m.put('\u0206', "E");
+               m.put('\u0207', "e");
+               m.put('\u0208', "I");
+               m.put('\u0209', "i");
+               m.put('\u020a', "I");
+               m.put('\u020b', "i");
+               m.put('\u020c', "O");
+               m.put('\u020d', "o");
+               m.put('\u020e', "O");
+               m.put('\u020f', "o");
+               m.put('\u0210', "R");
+               m.put('\u0211', "r");
+               m.put('\u0212', "R");
+               m.put('\u0213', "r");
+               m.put('\u0214', "U");
+               m.put('\u0215', "u");
+               m.put('\u0216', "U");
+               m.put('\u0217', "u");
+               m.put('\u0218', "S");
+               m.put('\u0219', "s");
+               m.put('\u021a', "T");
+               m.put('\u021b', "t");
+               m.put('\u021e', "H");
+               m.put('\u021f', "h");
+               m.put('\u0226', "A");
+               m.put('\u0227', "a");
+               m.put('\u0228', "E");
+               m.put('\u0229', "e");
+               m.put('\u022a', "O");
+               m.put('\u022b', "o");
+               m.put('\u022c', "O");
+               m.put('\u022d', "o");
+               m.put('\u022e', "O");
+               m.put('\u022f', "o");
+               m.put('\u0230', "O");
+               m.put('\u0231', "o");
+               m.put('\u0232', "Y");
+               m.put('\u0233', "y");
+               m.put('\u2070', "0");
+               m.put('\u2071', "i");
+               m.put('\u2074', "4");
+               m.put('\u2075', "5");
+               m.put('\u2076', "6");
+               m.put('\u2077', "7");
+               m.put('\u2078', "8");
+               m.put('\u2079', "9");
+               m.put('\u2080', "0");
+               m.put('\u2081', "1");
+               m.put('\u2082', "2");
+               m.put('\u2083', "3");
+               m.put('\u2084', "4");
+               m.put('\u2085', "5");
+               m.put('\u2086', "6");
+               m.put('\u2087', "7");
+               m.put('\u2088', "8");
+               m.put('\u2089', "9");
+               m.put('\u2044', "/");
+               m.put('\u200b', " ");
+               m.put('\u00a0', " ");
+               NORMALIZATION_MAP = Collections.unmodifiableMap(m);
+       }
 }
index 241ecefcfba93f62525c9f6bd0734cb2b6d3937e..d210e01e9b52c328292dbc1c100f0fcff51b0596 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.l10n;
 
 import java.util.Locale;
+import java.util.MissingResourceException;
 import java.util.ResourceBundle;
 
 /**
@@ -11,6 +12,7 @@ import java.util.ResourceBundle;
 public class ResourceBundleTranslator implements Translator {
        
        private final ResourceBundle bundle;
+       private final ResourceBundle english;
        
        /**
         * Create a ResourceBundleTranslator using the default Locale.
@@ -29,6 +31,7 @@ public class ResourceBundleTranslator implements Translator {
         */
        public ResourceBundleTranslator(String baseName, Locale locale) {
                this.bundle = ResourceBundle.getBundle(baseName, locale);
+               this.english = ResourceBundle.getBundle(baseName, Locale.ROOT);
        }
        
        
@@ -40,4 +43,27 @@ public class ResourceBundleTranslator implements Translator {
                return bundle.getString(key);
        }
        
+       @Override
+       public synchronized String get(String base, String text) {
+               String key = base + "." + L10N.normalize(text);
+               try {
+                       return bundle.getString(key);
+               } catch (MissingResourceException e) {
+                       return text;
+               }
+       }
+       
+       @Override
+       public synchronized String getBaseText(String base, String translation) {
+               String prefix = base + ".";
+               for (String key : bundle.keySet()) {
+                       if (key.startsWith(prefix)) {
+                               String value = bundle.getString(key);
+                               if (value.equals(translation)) {
+                                       return english.getString(key);
+                               }
+                       }
+               }
+               return translation;
+       }
 }
index 9eed2cdfa51ada85ce290e1941df03676c1ccfb7..5211ed730d80868449f09e265fc5dd9a578196d5 100644 (file)
@@ -22,4 +22,33 @@ public interface Translator {
         */
        public String get(String key);
        
+       
+       /**
+        * Retrieve a translated string based on a base key and base (English) version of the text.
+        * The base text is normalized before using as a key.
+        * <p>
+        * This is meant to be used in very specific cases where the English name is
+        * used as a key for translation and storage.  If a translation is not found,
+        * the base text is used instead.
+        * 
+        * @param base          the base for the logical key
+        * @param text          the base (English) text to translate
+        * @return                      the translated string, or "text" if not found
+        */
+       public String get(String base, String text);
+       
+       
+       /**
+        * Find the base (English) version of a translated text.
+        * <p>
+        * This is the opposite operation of {@link #get(String, String)}, and
+        * meant for use in very specific cases when storing the values of
+        * translated texts.
+        * 
+        * @param base                  the base for the logical key
+        * @param translation   the translated string
+        * @return                              the base text, or the translation if not found.
+        */
+       public String getBaseText(String base, String translation);
+       
 }
index b52d14536a383c6bf1aa18d1092b8517298d127a..a57838560b67f7d2689e8c30ff0b5091d25925a0 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.logging;
 
+import java.util.Locale;
+
 /**
  * The logging level.  The natural order of the LogLevel orders the levels
  * from highest priority to lowest priority.  Comparisons of the relative levels
@@ -16,13 +18,13 @@ public enum LogLevel {
         * No ERROR level events _should_ occur while running the program.
         */
        ERROR,
-
+       
        /** 
         * Level for indicating error conditions or atypical events that can occur during
         * normal operation (errors while loading files, weird computation results etc).
         */
        WARN,
-
+       
        /** 
         * Level for logging user actions (adding and modifying components, running
         * simulations etc).  A user action should be logged as soon as possible on this
@@ -30,13 +32,13 @@ public enum LogLevel {
         * user actions from a bounded log buffer.
         */
        USER,
-
+       
        /**
         * Level for indicating general level actions the software is performing and
         * other notable events during execution (dialogs shown, simulations run etc).
         */
        INFO,
-
+       
        /**
         * Level for indicating mid-results, outcomes of methods and other debugging 
         * information.  The data logged should be of value when analyzing error
@@ -44,7 +46,7 @@ public enum LogLevel {
         * during e.g. flight simulation should use the VBOSE level instead.
         */
        DEBUG,
-
+       
        /**
         * Level of verbose debug logging to be used in areas which are called repeatedly,
         * such as computational methods used in simulations.  This level is separated to
@@ -103,7 +105,7 @@ public enum LogLevel {
                if (value == null) {
                        return defaultLevel;
                }
-               value = value.toUpperCase().trim();
+               value = value.toUpperCase(Locale.ENGLISH).trim();
                
                // Find the correct level
                LogLevel level = defaultLevel;
index 4b5d8276f2f74ca4219c0ad9c0aaf901f8eef5fc..3fd82fdf3d18a61d488900efd6fa4339404fba46 100644 (file)
@@ -2,8 +2,10 @@ package net.sf.openrocket.masscalc;
 
 import static net.sf.openrocket.util.MathUtil.pow2;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 import net.sf.openrocket.motor.Motor;
@@ -38,6 +40,7 @@ public class BasicMassCalculator extends AbstractMassCalculator {
         * Return the CG of the rocket with the specified motor status (no motors,
         * ignition, burnout).
         */
+       @Override
        public Coordinate getCG(Configuration configuration, MassCalcType type) {
                checkCache(configuration);
                calculateStageCache(configuration);
@@ -80,6 +83,7 @@ public class BasicMassCalculator extends AbstractMassCalculator {
        /**
         * Return the CG of the rocket with the provided motor configuration.
         */
+       @Override
        public Coordinate getCG(Configuration configuration, MotorInstanceConfiguration motors) {
                checkCache(configuration);
                calculateStageCache(configuration);
@@ -103,7 +107,6 @@ public class BasicMassCalculator extends AbstractMassCalculator {
                return totalCG;
        }
        
-       
        /**
         * Return the longitudinal inertia of the rocket with the specified motor instance
         * configuration.
@@ -111,6 +114,7 @@ public class BasicMassCalculator extends AbstractMassCalculator {
         * @param configuration         the current motor instance configuration
         * @return                                      the longitudinal inertia of the rocket
         */
+       @Override
        public double getLongitudinalInertia(Configuration configuration, MotorInstanceConfiguration motors) {
                checkCache(configuration);
                calculateStageCache(configuration);
@@ -154,6 +158,7 @@ public class BasicMassCalculator extends AbstractMassCalculator {
         * @param configuration         the current motor instance configuration
         * @return                                      the rotational inertia of the rocket
         */
+       @Override
        public double getRotationalInertia(Configuration configuration, MotorInstanceConfiguration motors) {
                checkCache(configuration);
                calculateStageCache(configuration);
@@ -190,8 +195,26 @@ public class BasicMassCalculator extends AbstractMassCalculator {
                return totalInertia;
        }
        
+       /**
+        * Return the total mass of the motors
+        * 
+        * @param configuration         the current motor instance configuration
+        * @return                                      the total mass of all motors
+        */
+       @Override
+       public double getPropellantMass(Configuration configuration, MotorInstanceConfiguration motors){
+               double mass = 0;
+                               
+               // add up the masses of all motors in the rocket
+               if (motors != null) {
+                       for (MotorId id : motors.getMotorIDs()) {
+                               MotorInstance motor = motors.getMotorInstance(id);                                      
+                               mass = mass + motor.getCG().weight - motor.getParentMotor().getEmptyCG().weight;
+                       }
+               }
+               return mass;
+       }
        
-
        @Override
        public Map<RocketComponent, Coordinate> getCGAnalysis(Configuration configuration, MassCalcType type) {
                checkCache(configuration);
index 003650e11603ae6bbc5ae8b88ce82785dfa61557..5e657f7ab6006909aa342aa0fd63981c08c1ef74 100644 (file)
@@ -70,6 +70,14 @@ public interface MassCalculator extends Monitorable {
         */
        public double getRotationalInertia(Configuration configuration, MotorInstanceConfiguration motors);
        
+       /**
+        * Return the total mass of the motors
+        * 
+        * @param motors                        the motor configuration
+        * @param configuration         the current motor instance configuration
+        * @return                                      the total mass of all motors
+        */
+       public double getPropellantMass(Configuration configuration, MotorInstanceConfiguration motors);        
        
        /**
         * Compute an analysis of the per-component CG's of the provided configuration.
index 00be68b1c3cdce191dfe53b035d13d31fc086a60..055fc336b60768060132e3399f7a5472bb377305 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.material;
 
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.Unit;
 import net.sf.openrocket.unit.UnitGroup;
 import net.sf.openrocket.util.MathUtil;
@@ -16,16 +18,18 @@ import net.sf.openrocket.util.MathUtil;
 
 public abstract class Material implements Comparable<Material> {
        
+       private static final Translator trans = Application.getTranslator();
+       
        public enum Type {
-               LINE("Line", UnitGroup.UNITS_DENSITY_LINE),
-               SURFACE("Surface", UnitGroup.UNITS_DENSITY_SURFACE),
-               BULK("Bulk", UnitGroup.UNITS_DENSITY_BULK);
+               LINE("Databases.materials.types.Line", UnitGroup.UNITS_DENSITY_LINE),
+               SURFACE("Databases.materials.types.Surface", UnitGroup.UNITS_DENSITY_SURFACE),
+               BULK("Databases.materials.types.Bulk", UnitGroup.UNITS_DENSITY_BULK);
                
                private final String name;
                private final UnitGroup units;
                
-               private Type(String name, UnitGroup units) {
-                       this.name = name;
+               private Type(String nameKey, UnitGroup units) {
+                       this.name = trans.get(nameKey);
                        this.units = units;
                }
                
@@ -43,7 +47,7 @@ public abstract class Material implements Comparable<Material> {
        /////  Definitions of different material types  /////
        
        public static class Line extends Material {
-               public Line(String name, double density, boolean userDefined) {
+               Line(String name, double density, boolean userDefined) {
                        super(name, density, userDefined);
                }
                
@@ -55,7 +59,7 @@ public abstract class Material implements Comparable<Material> {
        
        public static class Surface extends Material {
                
-               public Surface(String name, double density, boolean userDefined) {
+               Surface(String name, double density, boolean userDefined) {
                        super(name, density, userDefined);
                }
                
@@ -71,7 +75,7 @@ public abstract class Material implements Comparable<Material> {
        }
        
        public static class Bulk extends Material {
-               public Bulk(String name, double density, boolean userDefined) {
+               Bulk(String name, double density, boolean userDefined) {
                        super(name, density, userDefined);
                }
                
@@ -82,20 +86,26 @@ public abstract class Material implements Comparable<Material> {
        }
        
        
-
+       
        private final String name;
        private final double density;
        private final boolean userDefined;
        
        
-       public Material(String name, double density, boolean userDefined) {
+       /**
+        * Constructor for materials.
+        * 
+        * @param name ignored when defining system materials.
+        * @param key ignored when defining user materials.
+        * @param density
+        * @param userDefined true if this is a user defined material, false if it is a system material.
+        */
+       private Material(String name, double density, boolean userDefined) {
                this.name = name;
-               this.density = density;
                this.userDefined = userDefined;
+               this.density = density;
        }
        
-       
-
        public double getDensity() {
                return density;
        }
@@ -159,10 +169,15 @@ public abstract class Material implements Comparable<Material> {
        
        
        /**
-        * Return a new material of the specified type.
+        * Return a new material.  The name is used as-is, without any translation.
+        * 
+        * @param type                  the material type
+        * @param name                  the material name
+        * @param density               the material density
+        * @param userDefined   whether the material is user-defined or not
+        * @return                              the new material
         */
-       public static Material newMaterial(Type type, String name, double density,
-                       boolean userDefined) {
+       public static Material newMaterial(Type type, String name, double density, boolean userDefined) {
                switch (type) {
                case LINE:
                        return new Material.Line(name, density, userDefined);
@@ -178,7 +193,6 @@ public abstract class Material implements Comparable<Material> {
                }
        }
        
-       
        public String toStorableString() {
                return getType().name() + "|" + name.replace('|', ' ') + '|' + density;
        }
index 6b7eb2b7c3f258f45a97758bff78e6dd361e8c54..eef78b00586d2aacccba042b3f511a95458a7df5 100644 (file)
@@ -115,8 +115,7 @@ public class ExtendedISAModel extends InterpolatingAtmosphericModel {
                        AtmosphericConditions diff = new AtmosphericConditions();
                        diff.setPressure((cond2.getPressure() - cond1.getPressure()) / cond1.getPressure() * 100);
                        diff.setTemperature((cond2.getTemperature() - cond1.getTemperature()) / cond1.getTemperature() * 100);
-                       System.out.println("alt=" + alt +
-                                       ": std:" + cond1 + " mod:" + cond2 + " diff:" + diff);
+                       //System.out.println("alt=" + alt +     ": std:" + cond1 + " mod:" + cond2 + " diff:" + diff);
                }
        }
        
index 831181bbfae3033dd04a38b6c2345243ad15ed3b..5d562ed7c72799e7f88a26a77d45e27281dfe326 100644 (file)
@@ -4,7 +4,9 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * Class containing information about motor manufacturers.
@@ -12,8 +14,22 @@ import java.util.Set;
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public class Manufacturer {
-       
-       private static Set<Manufacturer> manufacturers = new HashSet<Manufacturer>();
+
+       private static class ManufacturerList extends ConcurrentHashMap<String,Manufacturer> {
+               
+               void add( Manufacturer m ) {
+                       for( String s : m.getSearchNames() ) {
+                               Manufacturer previousRegistered;
+                               if ( (previousRegistered = putIfAbsent( s, m )) != null ) {
+                                       throw new IllegalStateException("Manufacturer name clash between " +
+                                                       "manufacturers " + previousRegistered + " and " + m + " name " + s);
+                               }
+                       }
+               }
+               
+       }
+       private static ManufacturerList manufacturers = new ManufacturerList();
+
        static {
                
                // AeroTech has many name combinations...
@@ -98,24 +114,10 @@ public class Manufacturer {
                                "WECO", "WECO FEUERWERKS", "SF", "SACHSEN", "SACHSEN FEUERWERK",
                                "SACHSEN FEUERWERKS"));
                
-
-               // Check that no duplicates have appeared
-               for (Manufacturer m1 : manufacturers) {
-                       for (Manufacturer m2 : manufacturers) {
-                               if (m1 == m2)
-                                       continue;
-                               for (String name : m1.getAllNames()) {
-                                       if (m2.matches(name)) {
-                                               throw new IllegalStateException("Manufacturer name clash between " +
-                                                               "manufacturers " + m1 + " and " + m2 + " name " + name);
-                                       }
-                               }
-                       }
-               }
        }
        
-
-
+       
+       
        private final String displayName;
        private final String simpleName;
        private final Set<String> allNames;
@@ -181,6 +183,9 @@ public class Manufacturer {
                return allNames;
        }
        
+       Set<String> getSearchNames() {
+               return searchNames;
+       }
        
        /**
         * Return the motor type that this manufacturer produces if it produces only one motor type.
@@ -228,22 +233,29 @@ public class Manufacturer {
         * @param name  the manufacturer name to search for.
         * @return              the Manufacturer object corresponding the name.
         */
-       public static synchronized Manufacturer getManufacturer(String name) {
-               for (Manufacturer m : manufacturers) {
-                       if (m.matches(name))
-                               return m;
+       public static Manufacturer getManufacturer(String name) {
+               String searchString = generateSearchString(name);
+               Manufacturer m = manufacturers.get(searchString);
+               if ( m != null ) {
+                       return m;
+               }
+
+               m = new Manufacturer(name.trim(), name.trim(), Motor.Type.UNKNOWN);
+
+               // We need some additional external synchronization here so we lock on the manufacturers.
+               synchronized( manufacturers ) {
+                       Manufacturer retest = manufacturers.get(searchString);
+                       if ( retest != null ) {
+                               // it exists now.
+                               return retest;
+                       }
+                       manufacturers.add(m);
                }
-               
-               Manufacturer m = new Manufacturer(name.trim(), name.trim(), Motor.Type.UNKNOWN);
-               manufacturers.add(m);
                return m;
        }
        
-       
-
-
-       private String generateSearchString(String str) {
-               return str.toLowerCase().replaceAll("[^a-zA-Z0-9]+", " ").trim();
+       private static String generateSearchString(String str) {
+               return str.toLowerCase(Locale.getDefault()).replaceAll("[^a-zA-Z0-9]+", " ").trim();
        }
        
 }
index 6b48e3a4b4c3286ec7288914f412b9e0dab4d1e1..ab474a8e946973b6832de70101bcc9d2d6187437 100644 (file)
@@ -56,5 +56,8 @@ public interface MotorInstance extends Cloneable, Monitorable {
         * identical to this instance and can be used independently from this one.
         */
        public MotorInstance clone();
+
+
+       public Motor getParentMotor();
        
 }
index e1ba1d77ca6c7b6f02d8aa4e5870e8a39b6fd107..e795c82308f9197fb241dd01a6fdd290e40a1594 100644 (file)
@@ -7,6 +7,7 @@ import java.util.Locale;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
 import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.ArrayUtils;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.Inertia;
@@ -43,6 +44,31 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor> {
        private double averageThrust;
        private double totalImpulse;
        
+       /**
+        * Deep copy constructor.
+        * Constructs a new ThrustCurveMotor from an existing ThrustCurveMotor.
+        * @param m
+        */
+       protected ThrustCurveMotor( ThrustCurveMotor m ) {
+               this.digest = m.digest;
+               this.manufacturer = m.manufacturer;
+               this.designation = m.designation;
+               this.description = m.description;
+               this.type = m.type;
+               this.delays = ArrayUtils.copyOf(m.delays, m.delays.length);
+               this.diameter = m.diameter;
+               this.length = m.length;
+               this.time = ArrayUtils.copyOf(m.time, m.time.length);
+               this.thrust = ArrayUtils.copyOf(m.thrust, m.thrust.length);
+               this.cg = new Coordinate[ m.cg.length ];
+               for( int i = 0; i< cg.length; i++ ) {
+                       this.cg[i] = m.cg[i].clone();
+               }
+               this.maxThrust = m.maxThrust;
+               this.burnTime = m.burnTime;
+               this.averageThrust = m.averageThrust;
+               this.totalImpulse = m.totalImpulse;
+       }
        
        /**
         * Sole constructor.  Sets all the properties of the motor.
@@ -398,6 +424,7 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor> {
                
                private final double unitRotationalInertia;
                private final double unitLongitudinalInertia;
+               private final Motor parentMotor;
                
                private int modID = 0;
                
@@ -411,6 +438,12 @@ public class ThrustCurveMotor implements Motor, Comparable<ThrustCurveMotor> {
                        stepCG = cg[0];
                        unitRotationalInertia = Inertia.filledCylinderRotational(getDiameter() / 2);
                        unitLongitudinalInertia = Inertia.filledCylinderLongitudinal(getDiameter() / 2, getLength());
+                       parentMotor = ThrustCurveMotor.this;
+               }
+               
+               @Override
+               public Motor getParentMotor(){
+                       return parentMotor;
                }
                
                @Override
index 07724c8fd4c6b3586a3c408051ba8d573fefd53b..b5e2eaee4d507ebb9b73754d216404a3f7f68023 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.optimization.rocketoptimization.modifiers;
 
+import java.util.Locale;
+
 import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.optimization.general.OptimizationException;
@@ -53,7 +55,7 @@ public abstract class GenericModifier<T> extends AbstractSimulationModifier {
                }
                
                try {
-                       methodName = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);
+                       methodName = methodName.substring(0, 1).toUpperCase(Locale.ENGLISH) + methodName.substring(1);
                        getter = new Method(modifiedClass.getMethod("get" + methodName));
                        setter = new Method(modifiedClass.getMethod("set" + methodName, double.class));
                } catch (SecurityException e) {
@@ -64,7 +66,7 @@ public abstract class GenericModifier<T> extends AbstractSimulationModifier {
        }
        
        
-
+       
        @Override
        public double getCurrentSIValue(Simulation simulation) throws OptimizationException {
                T modifiable = getModifiedObject(simulation);
@@ -97,7 +99,7 @@ public abstract class GenericModifier<T> extends AbstractSimulationModifier {
        protected abstract T getModifiedObject(Simulation simulation) throws OptimizationException;
        
        
-
+       
        @Override
        public String toString() {
                return "GenericModifier[modifiedClass=" + modifiedClass.getCanonicalName() + ", methodName=" + methodName + ", multiplier=" + multiplier + "]";
index 565330aae1b25d7f36ee4a7408b6aca0e23b96d0..cf77e3c579bd14a25ef0b69edb3f48dcd67209e6 100644 (file)
@@ -4,6 +4,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import net.sf.openrocket.document.OpenRocketDocument;
@@ -41,7 +42,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
        
        private static final double DEFAULT_RANGE_MULTIPLIER = 2.0;
        
-
+       
        private static final Map<Class<?>, List<ModifierDefinition>> definitions = new HashMap<Class<?>, List<ModifierDefinition>>();
        static {
                //addModifier("optimization.modifier.", unitGroup, multiplier, componentClass, methodName);
@@ -51,7 +52,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                 * For example, body tube does not have inner diameter definition because it is
                 * defined by the outer diameter and thickness.
                 */
-
+               
                addModifier("optimization.modifier.nosecone.length", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Length");
                addModifier("optimization.modifier.nosecone.diameter", UnitGroup.UNITS_LENGTH, 2.0, NoseCone.class, "AftRadius", "isAftRadiusAutomatic");
                addModifier("optimization.modifier.nosecone.thickness", UnitGroup.UNITS_LENGTH, 1.0, NoseCone.class, "Thickness", "isFilled");
@@ -81,7 +82,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                addModifier("optimization.modifier.launchlug.outerDiameter", UnitGroup.UNITS_LENGTH, 2.0, LaunchLug.class, "OuterRadius");
                addModifier("optimization.modifier.launchlug.thickness", UnitGroup.UNITS_LENGTH, 1.0, LaunchLug.class, "Thickness");
                
-
+               
                addModifier("optimization.modifier.masscomponent.mass", UnitGroup.UNITS_MASS, 1.0, MassComponent.class, "ComponentMass");
                
                addModifier("optimization.modifier.parachute.diameter", UnitGroup.UNITS_LENGTH, 1.0, Parachute.class, "Diameter");
@@ -100,7 +101,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
        }
        
        private static void addModifier(String modifierNameKey, UnitGroup unitGroup, double multiplier,
-                               Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
+                       Class<? extends RocketComponent> componentClass, String methodName, String autoMethod) {
                
                String modifierDescriptionKey = modifierNameKey + ".desc";
                
@@ -116,8 +117,8 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
        }
        
        
-
-
+       
+       
        @Override
        public Collection<SimulationModifier> getModifiers(OpenRocketDocument document) {
                List<SimulationModifier> modifiers = new ArrayList<SimulationModifier>();
@@ -151,7 +152,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                                }
                        }
                        
-
+                       
                        // Add override modifiers if mass/CG is overridden
                        if (c.isMassOverridden()) {
                                SimulationModifier mod = new GenericComponentModifier(
@@ -173,7 +174,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                                modifiers.add(mod);
                        }
                        
-
+                       
                        // Conditional motor mount parameters
                        if (c instanceof MotorMount) {
                                MotorMount mount = (MotorMount) c;
@@ -199,7 +200,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                                }
                        }
                        
-
+                       
                        // Inner component positioning
                        if (c instanceof InternalComponent) {
                                RocketComponent parent = c.getParent();
@@ -213,7 +214,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                                modifiers.add(mod);
                        }
                        
-
+                       
                        // Custom min/max for fin set position
                        if (c instanceof FinSet) {
                                RocketComponent parent = c.getParent();
@@ -227,7 +228,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                                modifiers.add(mod);
                        }
                        
-
+                       
                        // Custom min/max for launch lug position
                        if (c instanceof LaunchLug) {
                                RocketComponent parent = c.getParent();
@@ -241,7 +242,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                                modifiers.add(mod);
                        }
                        
-
+                       
                        // Recovery device deployment altitude and delay
                        if (c instanceof RecoveryDevice) {
                                RecoveryDevice device = (RecoveryDevice) c;
@@ -266,15 +267,15 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
                                }
                        }
                        
-
+                       
                        // Conditional shape parameter of Transition
                        if (c instanceof Transition) {
                                Transition transition = (Transition) c;
                                Transition.Shape shape = transition.getType();
                                if (shape.usesParameter()) {
                                        SimulationModifier mod = new GenericComponentModifier(
-                                                       trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase() + ".shapeparameter"),
-                                                       trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase() + ".shapeparameter.desc"),
+                                                       trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase(Locale.ENGLISH) + ".shapeparameter"),
+                                                       trans.get("optimization.modifier." + c.getClass().getSimpleName().toLowerCase(Locale.ENGLISH) + ".shapeparameter.desc"),
                                                        c, UnitGroup.UNITS_NONE,
                                                        1.0, c.getClass(), c.getID(), "ShapeParameter");
                                        mod.setMinValue(shape.minParameter());
@@ -303,7 +304,7 @@ public class DefaultSimulationModifierService implements SimulationModifierServi
         * String modifierName, Object relatedObject, UnitGroup unitGroup,
                        double multiplier, Class<? extends RocketComponent> componentClass, String componentId, String methodName
         */
-
+       
        private static class ModifierDefinition {
                private final String modifierNameKey;
                private final String modifierDescriptionKey;
index 152ccaf760e639657855e6579c636e5ea989c69c..ad2d6401c8b313c5c1a252109d7bf380827ffddf 100644 (file)
@@ -8,8 +8,6 @@ import java.util.ServiceLoader;
 import net.sf.openrocket.document.OpenRocketDocument;
 import net.sf.openrocket.optimization.rocketoptimization.OptimizableParameter;
 import net.sf.openrocket.optimization.rocketoptimization.SimulationModifier;
-import net.sf.openrocket.rocketcomponent.Rocket;
-import net.sf.openrocket.util.TestRockets;
 
 public final class OptimizationServiceHelper {
        
@@ -37,7 +35,7 @@ public final class OptimizationServiceHelper {
        }
        
        
-
+       
        /**
         * Return the optimization parameters for an OpenRocketDocument.  This queries the
         * getParameters() method from all available services and returns a collection of all
@@ -58,10 +56,4 @@ public final class OptimizationServiceHelper {
        }
        
        
-       public static void main(String[] args) {
-               Rocket r = TestRockets.makeBigBlue();
-               OpenRocketDocument document = new OpenRocketDocument(r);
-               System.out.println("Simulation modifiers: " + getSimulationModifiers(document));
-               System.out.println("Optimization parameters: " + getOptimizableParameters(document));
-       }
 }
diff --git a/core/src/net/sf/openrocket/plugin/Configurable.java b/core/src/net/sf/openrocket/plugin/Configurable.java
new file mode 100644 (file)
index 0000000..b8ebf6e
--- /dev/null
@@ -0,0 +1,29 @@
+package net.sf.openrocket.plugin;
+
+public interface Configurable {
+       
+       
+       /**
+        * Return the plugin ID.  This is a text string uniquely identifying this plugin.
+        * The recommended format is similar to the fully-qualified class name of the
+        * plugin, though a shorter format starting with the developer's domain name
+        * is also possible for future compatibility.
+        * 
+        * @return      the plugin ID
+        */
+       public String getPluginID();
+       
+       /**
+        * Test whether this plugin provides functionality corresponding to the specified
+        * plugin ID.  This provides backwards compatibility if the plugin ID should change.
+        * 
+        * @param pluginID      the plugin ID to test
+        * @return                      whether this plugin provides the requested functionality
+        */
+       public boolean isCompatible(String pluginID);
+       
+       public void loadFromXML(Object... objects);
+       
+       public void saveToXML(Object... objects);
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/SwingConfigurator.java b/core/src/net/sf/openrocket/plugin/SwingConfigurator.java
new file mode 100644 (file)
index 0000000..86ba323
--- /dev/null
@@ -0,0 +1,37 @@
+package net.sf.openrocket.plugin;
+
+import java.awt.Component;
+
+import net.xeoh.plugins.base.Plugin;
+
+/**
+ * Interface that defined a Swing configurator for a plugin.
+ * The implemeting class should be a plugin that provides the
+ * capability "<pluginID>:config" where <pluginID> is the
+ * plugin ID of the plugin to configure.
+ * <p>
+ * 
+ * @param <P> The plugin class that is being configured
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public interface SwingConfigurator<P> extends Plugin {
+       
+       /**
+        * Return whether this plugin is configurable or not.
+        * 
+        * @param plugin        the plugin to test.
+        * @return                      whether the plugin has a configuration component.
+        */
+       public boolean isConfigurable(P plugin);
+       
+       /**
+        * Return the configuration component for configuring the
+        * provided plugin.
+        * 
+        * @param plugin        the plugin to configure.
+        * @return                      a Swing component for configuring the plugin.
+        */
+       public Component getConfigurationComponent(P plugin);
+       
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/example/AirStartSimulationExtension.java b/core/src/net/sf/openrocket/plugin/example/AirStartSimulationExtension.java
new file mode 100644 (file)
index 0000000..7d14f5f
--- /dev/null
@@ -0,0 +1,42 @@
+package net.sf.openrocket.plugin.example;
+
+import java.awt.Component;
+
+public class AirStartSimulationExtension extends OpenRocketSimulationListener {
+       
+       @Override
+       public String getName() {
+               return "Air-start";
+       }
+       
+       @Override
+       public String[] getMenuPosition() {
+               return null;
+       }
+       
+       @Override
+       public void loadFromXML(Object... objects) {
+               // TODO Auto-generated method stub
+               
+       }
+       
+       @Override
+       public void saveToXML(Object... objects) {
+               // TODO Auto-generated method stub
+               
+       }
+       
+       @Override
+       public boolean isConfigurable() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+       
+       @Override
+       public Component getConfigurationComponent() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+       
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/example/ExampleMain.java b/core/src/net/sf/openrocket/plugin/example/ExampleMain.java
new file mode 100644 (file)
index 0000000..aea94be
--- /dev/null
@@ -0,0 +1,21 @@
+package net.sf.openrocket.plugin.example;
+
+import net.sf.openrocket.plugin.framework.JSPFPluginFactory;
+import net.sf.openrocket.plugin.framework.PluginFactory;
+
+public class ExampleMain {
+       
+       
+       public static void main(String[] args) {
+               PluginFactory factory = new JSPFPluginFactory();
+               
+               System.out.println("Plugins:");
+               System.out.println("---------");
+               for (ExamplePluginInterface plugin : factory.getPlugins(ExamplePluginInterface.class)) {
+                       plugin.print();
+               }
+               System.out.println("---------");
+       }
+       
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/example/ExamplePlugin.java b/core/src/net/sf/openrocket/plugin/example/ExamplePlugin.java
new file mode 100644 (file)
index 0000000..4579f9e
--- /dev/null
@@ -0,0 +1,17 @@
+package net.sf.openrocket.plugin.example;
+
+
+public class ExamplePlugin implements ExamplePluginInterface {
+       
+       private final String str;
+       
+       public ExamplePlugin(String str) {
+               this.str = str;
+       }
+       
+       @Override
+       public void print() {
+               System.out.println("ExamplePlugin: " + str);
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/example/ExamplePluginInterface.java b/core/src/net/sf/openrocket/plugin/example/ExamplePluginInterface.java
new file mode 100644 (file)
index 0000000..ddf157d
--- /dev/null
@@ -0,0 +1,9 @@
+package net.sf.openrocket.plugin.example;
+
+import net.xeoh.plugins.base.Plugin;
+
+public interface ExamplePluginInterface extends Plugin {
+       
+       public void print();
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/example/ExampleService.java b/core/src/net/sf/openrocket/plugin/example/ExampleService.java
new file mode 100644 (file)
index 0000000..8a6317b
--- /dev/null
@@ -0,0 +1,24 @@
+package net.sf.openrocket.plugin.example;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.openrocket.plugin.framework.AbstractService;
+import net.xeoh.plugins.base.annotations.PluginImplementation;
+
+@PluginImplementation
+public class ExampleService extends AbstractService<ExamplePluginInterface> {
+       
+       protected ExampleService() {
+               super(ExamplePluginInterface.class);
+       }
+       
+       @Override
+       protected List<ExamplePluginInterface> getPlugins(Object... args) {
+               List<ExamplePluginInterface> plugins = new ArrayList<ExamplePluginInterface>();
+               plugins.add(new ExamplePlugin("a"));
+               plugins.add(new ExamplePlugin("b"));
+               return plugins;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/example/ExampleSingletonPlugin.java b/core/src/net/sf/openrocket/plugin/example/ExampleSingletonPlugin.java
new file mode 100644 (file)
index 0000000..aa01518
--- /dev/null
@@ -0,0 +1,13 @@
+package net.sf.openrocket.plugin.example;
+
+import net.xeoh.plugins.base.annotations.PluginImplementation;
+
+@PluginImplementation
+public class ExampleSingletonPlugin implements ExamplePluginInterface {
+       
+       @Override
+       public void print() {
+               System.out.println("ExampleSingletonPlugin");
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/example/OpenRocketSimulationListener.java b/core/src/net/sf/openrocket/plugin/example/OpenRocketSimulationListener.java
new file mode 100644 (file)
index 0000000..ea178c0
--- /dev/null
@@ -0,0 +1,88 @@
+package net.sf.openrocket.plugin.example;
+
+import java.awt.Component;
+import java.util.Arrays;
+import java.util.List;
+
+import net.sf.openrocket.plugin.Configurable;
+import net.sf.openrocket.plugin.SwingConfigurator;
+import net.sf.openrocket.plugin.framework.Service;
+import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
+import net.sf.openrocket.util.BugException;
+import net.xeoh.plugins.base.Plugin;
+import net.xeoh.plugins.base.annotations.Capabilities;
+
+public abstract class OpenRocketSimulationListener extends AbstractSimulationListener
+               implements Plugin, Service, SwingConfigurator<OpenRocketSimulationListener>, Configurable {
+       
+       private final String[] ids;
+       private final String[] capabilities;
+       
+       public OpenRocketSimulationListener(String... ids) {
+               if (ids.length == 0) {
+                       ids = new String[] { this.getClass().getCanonicalName() };
+               }
+               
+               this.ids = ids.clone();
+               this.capabilities = new String[ids.length * 2];
+               for (int i = 0; i < ids.length; i++) {
+                       capabilities[i * 2] = ids[i] + ":service";
+                       capabilities[i * 2 + 1] = ids[i] + ":config";
+               }
+               
+       }
+       
+       @Capabilities
+       public String[] capabilities() {
+               return capabilities.clone();
+       }
+       
+       @SuppressWarnings("unchecked")
+       @Override
+       public <E> List<E> getPlugins(Class<E> e, Object... args) {
+               if (e != this.getClass()) {
+                       throw new BugException("Attempting to get plugin of type " + e + " but I am of type " + this.getClass());
+               }
+               try {
+                       return (List<E>) Arrays.asList(this.getClass().newInstance());
+               } catch (IllegalAccessException e1) {
+                       throw new BugException("Could not instantiate new object of type " + this.getClass(), e1);
+               } catch (InstantiationException e2) {
+                       throw new BugException("Could not instantiate new object of type " + this.getClass(), e2);
+               }
+       }
+       
+       
+       @Override
+       public boolean isConfigurable(OpenRocketSimulationListener plugin) {
+               return plugin.isConfigurable();
+       }
+       
+       @Override
+       public Component getConfigurationComponent(OpenRocketSimulationListener plugin) {
+               return plugin.getConfigurationComponent();
+       }
+       
+       public abstract boolean isConfigurable();
+       
+       public abstract Component getConfigurationComponent();
+       
+       
+       
+       @Override
+       public String getPluginID() {
+               return ids[0];
+       }
+       
+       @Override
+       public boolean isCompatible(String pluginID) {
+               for (String id : ids) {
+                       if (pluginID.equals(id)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/example/stuff.txt b/core/src/net/sf/openrocket/plugin/example/stuff.txt
new file mode 100644 (file)
index 0000000..e4a4fc3
--- /dev/null
@@ -0,0 +1,135 @@
+
+
+
+Plugin:
+
+foo()
+bar()
+getValue()
+setValue()
+
+
+
+Service:
+
+getPlugins(args...)
+capabilities()  ->  "pluginid:service"
+
+
+
+SwingConfigurator:
+
+getConfigurationComponent(plugin)
+capabilities()  ->  "pluginid:config"
+
+
+
+
+OpenRocketSimulationListener extends SimulationListener implements Service, SwingConfigurator:
+
+
+constructor:
+  pluginid = class name
+  
+
+getPlugins():
+  return new this
+
+capabilities: pluginid:service, pluginid:config
+
+getConfigurationComponent(plugin)
+  plugin.getConfigurationComponent()
+
+abstract getConfigurationComponent()
+
+
+
+
+
+Types of plugins:
+
+
+AtmosphericModel
+ - Name -> dropdown
+ - Config component -> dialog window (or button)
+ - stateful, non-dynamic
+ - stored
+
+SimulationListener
+ - Name + menu position -> Add extension menu
+ - Config component -> dialog after edit button
+ - stateful, (dynamic?)
+ - stored
+
+OptimizationModifier
+ - contains its own name, description, related object
+ - config N/A
+ - stateful, dynamic
+ - not stored
+OptimizationParameter
+ - name
+ - config N/A
+ - stateful, (dynamic?)
+ - not stored
+
+PluginDialogWindow
+ - name + menu position -> Menu
+ - stateful, non-dynamic
+ - not stored
+
+Motor
+ - Name -> Config tab
+ - Config component -> tab contents ????
+ - or a separate configuration interface?
+ - stored
+
+
+
+Name is common  -  out, instead have name separately in plugin interfaces?
+Menu position used twice  -  out
+
+Leave common configuration out
+ -> :config supported by those that make sense
+ -> may have separate interface from SwingConfigurator (e.g. SwingMotorConfigurator)
+
+Motor
+ -> :loader separately?  for injecting placeholders
+    or store data and call loaders later
+
+
+
+
+<extension pluginid="com.example.MyFancyExtension">
+  <param type="double" key="altitude">100.0</param>
+  <param type="material" key="mat">
+    <name>Gold</name>
+    <type>bulk</type>
+    <density>16000</density>
+  </param>
+</extension>
+
+
+<extension pluginid="com.example.MyFancyExtension">
+  <param type="double" key="altitude">100.0</param>
+  <param type="material" key="mat">
+    <name>Gold</name>
+    <type>bulk</type>
+    <density>16000</density>
+  </param>
+</extension>
+
+
+<extension pluginid="com.example.MyFancyExtension">
+</extension>
+
+
+<extension pluginid="com.example.MyFancyExtension">
+</extension>
+
+
diff --git a/core/src/net/sf/openrocket/plugin/framework/AbstractService.java b/core/src/net/sf/openrocket/plugin/framework/AbstractService.java
new file mode 100644 (file)
index 0000000..eca8a2a
--- /dev/null
@@ -0,0 +1,45 @@
+package net.sf.openrocket.plugin.framework;
+
+import java.util.Collections;
+import java.util.List;
+
+import net.sf.openrocket.util.BugException;
+
+/**
+ * An abstract service implementation that returns plugins of type P.
+ * 
+ * @param <P>  the plugin type that this service returns.
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public abstract class AbstractService<P> implements Service {
+       
+       private final Class<P> type;
+       
+       protected AbstractService(Class<P> type) {
+               this.type = type;
+       }
+       
+       @SuppressWarnings("unchecked")
+       @Override
+       public <E> List<E> getPlugins(Class<E> e, Object... args) {
+               
+               if (e != type) {
+                       return Collections.emptyList();
+               }
+               
+               List<P> plugins = getPlugins(args);
+               
+               // Check list content types to avoid mysterious bugs later on
+               for (P p : plugins) {
+                       if (!type.isInstance(p)) {
+                               throw new BugException("Requesting plugins of type " + type + " but received " +
+                                               ((p != null) ? p.getClass() : "null"));
+                       }
+               }
+               
+               return (List<E>) plugins;
+       }
+       
+       protected abstract List<P> getPlugins(Object... args);
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/framework/JSPFPluginFactory.java b/core/src/net/sf/openrocket/plugin/framework/JSPFPluginFactory.java
new file mode 100644 (file)
index 0000000..f75cf36
--- /dev/null
@@ -0,0 +1,50 @@
+package net.sf.openrocket.plugin.framework;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.openrocket.util.BugException;
+import net.xeoh.plugins.base.Plugin;
+import net.xeoh.plugins.base.PluginManager;
+import net.xeoh.plugins.base.impl.PluginManagerFactory;
+import net.xeoh.plugins.base.util.JSPFProperties;
+import net.xeoh.plugins.base.util.PluginManagerUtil;
+
+public class JSPFPluginFactory implements PluginFactory {
+       
+       private final PluginManager pluginManager;
+       
+       public JSPFPluginFactory() {
+               
+               final JSPFProperties props = new JSPFProperties();
+               
+               //              props.setProperty(PluginManager.class, "cache.enabled", "true");
+               //              props.setProperty(PluginManager.class, "cache.mode", "weak"); //optional
+               //              props.setProperty(PluginManager.class, "cache.file", "jspf.cache");
+               
+               try {
+                       pluginManager = PluginManagerFactory.createPluginManager(props);
+                       pluginManager.addPluginsFrom(new URI("classpath://*"));
+               } catch (URISyntaxException e) {
+                       throw new BugException(e);
+               }
+       }
+       
+       @Override
+       public <E extends Plugin> List<E> getPlugins(Class<E> e, Object... args) {
+               
+               List<E> plugins = new ArrayList<E>();
+               
+               PluginManagerUtil pluginManagerUtil = new PluginManagerUtil(pluginManager);
+               plugins.addAll(pluginManagerUtil.getPlugins(e));
+               
+               for (Service s : pluginManagerUtil.getPlugins(Service.class)) {
+                       plugins.addAll(s.getPlugins(e, args));
+               }
+               
+               return plugins;
+               
+       }
+}
diff --git a/core/src/net/sf/openrocket/plugin/framework/PluginFactory.java b/core/src/net/sf/openrocket/plugin/framework/PluginFactory.java
new file mode 100644 (file)
index 0000000..25b6cbf
--- /dev/null
@@ -0,0 +1,11 @@
+package net.sf.openrocket.plugin.framework;
+
+import java.util.List;
+
+import net.xeoh.plugins.base.Plugin;
+
+public interface PluginFactory {
+       
+       public <E extends Plugin> List<E> getPlugins(Class<E> e, Object... args);
+       
+}
diff --git a/core/src/net/sf/openrocket/plugin/framework/Service.java b/core/src/net/sf/openrocket/plugin/framework/Service.java
new file mode 100644 (file)
index 0000000..ee56b8e
--- /dev/null
@@ -0,0 +1,30 @@
+package net.sf.openrocket.plugin.framework;
+
+import java.util.List;
+
+import net.xeoh.plugins.base.Plugin;
+
+/**
+ * A discovery service that returns plugins of a specified type with
+ * provided arguments.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public interface Service extends Plugin {
+       
+       /**
+        * Return the plugins that match the provided type and are applicable
+        * for the arguments.  The arguments depend on the class type.
+        * <p>
+        * This method may return different plugins for different arguments.
+        * For example, if the arguments contain the OpenRocketDocument, the
+        * service may return only plugins applicable for the specified document.
+        * 
+        * @param type  the plugin interface type
+        * @param args  arguments for the interface.
+        * @return              the plugin instances applicable.
+        */
+       public <E> List<E> getPlugins(Class<E> type, Object... args);
+       
+       
+}
index 87343e9351b9734992abe645c9776e969d592763..6e7bd7aaf4a4d60047609da7d6b56fca2f60318d 100644 (file)
 package net.sf.openrocket.preset;
 
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.security.MessageDigest;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.openrocket.material.Material;
 import net.sf.openrocket.motor.Manufacturer;
-import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
+import net.sf.openrocket.rocketcomponent.Transition.Shape;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.TextUtil;
+
 
 /**
  * A model for a preset component.
  * <p>
  * A preset component contains a component class type, manufacturer information,
  * part information, and a method that returns a prototype of the preset component.
- * 
+ *
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
-public abstract class ComponentPreset {
+public class ComponentPreset implements Comparable<ComponentPreset> {
        
-       private final Manufacturer manufacturer;
-       private final String partNo;
-       private final String partDescription;
-       private final RocketComponent prototype;
+       private final TypedPropertyMap properties = new TypedPropertyMap();
        
+       private String digest = "";
        
-       public ComponentPreset(Manufacturer manufacturer, String partNo, String partDescription,
-                       RocketComponent prototype) {
-               this.manufacturer = manufacturer;
-               this.partNo = partNo;
-               this.partDescription = partDescription;
-               this.prototype = prototype.copy();
+       public enum Type {
+               BODY_TUBE(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.INNER_DIAMETER,
+                               ComponentPreset.OUTER_DIAMETER,
+                               ComponentPreset.LENGTH }),
+               
+               NOSE_CONE(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.SHAPE,
+                               ComponentPreset.AFT_OUTER_DIAMETER,
+                               ComponentPreset.AFT_SHOULDER_DIAMETER,
+                               ComponentPreset.AFT_SHOULDER_LENGTH,
+                               ComponentPreset.LENGTH }),
+               
+               TRANSITION(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.SHAPE,
+                               ComponentPreset.FORE_OUTER_DIAMETER,
+                               ComponentPreset.FORE_SHOULDER_DIAMETER,
+                               ComponentPreset.FORE_SHOULDER_LENGTH,
+                               ComponentPreset.AFT_OUTER_DIAMETER,
+                               ComponentPreset.AFT_SHOULDER_DIAMETER,
+                               ComponentPreset.AFT_SHOULDER_LENGTH,
+                               ComponentPreset.LENGTH }),
+               
+               TUBE_COUPLER(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.OUTER_DIAMETER,
+                               ComponentPreset.INNER_DIAMETER,
+                               ComponentPreset.LENGTH }),
+               
+               BULK_HEAD(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.OUTER_DIAMETER,
+                               ComponentPreset.LENGTH }),
+               
+               CENTERING_RING(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.INNER_DIAMETER,
+                               ComponentPreset.OUTER_DIAMETER,
+                               ComponentPreset.LENGTH }),
                
-               if (prototype.getParent() != null) {
-                       throw new IllegalArgumentException("Prototype component cannot have a parent");
+               ENGINE_BLOCK(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.INNER_DIAMETER,
+                               ComponentPreset.OUTER_DIAMETER,
+                               ComponentPreset.LENGTH }),
+               
+               LAUNCH_LUG(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.INNER_DIAMETER,
+                               ComponentPreset.OUTER_DIAMETER,
+                               ComponentPreset.LENGTH }),
+               
+               STREAMER(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.LENGTH,
+                               ComponentPreset.WIDTH,
+                               ComponentPreset.THICKNESS,
+                               ComponentPreset.MATERIAL }),
+               
+               PARACHUTE(new TypedKey<?>[] {
+                               ComponentPreset.MANUFACTURER,
+                               ComponentPreset.PARTNO,
+                               ComponentPreset.DESCRIPTION,
+                               ComponentPreset.DIAMETER,
+                               ComponentPreset.SIDES,
+                               ComponentPreset.LINE_COUNT,
+                               ComponentPreset.LINE_LENGTH,
+                               ComponentPreset.LINE_MATERIAL,
+                               ComponentPreset.MATERIAL });
+               
+               TypedKey<?>[] displayedColumns;
+               
+               Type(TypedKey<?>[] displayedColumns) {
+                       this.displayedColumns = displayedColumns;
                }
-               if (prototype.getChildCount() > 0) {
-                       throw new IllegalArgumentException("Prototype component cannot have children");
+               
+               public List<Type> getCompatibleTypes() {
+                       return compatibleTypeMap.get(Type.this);
                }
+               
+               public TypedKey<?>[] getDisplayedColumns() {
+                       return displayedColumns;
+               }
+               
+               private static Map<Type, List<Type>> compatibleTypeMap = new HashMap<Type, List<Type>>();
+               
+               static {
+                       compatibleTypeMap.put(BODY_TUBE, Arrays.asList(BODY_TUBE, TUBE_COUPLER, LAUNCH_LUG));
+                       compatibleTypeMap.put(TUBE_COUPLER, Arrays.asList(BODY_TUBE, TUBE_COUPLER, LAUNCH_LUG));
+                       compatibleTypeMap.put(LAUNCH_LUG, Arrays.asList(BODY_TUBE, TUBE_COUPLER, LAUNCH_LUG));
+                       compatibleTypeMap.put(CENTERING_RING, Arrays.asList(CENTERING_RING, ENGINE_BLOCK));
+                       compatibleTypeMap.put(NOSE_CONE, Arrays.asList(NOSE_CONE, TRANSITION));
+               }
+               
        }
        
+       public final static TypedKey<Manufacturer> MANUFACTURER = new TypedKey<Manufacturer>("Manufacturer", Manufacturer.class);
+       public final static TypedKey<String> PARTNO = new TypedKey<String>("PartNo", String.class);
+       public final static TypedKey<String> DESCRIPTION = new TypedKey<String>("Description", String.class);
+       public final static TypedKey<Type> TYPE = new TypedKey<Type>("Type", Type.class);
+       public final static TypedKey<Double> LENGTH = new TypedKey<Double>("Length", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> WIDTH = new TypedKey<Double>("Width", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> INNER_DIAMETER = new TypedKey<Double>("InnerDiameter", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> OUTER_DIAMETER = new TypedKey<Double>("OuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> FORE_SHOULDER_LENGTH = new TypedKey<Double>("ForeShoulderLength", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> FORE_SHOULDER_DIAMETER = new TypedKey<Double>("ForeShoulderDiameter", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> FORE_OUTER_DIAMETER = new TypedKey<Double>("ForeOuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> AFT_SHOULDER_LENGTH = new TypedKey<Double>("AftShoulderLength", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> AFT_SHOULDER_DIAMETER = new TypedKey<Double>("AftShoulderDiameter", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Double> AFT_OUTER_DIAMETER = new TypedKey<Double>("AftOuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Shape> SHAPE = new TypedKey<Shape>("Shape", Shape.class);
+       public final static TypedKey<Material> MATERIAL = new TypedKey<Material>("Material", Material.class);
+       public final static TypedKey<Finish> FINISH = new TypedKey<Finish>("Finish", Finish.class);
+       public final static TypedKey<Double> THICKNESS = new TypedKey<Double>("Thickness", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Boolean> FILLED = new TypedKey<Boolean>("Filled", Boolean.class);
+       public final static TypedKey<Double> MASS = new TypedKey<Double>("Mass", Double.class, UnitGroup.UNITS_MASS);
+       public final static TypedKey<Double> DIAMETER = new TypedKey<Double>("Diameter", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Integer> SIDES = new TypedKey<Integer>("Sides", Integer.class);
+       public final static TypedKey<Integer> LINE_COUNT = new TypedKey<Integer>("LineCount", Integer.class);
+       public final static TypedKey<Double> LINE_LENGTH = new TypedKey<Double>("LineLength", Double.class, UnitGroup.UNITS_LENGTH);
+       public final static TypedKey<Material> LINE_MATERIAL = new TypedKey<Material>("LineMaterial", Material.class);
+       public final static TypedKey<byte[]> IMAGE = new TypedKey<byte[]>("Image", byte[].class);
+       
+       public final static List<TypedKey<?>> ORDERED_KEY_LIST = Collections.unmodifiableList(Arrays.<TypedKey<?>> asList(
+                       MANUFACTURER,
+                       PARTNO,
+                       DESCRIPTION,
+                       OUTER_DIAMETER,
+                       FORE_OUTER_DIAMETER,
+                       AFT_OUTER_DIAMETER,
+                       INNER_DIAMETER,
+                       LENGTH,
+                       WIDTH,
+                       AFT_SHOULDER_DIAMETER,
+                       AFT_SHOULDER_LENGTH,
+                       FORE_SHOULDER_DIAMETER,
+                       FORE_SHOULDER_LENGTH,
+                       SHAPE,
+                       THICKNESS,
+                       FILLED,
+                       DIAMETER,
+                       SIDES,
+                       LINE_COUNT,
+                       LINE_LENGTH,
+                       LINE_MATERIAL,
+                       MASS,
+                       FINISH,
+                       MATERIAL
+                       ));
+       
+       
+       // package scope constructor to encourage use of factory.
+       ComponentPreset() {
+       }
        
        /**
-        * Return the component class that this preset defines.
+        * Convenience method to retrieve the Type of this ComponentPreset.
+        *
+        * @return
         */
-       public Class<? extends RocketComponent> getComponentClass() {
-               return prototype.getClass();
+       public Type getType() {
+               return properties.get(TYPE);
        }
        
        /**
-        * Return the manufacturer of this preset component.
+        * Convenience method to retrieve the Manufacturer of this ComponentPreset.
+        * @return
         */
        public Manufacturer getManufacturer() {
-               return manufacturer;
+               return properties.get(MANUFACTURER);
        }
        
        /**
-        * Return the part number.  This is the part identifier (e.g. "BT-50").
+        * Convenience method to retrieve the PartNo of this ComponentPreset.
+        * @return
         */
        public String getPartNo() {
-               return partNo;
+               return properties.get(PARTNO);
+       }
+       
+       public String getDigest() {
+               return digest;
+       }
+       
+       public boolean has(Object key) {
+               return properties.containsKey(key);
        }
        
        /**
-        * Return the part description.  This is a longer description of the component.
+        * Package scope so the ComponentPresetFactory can call it.
+        * @param other
         */
-       public String getPartDescription() {
-               return partDescription;
+       void putAll(TypedPropertyMap other) {
+               if (other == null) {
+                       return;
+               }
+               properties.putAll(other);
        }
        
        /**
-        * Return a prototype component.  This component may be modified freely.
+        * Package scope so the ComponentPresetFactory can call it.
+        * @param key
+        * @param value
         */
-       public RocketComponent getPrototype() {
-               return prototype.copy();
+       <T> void put(TypedKey<T> key, T value) {
+               properties.put(key, value);
+       }
+       
+       public <T> T get(TypedKey<T> key) {
+               T value = properties.get(key);
+               if (value == null) {
+                       throw new BugException("Preset did not contain key " + key + " " + properties.toString());
+               }
+               return value;
+       }
+       
+       @Override
+       public int compareTo(ComponentPreset p2) {
+               int manuCompare = this.getManufacturer().getSimpleName().compareTo(p2.getManufacturer().getSimpleName());
+               if (manuCompare != 0)
+                       return manuCompare;
+               
+               int partNoCompare = this.getPartNo().compareTo(p2.getPartNo());
+               return partNoCompare;
+       }
+       
+       @Override
+       public String toString() {
+               return get(PARTNO);
+       }
+       
+       public String preferenceKey() {
+               return get(MANUFACTURER).toString() + "|" + get(PARTNO);
+       }
+       
+       @Override
+       public boolean equals(final Object o) {
+               if (this == o) {
+                       return true;
+               }
+               if (o == null || getClass() != o.getClass()) {
+                       return false;
+               }
+               
+               ComponentPreset that = (ComponentPreset) o;
+               
+               if (digest != null ? !digest.equals(that.digest) : that.digest != null) {
+                       return false;
+               }
+               
+               return true;
+       }
+       
+       @Override
+       public int hashCode() {
+               return digest != null ? digest.hashCode() : 0;
+       }
+       
+       /**
+        * Package scope so the factory can call it.
+        */
+       void computeDigest() {
+               
+               try {
+                       ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                       DataOutputStream os = new DataOutputStream(bos);
+                       
+                       List<TypedKey<?>> keys = new ArrayList<TypedKey<?>>(properties.keySet());
+                       
+                       Collections.sort(keys, new Comparator<TypedKey<?>>() {
+                               @Override
+                               public int compare(TypedKey<?> a, TypedKey<?> b) {
+                                       return a.getName().compareTo(b.getName());
+                               }
+                       });
+                       
+                       for (TypedKey<?> key : keys) {
+                               
+                               Object value = properties.get(key);
+                               
+                               os.writeBytes(key.getName());
+                               
+                               if (key.getType() == Double.class) {
+                                       Double d = (Double) value;
+                                       os.writeDouble(d);
+                               } else if (key.getType() == String.class) {
+                                       String s = (String) value;
+                                       os.writeBytes(s);
+                               } else if (key.getType() == Manufacturer.class) {
+                                       String s = ((Manufacturer) value).getSimpleName();
+                                       os.writeBytes(s);
+                               } else if (key.getType() == Finish.class) {
+                                       String s = ((Finish) value).name();
+                                       os.writeBytes(s);
+                               } else if (key.getType() == Type.class) {
+                                       String s = ((Type) value).name();
+                                       os.writeBytes(s);
+                               } else if (key.getType() == Boolean.class) {
+                                       Boolean b = (Boolean) value;
+                                       os.writeBoolean(b);
+                               } else if (key.getType() == Material.class) {
+                                       double d = ((Material) value).getDensity();
+                                       os.writeDouble(d);
+                               } else if (key.getType() == Shape.class) {
+                                       // this is ugly to use the ordinal but what else?
+                                       int i = ((Shape) value).ordinal();
+                                       os.writeInt(i);
+                               }
+                               
+                       }
+                       
+                       MessageDigest md5 = MessageDigest.getInstance("MD5");
+                       digest = TextUtil.hexString(md5.digest(bos.toByteArray()));
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new BugException(e);
+               }
        }
        
 }
diff --git a/core/src/net/sf/openrocket/preset/ComponentPresetFactory.java b/core/src/net/sf/openrocket/preset/ComponentPresetFactory.java
new file mode 100644 (file)
index 0000000..7d2677b
--- /dev/null
@@ -0,0 +1,280 @@
+package net.sf.openrocket.preset;
+
+import static net.sf.openrocket.preset.ComponentPreset.*;
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.rocketcomponent.Transition;
+
+public abstract class ComponentPresetFactory {
+       
+       public static ComponentPreset create(TypedPropertyMap props) throws InvalidComponentPresetException {
+               
+               InvalidComponentPresetException exceptions = new InvalidComponentPresetException("Invalid preset specification.");
+               
+               ComponentPreset preset = new ComponentPreset();
+               // First do validation.
+               if (!props.containsKey(MANUFACTURER)) {
+                       exceptions.addInvalidParameter(MANUFACTURER, "No Manufacturer specified");
+               }
+               if (!props.containsKey(PARTNO)) {
+                       exceptions.addInvalidParameter(PARTNO, "No PartNo specified");
+               }
+               if (!props.containsKey(TYPE)) {
+                       exceptions.addInvalidParameter(TYPE, "No Type specified");
+                       // We can't do anything else without TYPE so throw immediately.
+                       throw exceptions;
+               }
+               
+               
+               preset.putAll(props);
+               
+               // Should check for various bits of each of the types.
+               Type t = props.get(TYPE);
+               switch (t) {
+               case BODY_TUBE: {
+                       makeBodyTube(exceptions, preset);
+                       break;
+               }
+               case NOSE_CONE: {
+                       makeNoseCone(exceptions, preset);
+                       break;
+               }
+               case TRANSITION: {
+                       makeTransition(exceptions, preset);
+                       break;
+               }
+               case BULK_HEAD: {
+                       makeBulkHead(exceptions, preset);
+                       break;
+               }
+               case TUBE_COUPLER: {
+                       // For now TUBE_COUPLER is the same as BODY_TUBE
+                       makeBodyTube(exceptions, preset);
+                       break;
+               }
+               case CENTERING_RING: {
+                       makeCenteringRing(exceptions, preset);
+                       break;
+               }
+               case ENGINE_BLOCK: {
+                       makeEngineBlock(exceptions, preset);
+                       break;
+               }
+               case LAUNCH_LUG: {
+                       // Same processing as BODY_TUBE
+                       makeBodyTube(exceptions, preset);
+                       break;
+               }
+               case STREAMER: {
+                       makeStreamer(exceptions, preset);
+                       break;
+               }
+               case PARACHUTE: {
+                       makeParachute(exceptions, preset);
+                       break;
+               }
+               }
+               
+               if (exceptions.hasProblems()) {
+                       throw exceptions;
+               }
+               
+               preset.computeDigest();
+               
+               return preset;
+               
+       }
+       
+       private static void makeBodyTube(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
+               
+               checkRequiredFields(exceptions, preset, LENGTH);
+               
+               checkDiametersAndThickness(exceptions, preset);
+               
+               double volume = computeVolumeOfTube(preset);
+               
+               // Need to translate Mass to Density.
+               if (preset.has(MASS)) {
+                       String materialName = "TubeCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
+                       preset.put(MATERIAL, m);
+               }
+               
+               
+       }
+       
+       private static void makeNoseCone(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               
+               checkRequiredFields(exceptions, preset, LENGTH, SHAPE, AFT_OUTER_DIAMETER);
+               
+               if (preset.has(MASS)) {
+                       // compute a density for this component
+                       double mass = preset.get(MASS);
+                       NoseCone nc = new NoseCone();
+                       nc.loadPreset(preset);
+                       double density = mass / nc.getComponentVolume();
+                       
+                       String materialName = "NoseConeCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
+                       preset.put(MATERIAL, m);
+                       
+               }
+               
+       }
+       
+       private static void makeTransition(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               checkRequiredFields(exceptions, preset, LENGTH, AFT_OUTER_DIAMETER, FORE_OUTER_DIAMETER);
+               
+               if (preset.has(MASS)) {
+                       // compute a density for this component
+                       double mass = preset.get(MASS);
+                       Transition tr = new Transition();
+                       tr.loadPreset(preset);
+                       double density = mass / tr.getComponentVolume();
+                       
+                       String materialName = "TransitionCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
+                       preset.put(MATERIAL, m);
+                       
+               }
+               
+       }
+       
+       private static void makeBulkHead(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               checkRequiredFields(exceptions, preset, LENGTH, OUTER_DIAMETER);
+               
+               if (preset.has(MASS)) {
+                       // compute a density for this component
+                       double mass = preset.get(MASS);
+                       
+                       double volume = computeVolumeOfTube(preset);
+                       double density = mass / volume;
+                       
+                       String materialName = "BulkHeadCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, density);
+                       preset.put(MATERIAL, m);
+                       
+               }
+               
+       }
+       
+       private static void makeCenteringRing(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
+               checkRequiredFields(exceptions, preset, LENGTH);
+               
+               checkDiametersAndThickness(exceptions, preset);
+               
+               double volume = computeVolumeOfTube(preset);
+               
+               // Need to translate Mass to Density.
+               if (preset.has(MASS)) {
+                       String materialName = "CenteringRingCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
+                       preset.put(MATERIAL, m);
+               }
+               
+       }
+       
+       private static void makeEngineBlock(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
+               checkRequiredFields(exceptions, preset, LENGTH);
+               
+               checkDiametersAndThickness(exceptions, preset);
+               
+               double volume = computeVolumeOfTube(preset);
+               
+               // Need to translate Mass to Density.
+               if (preset.has(MASS)) {
+                       String materialName = "EngineBlockCustom";
+                       if (preset.has(MATERIAL)) {
+                               materialName = preset.get(MATERIAL).getName();
+                       }
+                       Material m = Databases.findMaterial(Material.Type.BULK, materialName, preset.get(MASS) / volume);
+                       preset.put(MATERIAL, m);
+               }
+               
+       }
+       
+       private static void makeStreamer(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               checkRequiredFields(exceptions, preset, LENGTH, WIDTH);
+       }
+       
+       private static void makeParachute(InvalidComponentPresetException exceptions, ComponentPreset preset) {
+               checkRequiredFields(exceptions, preset, DIAMETER, LINE_COUNT, LINE_LENGTH);
+       }
+       
+       
+       private static void checkRequiredFields(InvalidComponentPresetException exceptions, ComponentPreset preset, TypedKey<?>... keys) {
+               for (TypedKey<?> key : keys) {
+                       if (!preset.has(key)) {
+                               exceptions.addInvalidParameter(key, "No " + key.getName() + " specified");
+                       }
+               }
+       }
+       
+       private static void checkDiametersAndThickness(InvalidComponentPresetException exceptions, ComponentPreset preset) throws InvalidComponentPresetException {
+               // Need to verify contains 2 of OD, thickness, ID.  Compute the third.
+               boolean hasOd = preset.has(OUTER_DIAMETER);
+               boolean hasId = preset.has(INNER_DIAMETER);
+               boolean hasThickness = preset.has(THICKNESS);
+               
+               double outerRadius;
+               double innerRadius;
+               double thickness;
+               
+               if (hasOd) {
+                       outerRadius = preset.get(OUTER_DIAMETER) / 2.0;
+                       thickness = 0;
+                       if (hasId) {
+                               innerRadius = preset.get(INNER_DIAMETER) / 2.0;
+                               thickness = outerRadius - innerRadius;
+                       } else if (hasThickness) {
+                               thickness = preset.get(THICKNESS);
+                               innerRadius = outerRadius - thickness;
+                       } else {
+                               exceptions.addMessage("Preset dimensions underspecified");
+                               throw exceptions;
+                       }
+               } else {
+                       if (!hasId || !hasThickness) {
+                               exceptions.addMessage("Preset dimensions underspecified");
+                               throw exceptions;
+                       }
+                       innerRadius = preset.get(INNER_DIAMETER) / 2.0;
+                       thickness = preset.get(THICKNESS);
+                       outerRadius = innerRadius + thickness;
+               }
+               
+               preset.put(OUTER_DIAMETER, outerRadius * 2.0);
+               preset.put(INNER_DIAMETER, innerRadius * 2.0);
+               preset.put(THICKNESS, thickness);
+               
+       }
+       
+       private static double computeVolumeOfTube(ComponentPreset preset) {
+               double or = preset.get(OUTER_DIAMETER) / 2.0;
+               double ir = preset.has(INNER_DIAMETER) ? preset.get(INNER_DIAMETER) / 2.0 : 0.0;
+               double l = preset.get(LENGTH);
+               return Math.PI * (or * or - ir * ir) * l;
+       }
+       
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/InvalidComponentPresetException.java b/core/src/net/sf/openrocket/preset/InvalidComponentPresetException.java
new file mode 100644 (file)
index 0000000..c28fb09
--- /dev/null
@@ -0,0 +1,56 @@
+package net.sf.openrocket.preset;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InvalidComponentPresetException extends Exception {
+
+       private List<String> errors = new ArrayList<String>();
+       private List<TypedKey<?>> invalidParameters = new ArrayList<TypedKey<?>>();
+       
+       public InvalidComponentPresetException() {
+               super();
+       }
+
+       public InvalidComponentPresetException(String message, Throwable cause) {
+               super(message, cause);
+       }
+
+       public InvalidComponentPresetException(String message) {
+               super(message);
+       }
+
+       public InvalidComponentPresetException(Throwable cause) {
+               super(cause);
+       }
+       
+       void addInvalidParameter(TypedKey<?> key ) {
+               invalidParameters.add(key);
+       }
+       
+       void addInvalidParameter(TypedKey<?> key, String message ) {
+               invalidParameters.add(key);
+               errors.add(message);
+       }
+       
+       void addMessage( String message ) {
+               errors.add(message);
+       }
+
+       boolean hasProblems() {
+               return (invalidParameters.size() + errors.size()) > 0;
+       }
+       
+       public int problemCount() {
+               return Math.max( invalidParameters.size(), errors.size() );
+       }
+       
+       public List<String> getErrors() {
+               return errors;
+       }
+
+       public List<TypedKey<?>> getInvalidParameters() {
+               return invalidParameters;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/TypedKey.java b/core/src/net/sf/openrocket/preset/TypedKey.java
new file mode 100644 (file)
index 0000000..c3e4473
--- /dev/null
@@ -0,0 +1,69 @@
+package net.sf.openrocket.preset;
+
+import net.sf.openrocket.unit.UnitGroup;
+
+public class TypedKey<T> {
+
+       private final String name;
+       private final Class<T> type;
+       private final UnitGroup unitGroup;
+       
+       public TypedKey(String name, Class<T> type) {
+               this(name, type, null);
+       }
+       
+       public TypedKey(String name, Class<T> type, UnitGroup unitGroup) {
+               this.name = name;
+               this.type = type;
+               this.unitGroup = unitGroup;
+       }
+
+       @Override
+       public String toString() {
+               return "TypedKey [name=" + name + "]";
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public Class<T> getType() {
+               return type;
+       }
+
+       public UnitGroup getUnitGroup() {
+               return unitGroup;
+       }
+
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + ((name == null) ? 0 : name.hashCode());
+               result = prime * result + ((type == null) ? 0 : type.hashCode());
+               return result;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               TypedKey other = (TypedKey) obj;
+               if (name == null) {
+                       if (other.name != null)
+                               return false;
+               } else if (!name.equals(other.name))
+                       return false;
+               if (type == null) {
+                       if (other.type != null)
+                               return false;
+               } else if (!type.equals(other.type))
+                       return false;
+               return true;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/TypedPropertyMap.java b/core/src/net/sf/openrocket/preset/TypedPropertyMap.java
new file mode 100644 (file)
index 0000000..cb43f12
--- /dev/null
@@ -0,0 +1,86 @@
+package net.sf.openrocket.preset;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class TypedPropertyMap implements Cloneable {
+       
+       private final Map<TypedKey<?>, Object> delegate;
+       
+       public TypedPropertyMap() {
+               delegate = new LinkedHashMap<TypedKey<?>, Object>();
+       }
+       
+       public int size() {
+               return delegate.size();
+       }
+       
+       public boolean isEmpty() {
+               return delegate.isEmpty();
+       }
+       
+       public boolean containsKey(Object key) {
+               return delegate.containsKey(key);
+       }
+       
+       public boolean containsValue(Object value) {
+               return delegate.containsValue(value);
+       }
+       
+       @SuppressWarnings("unchecked")
+       public <T> T get(TypedKey<T> key) {
+               return (T) delegate.get(key);
+       }
+       
+       @SuppressWarnings("unchecked")
+       public <T> T put(TypedKey<T> key, T value) {
+               return (T) delegate.put(key, value);
+       }
+       
+       public Object remove(Object key) {
+               return delegate.remove(key);
+       }
+       
+       public void putAll(TypedPropertyMap other) {
+               if (other == null) {
+                       return;
+               }
+               delegate.putAll(other.delegate);
+       }
+       
+       public void clear() {
+               delegate.clear();
+       }
+       
+       public Set<TypedKey<?>> keySet() {
+               return delegate.keySet();
+       }
+       
+       public Collection<Object> values() {
+               return delegate.values();
+       }
+       
+       public Set<Entry<TypedKey<?>, Object>> entrySet() {
+               return delegate.entrySet();
+       }
+       @Override
+       public String toString() {
+               StringBuilder sb = new StringBuilder("TypedPropertyMap: { ");
+               for( Map.Entry<TypedKey<?>, Object> e : delegate.entrySet() ) {
+                       sb.append(e.getKey()).append(" => ").append(String.valueOf(e.getValue()));
+               }
+               sb.append("}");
+               return sb.toString();
+       }
+
+       @Override
+       protected TypedPropertyMap clone() throws CloneNotSupportedException {
+               TypedPropertyMap clone = new TypedPropertyMap();
+               clone.putAll(this);
+               return clone;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/BaseColumnParser.java b/core/src/net/sf/openrocket/preset/loader/BaseColumnParser.java
new file mode 100644 (file)
index 0000000..9c95197
--- /dev/null
@@ -0,0 +1,42 @@
+package net.sf.openrocket.preset.loader;
+
+import java.util.Locale;
+
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+
+public abstract class BaseColumnParser implements RocksimComponentFileColumnParser {
+
+       protected String columnHeader;
+       protected boolean isConfigured = false;
+       protected int columnIndex;
+
+       public BaseColumnParser(String columnHeader) {
+               super();
+               this.columnHeader = columnHeader.toLowerCase(Locale.US);
+       }
+
+       @Override
+       public void configure(String[] headers) {
+               if ( headers == null ) {
+                       return;
+               }
+               for( int i =0; i< headers.length; i++ ) {
+                       if ( columnHeader.equals(headers[i].toLowerCase(Locale.US))) {
+                               columnIndex = i;
+                               isConfigured = true;
+                               return;
+                       }
+               }
+       }
+
+       @Override
+       final public void parse(String[] data, TypedPropertyMap props) {
+               if ( isConfigured ) {
+                       doParse(data[columnIndex], data, props);
+               }
+       }
+       
+       protected abstract void doParse(String columnData, String[] data, TypedPropertyMap props );
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/BaseComponentLoader.java b/core/src/net/sf/openrocket/preset/loader/BaseComponentLoader.java
new file mode 100644 (file)
index 0000000..d178209
--- /dev/null
@@ -0,0 +1,50 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class BaseComponentLoader extends RocksimComponentFileLoader {
+
+       List<ComponentPreset> presets;
+
+       public BaseComponentLoader(MaterialHolder materials, File theBasePathToLoadFrom) {
+               super(theBasePathToLoadFrom);
+               presets = new ArrayList<ComponentPreset>();
+
+               fileColumns.add( new ManufacturerColumnParser() );
+               fileColumns.add( new StringColumnParser("Part No.", ComponentPreset.PARTNO));
+               fileColumns.add( new StringColumnParser("Desc.", ComponentPreset.DESCRIPTION));
+               fileColumns.add(new MaterialColumnParser(materials));
+               fileColumns.add(new MassColumnParser("Mass","Mass units"));
+
+       }
+
+       protected abstract ComponentPreset.Type getComponentPresetType();
+
+       public List<ComponentPreset> getPresets() {
+               return presets;
+       }
+
+       @Override
+       protected void postProcess(TypedPropertyMap props) {
+               try {
+            //Some Rocksim files don't contain description, so set it to the part no when not available.
+            if (!props.containsKey(ComponentPreset.DESCRIPTION)) {
+                props.put(ComponentPreset.DESCRIPTION, props.get(ComponentPreset.PARTNO));
+            }
+                       props.put(ComponentPreset.TYPE, getComponentPresetType());
+                       ComponentPreset preset = ComponentPresetFactory.create(props);
+                       presets.add(preset);
+               } catch ( InvalidComponentPresetException ex ) {
+                       System.err.println(ex.getMessage());
+                       System.err.println(props);
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/core/src/net/sf/openrocket/preset/loader/BaseUnitColumnParser.java b/core/src/net/sf/openrocket/preset/loader/BaseUnitColumnParser.java
new file mode 100644 (file)
index 0000000..4cdb398
--- /dev/null
@@ -0,0 +1,53 @@
+package net.sf.openrocket.preset.loader;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.unit.UnitGroup;
+
+
+public abstract class BaseUnitColumnParser extends BaseColumnParser {
+
+       protected String unitHeader;
+       protected int unitIndex;
+       protected boolean unitConfigured;
+       
+       protected static Map<String,Unit> rocksimUnits;
+       
+       static {
+               rocksimUnits = new HashMap<String,Unit>();
+               rocksimUnits.put("0", UnitGroup.UNITS_LENGTH.getUnit("in"));
+               rocksimUnits.put("1", UnitGroup.UNITS_LENGTH.getUnit("mm"));
+       }
+
+       protected String mungeUnitNameString( String name ) {
+               String newString = name.toLowerCase(Locale.US);
+               return newString.replace(".", "");
+       }
+       
+       public BaseUnitColumnParser(String columnHeader, String unitHeader) {
+               super(columnHeader);
+               this.unitHeader = unitHeader.toLowerCase(Locale.US);
+       }
+
+       @Override
+       public void configure(String[] headers) {
+               // super configure will set columnIndex;
+               super.configure(headers);
+               
+               // This indicates the actual dimension column was found.
+               if ( isConfigured ) {
+                       // Look for the unit column proceeding it
+                       for( int i=columnIndex-1; i>=0; i-- ) {
+                               if ( unitHeader.equals(headers[i].toLowerCase(Locale.US))) {
+                                       unitConfigured = true;
+                                       unitIndex = i;
+                                       return;
+                               }
+                       }
+               }
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/BodyTubeLoader.java b/core/src/net/sf/openrocket/preset/loader/BodyTubeLoader.java
new file mode 100644 (file)
index 0000000..dcb7ccc
--- /dev/null
@@ -0,0 +1,30 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+
+import java.io.File;
+
+public class BodyTubeLoader extends BaseComponentLoader {
+
+       public BodyTubeLoader(MaterialHolder materials, File theBasePathToLoadFrom) {
+               super(materials, theBasePathToLoadFrom);
+               fileColumns.add(new DoubleUnitColumnParser("ID","Units",ComponentPreset.INNER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("OD","Units",ComponentPreset.OUTER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("Length","Units",ComponentPreset.LENGTH));
+
+       }
+
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.BODY_TUBE;
+       }
+
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.BODY_TUBE;
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/BulkHeadLoader.java b/core/src/net/sf/openrocket/preset/loader/BulkHeadLoader.java
new file mode 100644 (file)
index 0000000..b9d0106
--- /dev/null
@@ -0,0 +1,36 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import java.io.File;
+
+public class BulkHeadLoader extends BaseComponentLoader {
+
+       public BulkHeadLoader(MaterialHolder materials, File theBasePath) {
+               super(materials, theBasePath);
+               fileColumns.add(new DoubleUnitColumnParser("OD","Units",ComponentPreset.OUTER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("Length","Units",ComponentPreset.LENGTH));
+
+       }
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.BULK_HEAD;
+       }
+
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.BULKHEAD;
+       }
+
+       @Override
+       protected void postProcess(TypedPropertyMap props) {
+               props.put(ComponentPreset.FILLED, true);
+               super.postProcess(props);
+       }
+
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/CenteringRingLoader.java b/core/src/net/sf/openrocket/preset/loader/CenteringRingLoader.java
new file mode 100644 (file)
index 0000000..ad46569
--- /dev/null
@@ -0,0 +1,24 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+
+import java.io.File;
+
+public class CenteringRingLoader extends BodyTubeLoader {
+
+       public CenteringRingLoader(MaterialHolder materials, File theBasePath) {
+               super(materials, theBasePath);
+       }
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.CENTERING_RING;
+       }
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.CENTERING_RING;
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/DoubleColumnParser.java b/core/src/net/sf/openrocket/preset/loader/DoubleColumnParser.java
new file mode 100644 (file)
index 0000000..e4f5413
--- /dev/null
@@ -0,0 +1,21 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+public class DoubleColumnParser extends BaseColumnParser {
+
+       private TypedKey<Double> propKey;
+       
+       public DoubleColumnParser(String columnHeader, TypedKey<Double> propKey) {
+               super(columnHeader);
+               this.propKey = propKey;
+       }
+
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               double value = Double.valueOf(columnData);
+               props.put(propKey, value);
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/DoubleUnitColumnParser.java b/core/src/net/sf/openrocket/preset/loader/DoubleUnitColumnParser.java
new file mode 100644 (file)
index 0000000..bd9a5c1
--- /dev/null
@@ -0,0 +1,57 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.unit.UnitGroup;
+
+public class DoubleUnitColumnParser extends BaseUnitColumnParser {
+
+       private TypedKey<Double> propKey;
+
+       public DoubleUnitColumnParser(String columnHeader, String unitHeader,
+                       TypedKey<Double> propKey) {
+               super(columnHeader, unitHeader);
+               this.propKey = propKey;
+       }
+
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               try {
+                       if (columnData == null || "".equals(columnData) ) {
+                               return;
+                       }
+                       double value = Double.valueOf(columnData);
+
+                       if ( unitConfigured ) {
+                               String unitName = data[unitIndex];
+
+                               Unit unit = rocksimUnits.get(unitName);
+                               if ( unit == null ) {
+                                       if ( unitName == null || "" .equals(unitName) || "?".equals(unitName)) {
+                                               // Hmm no data...  Lets assume SI
+                                               if ( propKey.getUnitGroup() == UnitGroup.UNITS_LENGTH ) {
+                                                       unit = UnitGroup.UNITS_LENGTH.getUnit("in");
+                                               } else {
+                                                       unit= UnitGroup.UNITS_MASS.getUnit("oz");
+                                               }
+                                       } else {
+                                               unitName = super.mungeUnitNameString(unitName);
+                                               UnitGroup group = propKey.getUnitGroup();
+                                               unit = group.getUnit(unitName);
+                                       }
+                               }
+
+                               value = unit.fromUnit(value);
+                       }
+
+                       props.put(propKey, value);
+               }
+               catch ( NumberFormatException nex) {
+               }
+        catch ( IllegalArgumentException iae) {
+        }
+       }
+
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/EngineBlockLoader.java b/core/src/net/sf/openrocket/preset/loader/EngineBlockLoader.java
new file mode 100644 (file)
index 0000000..0fa6a6e
--- /dev/null
@@ -0,0 +1,24 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+
+import java.io.File;
+
+public class EngineBlockLoader extends BodyTubeLoader {
+
+       public EngineBlockLoader(MaterialHolder materials, File theBasePath) {
+               super(materials, theBasePath);
+       }
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.ENGINE_BLOCK;
+       }
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.ENGINE_BLOCK;
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/IntegerColumnParser.java b/core/src/net/sf/openrocket/preset/loader/IntegerColumnParser.java
new file mode 100644 (file)
index 0000000..d871be1
--- /dev/null
@@ -0,0 +1,21 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+public class IntegerColumnParser extends BaseColumnParser {
+
+       private TypedKey<Integer> propKey;
+       
+       public IntegerColumnParser(String columnHeader, TypedKey<Integer> propKey) {
+               super(columnHeader);
+               this.propKey = propKey;
+       }
+
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               int value = Integer.valueOf(columnData);
+               props.put(propKey, value);
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/LaunchLugLoader.java b/core/src/net/sf/openrocket/preset/loader/LaunchLugLoader.java
new file mode 100644 (file)
index 0000000..8242e8f
--- /dev/null
@@ -0,0 +1,30 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+
+import java.io.File;
+
+public class LaunchLugLoader extends BaseComponentLoader {
+
+       public LaunchLugLoader(MaterialHolder materials, File theBasePath) {
+               super(materials, theBasePath);
+               fileColumns.add(new DoubleUnitColumnParser("ID","Units",ComponentPreset.INNER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("OD","Units",ComponentPreset.OUTER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("Length","Units",ComponentPreset.LENGTH));
+
+       }
+
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.LAUNCH_LUG;
+       }
+
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.LAUNCH_LUG;
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/LineMaterialColumnParser.java b/core/src/net/sf/openrocket/preset/loader/LineMaterialColumnParser.java
new file mode 100644 (file)
index 0000000..42a7972
--- /dev/null
@@ -0,0 +1,35 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+public class LineMaterialColumnParser extends BaseColumnParser {
+       
+       private final MaterialHolder materialMap;
+       
+       private final TypedKey<Material> param;
+       
+       public LineMaterialColumnParser(MaterialHolder materialMap, String columnName, TypedKey<Material> param) {
+               super(columnName);
+               this.param = param;
+               this.materialMap = materialMap;
+       }
+       
+       
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               
+               if (columnData == null || "".equals(columnData.trim())) {
+                       return;
+               }
+               
+               Material.Line myMaterial = (Material.Line) Databases.findMaterial(Material.Type.LINE, columnData, 0.0);
+               
+               Material.Line m = materialMap.getLineMaterial(myMaterial);
+               props.put(param, m != null ? m : myMaterial);
+               
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/ManufacturerColumnParser.java b/core/src/net/sf/openrocket/preset/loader/ManufacturerColumnParser.java
new file mode 100644 (file)
index 0000000..7d019c0
--- /dev/null
@@ -0,0 +1,20 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+public class ManufacturerColumnParser extends BaseColumnParser {
+
+       public ManufacturerColumnParser() {
+               super("Mfg.");
+       }
+
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               Manufacturer m = Manufacturer.getManufacturer(columnData);
+               props.put(ComponentPreset.MANUFACTURER, m);
+
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/MassColumnParser.java b/core/src/net/sf/openrocket/preset/loader/MassColumnParser.java
new file mode 100644 (file)
index 0000000..ce382ec
--- /dev/null
@@ -0,0 +1,30 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+/**
+ * Special DoubleUnitColumnParser for Mass column.  Here we assume that if a mass of 0 is
+ * specified in the csv, then we should not put a mass explicitly in the preset but instead
+ * rely on the density to compute a mass value.
+ *
+ */
+public class MassColumnParser extends DoubleUnitColumnParser {
+
+       public MassColumnParser(String columnHeader, String unitHeader) {
+               super(columnHeader, unitHeader, ComponentPreset.MASS);
+       }
+
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               if ( columnData == null || "".equals(columnData.trim()) || "?".equals(columnData.trim())) {
+                       return;
+               }
+               double d = Double.valueOf(columnData);
+               if ( d == 0.0 ) {
+                       return;
+               }
+               super.doParse(columnData, data, props);
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/MaterialColumnParser.java b/core/src/net/sf/openrocket/preset/loader/MaterialColumnParser.java
new file mode 100644 (file)
index 0000000..2d559bb
--- /dev/null
@@ -0,0 +1,39 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+public class MaterialColumnParser extends BaseColumnParser {
+       
+       private final MaterialHolder materialMap;
+       
+       private final TypedKey<Material> param;
+       
+       public MaterialColumnParser(MaterialHolder materialMap, String columnName, TypedKey<Material> param) {
+               super(columnName);
+               this.param = param;
+               this.materialMap = materialMap;
+       }
+       
+       public MaterialColumnParser(MaterialHolder materialMap) {
+               this(materialMap, "Material", ComponentPreset.MATERIAL);
+       }
+       
+       
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               
+               if (columnData == null || "".equals(columnData.trim())) {
+                       return;
+               }
+               
+               Material.Bulk tmpMaterial = (Material.Bulk) Databases.findMaterial(Material.Type.BULK, columnData, 0.0);
+               Material.Bulk m = materialMap.getBulkMaterial(tmpMaterial);
+               props.put(param, m != null ? m : tmpMaterial);
+               
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/MaterialHolder.java b/core/src/net/sf/openrocket/preset/loader/MaterialHolder.java
new file mode 100644 (file)
index 0000000..7ab176b
--- /dev/null
@@ -0,0 +1,134 @@
+package net.sf.openrocket.preset.loader;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import net.sf.openrocket.database.Database;
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.unit.UnitGroup;
+
+public class MaterialHolder {
+       
+       private final Map<String, Material.Bulk> bulkMaterials = new HashMap<String, Material.Bulk>();
+       
+       private final Map<String, Material.Surface> surfaceMaterials = new HashMap<String, Material.Surface>();
+       
+       private final Map<String, Material.Line> lineMaterials = new HashMap<String, Material.Line>();
+       
+       public MaterialHolder() {
+       }
+       
+       public MaterialHolder(List<Material> materials) {
+               if (materials == null) {
+                       return;
+               }
+               for (Material material : materials) {
+                       this.put(material);
+               }
+       }
+       
+       public void put(Material material) {
+               switch (material.getType()) {
+               case BULK:
+                       bulkMaterials.put(material.getName(), (Material.Bulk) material);
+                       break;
+               case SURFACE:
+                       surfaceMaterials.put(material.getName(), (Material.Surface) material);
+                       break;
+               case LINE:
+                       lineMaterials.put(material.getName(), (Material.Line) material);
+                       break;
+               }
+       }
+       
+       public Material getMaterial(Material material) {
+               switch (material.getType()) {
+               case BULK:
+                       return getBulkMaterial((Material.Bulk) material);
+               case SURFACE:
+                       return getSurfaceMaterial((Material.Surface) material, null);
+               case LINE:
+                       return getLineMaterial((Material.Line) material);
+               default:
+                       return null;
+               }
+       }
+       
+       public Material.Bulk getBulkMaterial(Material.Bulk material) {
+               Material.Bulk m = bulkMaterials.get(material.getName());
+               return m;
+       }
+       
+       public Material.Surface getSurfaceMaterial(Material.Surface material, Double thickness) {
+               Material.Surface m = surfaceMaterials.get(material.getName());
+               if (m != null) {
+                       return m;
+               }
+               // Try to see if we can convert a bulk material.
+               if (thickness == null) {
+                       // if we have no thickness, there is nothing we can do
+                       return null;
+               }
+               String thicknessName = UnitGroup.UNITS_LENGTH.getUnit("mm").toString(thickness);
+               String convertedMaterialName = material.getName() + "(" + thicknessName + ")";
+               m = surfaceMaterials.get(convertedMaterialName);
+               if (m != null) {
+                       return m;
+               }
+               Material.Bulk bulk = bulkMaterials.get(material.getName());
+               
+               if (bulk == null) {
+                       return null;
+               }
+               
+               // Ok, now we have a thickness and a bulk material of the correct name,
+               // we can make our own surface material.
+               
+               Material.Surface surface = (Material.Surface) Databases.findMaterial(Material.Type.SURFACE, convertedMaterialName, bulk.getDensity() * thickness);
+               
+               this.put(surface);
+               
+               return surface;
+               
+       }
+       
+       public Material.Line getLineMaterial(Material.Line material) {
+               Material.Line m = lineMaterials.get(material.getName());
+               return m;
+       }
+       
+       public int size() {
+               return bulkMaterials.size() + surfaceMaterials.size() + lineMaterials.size();
+       }
+       
+       public Collection<Material> values() {
+               
+               HashSet<Material> allMats = new HashSet<Material>();
+               allMats.addAll(bulkMaterials.values());
+               allMats.addAll(surfaceMaterials.values());
+               allMats.addAll(lineMaterials.values());
+               
+               return allMats;
+               
+       }
+       
+       public Database<Material> asDatabase(Material.Type theType) {
+               Database<Material> result = new Database<Material>();
+               switch (theType) {
+               case LINE:
+                       result.addAll(lineMaterials.values());
+                       break;
+               case SURFACE:
+                       result.addAll(surfaceMaterials.values());
+                       break;
+               case BULK:
+               default:
+                       result.addAll(bulkMaterials.values());
+               }
+               return result;
+       }
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/MaterialLoader.java b/core/src/net/sf/openrocket/preset/loader/MaterialLoader.java
new file mode 100644 (file)
index 0000000..b7ef55b
--- /dev/null
@@ -0,0 +1,62 @@
+package net.sf.openrocket.preset.loader;
+
+import java.io.File;
+
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+import net.sf.openrocket.util.BugException;
+
+public class MaterialLoader extends RocksimComponentFileLoader {
+       
+       private MaterialHolder materialMap = new MaterialHolder();
+       
+       private final static TypedKey<String> MATERIALNAME = new TypedKey<String>("MaterialName", String.class);
+       private final static TypedKey<String> UNITS = new TypedKey<String>("Units", String.class);
+       private final static TypedKey<Double> DENSITY = new TypedKey<Double>("Density", Double.class);
+       
+       public MaterialLoader(File theBasePathToLoadFrom) {
+               super(theBasePathToLoadFrom);
+               fileColumns.add(new StringColumnParser("Material Name", MATERIALNAME));
+               fileColumns.add(new StringColumnParser("Units", UNITS));
+               fileColumns.add(new DoubleColumnParser("Density", DENSITY));
+       }
+       
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.MATERIAL;
+       }
+       
+       public MaterialHolder getMaterialMap() {
+               return materialMap;
+       }
+       
+       @Override
+       protected void postProcess(TypedPropertyMap props) {
+               String name = props.get(MATERIALNAME);
+               String unit = props.get(UNITS);
+               double density = props.get(DENSITY);
+               
+               String cleanedMaterialName = stripAll(name, '"').trim();
+               
+               if ("g/cm".equals(unit)) {
+                       materialMap.put(Databases.findMaterial(Material.Type.LINE, cleanedMaterialName, 0.1d * density));
+               } else if ("g/cm2".equals(unit)) {
+                       materialMap.put(Databases.findMaterial(Material.Type.SURFACE, cleanedMaterialName, 10.0d * density));
+               } else if ("g/cm3".equals(unit)) {
+                       materialMap.put(Databases.findMaterial(Material.Type.BULK, cleanedMaterialName, 1000.0d * density));
+               } else if ("kg/m3".equals(unit)) {
+                       materialMap.put(Databases.findMaterial(Material.Type.BULK, cleanedMaterialName, density));
+               } else if ("lb/ft3".equals(unit)) {
+                       materialMap.put(Databases.findMaterial(Material.Type.BULK, cleanedMaterialName, 16.0184634d * density));
+               } else if ("oz/in".equals(unit)) {
+                       materialMap.put(Databases.findMaterial(Material.Type.LINE, cleanedMaterialName, 1.11612296d * density));
+               } else if ("oz/in2".equals(unit)) {
+                       materialMap.put(Databases.findMaterial(Material.Type.SURFACE, cleanedMaterialName, 43.94184876d * density));
+               } else {
+                       throw new BugException("Unknown unit in Materials file: " + unit);
+               }
+       }
+       
+}
\ No newline at end of file
diff --git a/core/src/net/sf/openrocket/preset/loader/NoseConeLoader.java b/core/src/net/sf/openrocket/preset/loader/NoseConeLoader.java
new file mode 100644 (file)
index 0000000..8c8f407
--- /dev/null
@@ -0,0 +1,44 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import java.io.File;
+
+public class NoseConeLoader extends BaseComponentLoader {
+
+       public NoseConeLoader(MaterialHolder materials, File theBasePath) {
+               super(materials, theBasePath);
+               fileColumns.add(new DoubleUnitColumnParser("Outer Dia","Units",ComponentPreset.AFT_OUTER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("Length","Units",ComponentPreset.LENGTH));
+               fileColumns.add(new DoubleUnitColumnParser("Insert Length","Units",ComponentPreset.AFT_SHOULDER_LENGTH));
+               fileColumns.add(new DoubleUnitColumnParser("Insert OD","Units",ComponentPreset.AFT_SHOULDER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("Thickness","Units",ComponentPreset.THICKNESS));
+               fileColumns.add(new ShapeColumnParser() );
+       }
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.NOSE_CONE;
+       }
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.NOSE_CONE;
+       }
+
+       @Override
+       protected void postProcess(TypedPropertyMap props) {
+
+               if ( props.containsKey( ComponentPreset.THICKNESS )) {
+                       double thickness = props.get(ComponentPreset.THICKNESS);
+                       if ( thickness == 0d ) {
+                               props.remove( ComponentPreset.THICKNESS );
+                               props.put(ComponentPreset.FILLED, true);
+                       }
+               }
+               super.postProcess(props);
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/ParachuteLoader.java b/core/src/net/sf/openrocket/preset/loader/ParachuteLoader.java
new file mode 100644 (file)
index 0000000..4f53e40
--- /dev/null
@@ -0,0 +1,51 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import java.io.File;
+
+public class ParachuteLoader extends BaseComponentLoader {
+
+       private final MaterialHolder materials;
+
+       public ParachuteLoader(MaterialHolder materials, File theBasePath) {
+               super(materials, theBasePath);
+               this.materials = materials;
+               fileColumns.add(new IntegerColumnParser("n sides", ComponentPreset.SIDES));
+               fileColumns.add(new DoubleUnitColumnParser("OD","Units",ComponentPreset.DIAMETER));
+               fileColumns.add(new IntegerColumnParser("Shroud Count", ComponentPreset.LINE_COUNT));
+               fileColumns.add(new DoubleUnitColumnParser("Shroud Len", "Units", ComponentPreset.LINE_LENGTH));
+               fileColumns.add(new LineMaterialColumnParser(materials,"Shroud Material",ComponentPreset.LINE_MATERIAL));
+               fileColumns.add(new DoubleUnitColumnParser("Chute Thickness", "Units", ComponentPreset.THICKNESS));
+               fileColumns.add( new SurfaceMaterialColumnParser(materials,"Chute Material", ComponentPreset.MATERIAL));
+       }
+
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.PARACHUTE;
+       }
+
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.PARACHUTE;
+       }
+
+
+       @Override
+       protected void postProcess(TypedPropertyMap props) {
+               super.postProcess(props);
+
+               // Fix the material since some files use bulk materials for streamers.
+               Double thickness = props.get( ComponentPreset.THICKNESS );
+               Material.Surface myMaterial = (Material.Surface) props.get( ComponentPreset.MATERIAL );
+
+               Material.Surface m = materials.getSurfaceMaterial(myMaterial, thickness);
+               props.put(ComponentPreset.MATERIAL, m!=null ? m : myMaterial);
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileColumnParser.java b/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileColumnParser.java
new file mode 100644 (file)
index 0000000..cfaf091
--- /dev/null
@@ -0,0 +1,22 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+public interface RocksimComponentFileColumnParser {
+
+       /**
+        * Examine the array of column headers and configure parsing for this type. 
+        * 
+        * @param headers
+        */
+       public void configure( String[] headers );
+       
+       /**
+        * Examine the data array, parse the appropriate data and push into props.
+        * 
+        * @param data
+        * @param props
+        */
+       public void parse( String[] data, TypedPropertyMap props );
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileLoader.java b/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileLoader.java
new file mode 100644 (file)
index 0000000..c0ca293
--- /dev/null
@@ -0,0 +1,276 @@
+package net.sf.openrocket.preset.loader;
+
+import au.com.bytecode.opencsv.CSVReader;
+import net.sf.openrocket.gui.print.PrintUnit;
+import net.sf.openrocket.preset.TypedPropertyMap;
+import net.sf.openrocket.unit.Unit;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.ArrayList;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.List;
+
+/**
+ * Primary entry point for parsing component CSV files that are in Rocksim format.
+ */
+public abstract class RocksimComponentFileLoader {
+
+    private static final PrintStream LOGGER = System.err;
+
+       private String basePath = "";
+
+       private File dir;
+
+       protected List<RocksimComponentFileColumnParser> fileColumns = new ArrayList<RocksimComponentFileColumnParser>();
+
+       /**
+        * Constructor.
+        *
+        * @param theBasePathToLoadFrom base path
+        */
+       public RocksimComponentFileLoader(File theBasePathToLoadFrom) {
+               dir = theBasePathToLoadFrom;
+               basePath = dir.getAbsolutePath();
+       }
+
+       /**
+        * Constructor.
+        *
+        * @param theBasePathToLoadFrom base path
+        */
+       public RocksimComponentFileLoader(String theBasePathToLoadFrom) {
+               dir = new File(basePath);
+               basePath = theBasePathToLoadFrom;
+       }
+
+       protected abstract RocksimComponentFileType getFileType();
+
+       public void load() {
+               try {
+               load(getFileType());
+               } catch (FileNotFoundException fex ) {
+               LOGGER.println( fex.getLocalizedMessage() );
+               }
+       }
+
+       /**
+        * Read a comma separated component file and return the parsed contents as a list of string arrays.  Not for
+        * production use - just here for smoke testing.
+        *
+        * @param type the type of component file to read; uses the default file name
+        *
+        * @return a list (guaranteed never to be null) of string arrays.  Each element of the list represents a row in the
+        *         component data file; the element in the list itself is an array of String, where each item in the array
+        *         is a column (cell) in the row.  The string array is in sequential order as it appeared in the file.
+        */
+       private void load(RocksimComponentFileType type) throws FileNotFoundException {
+               if (!dir.exists()) {
+                       throw new IllegalArgumentException(basePath + " does not exist");
+               }
+               if (!dir.isDirectory()) {
+                       throw new IllegalArgumentException(basePath + " is not directory");
+               }
+               if (!dir.canRead()) {
+                       throw new IllegalArgumentException(basePath + " is not readable");
+               }
+               FileInputStream fis = new FileInputStream(new File(dir, type.getDefaultFileName()));
+               load(fis);
+       }
+
+       /**
+        * Read a comma separated component file and return the parsed contents as a list of string arrays.
+        *
+        * @param file the file to read and parse
+        *
+        * @return a list (guaranteed never to be null) of string arrays.  Each element of the list represents a row in the
+        *         component data file; the element in the list itself is an array of String, where each item in the array
+        *         is a column (cell) in the row.  The string array is in sequential order as it appeared in the file.
+        */
+       private void load(File file) throws FileNotFoundException {
+               load(new FileInputStream(file));
+       }
+
+       /**
+        * Read a comma separated component file and return the parsed contents as a list of string arrays.
+        *
+        * @param is the stream to read and parse
+        *
+        * @return a list (guaranteed never to be null) of string arrays.  Each element of the list represents a row in the
+        *         component data file; the element in the list itself is an array of String, where each item in the array
+        *         is a column (cell) in the row.  The string array is in sequential order as it appeared in the file.
+        */
+       private void load(InputStream is) {
+               if (is == null) {
+                       return;
+               }
+               InputStreamReader r = null;
+               try {
+                       r = new InputStreamReader(is);
+
+                       // Create the CSV reader.  Use comma separator.
+                       CSVReader reader = new CSVReader(r, ',', '\'', '\\');
+
+                       //Read and throw away the header row.
+                       parseHeaders(reader.readNext());
+
+                       String[] data = null;
+                       while ((data = reader.readNext()) != null) {
+                               // detect empty lines and skip:
+                               if (data.length == 0) {
+                                       continue;
+                               }
+                               if (data.length == 1 && "".equals(data[0].trim())) {
+                                       continue;
+                               }
+                               parseData(data);
+                       }
+                       //Read the rest of the file as data rows.
+                       return;
+               }
+               catch (IOException e) {
+               }
+               finally {
+                       if (r != null) {
+                               try {
+                                       r.close();
+                               }
+                               catch (IOException e) {
+                               }
+                       }
+               }
+
+       }
+
+       protected void parseHeaders(String[] headers) {
+               for (RocksimComponentFileColumnParser column : fileColumns) {
+                       column.configure(headers);
+               }
+       }
+
+       protected void parseData(String[] data) {
+               if (data == null || data.length == 0) {
+                       return;
+               }
+               TypedPropertyMap props = new TypedPropertyMap();
+
+               preProcess(data);
+
+               for (RocksimComponentFileColumnParser column : fileColumns) {
+                       column.parse(data, props);
+               }
+               postProcess(props);
+       }
+
+       protected void preProcess(String[] data) {
+               for (int i = 0; i < data.length; i++) {
+                       String d = data[i];
+                       if (d == null) {
+                               continue;
+                       }
+                       d = d.trim();
+                       d = stripAll(d, '"');
+
+                       data[i] = d;
+               }
+       }
+
+       protected abstract void postProcess(TypedPropertyMap props);
+
+       /**
+        * Rocksim CSV units are either inches or mm.  A value of 0 or "in." indicate inches.  A value of 1 or "mm" indicate
+        * millimeters.
+        *
+        * @param units the value from the file
+        *
+        * @return true if it's inches
+        */
+       protected static boolean isInches(String units) {
+               String tmp = units.trim().toLowerCase();
+               return "0".equals(tmp) || tmp.startsWith("in");
+       }
+
+       /**
+        * Convert inches or millimeters to meters.
+        *
+        * @param units a Rocksim CSV string representing the kind of units.
+        * @param value the original value within the CSV file
+        *
+        * @return the value in meters
+        */
+       protected static double convertLength(String units, double value) {
+               if (isInches(units)) {
+                       return PrintUnit.INCHES.toMeters(value);
+               }
+               else {
+                       return PrintUnit.MILLIMETERS.toMeters(value);
+               }
+       }
+
+       protected static double convertMass(String units, double value) {
+               if ("oz".equals(units)) {
+                       Unit u = UnitGroup.UNITS_MASS.getUnit(2);
+                       return u.fromUnit(value);
+               }
+               return value;
+       }
+
+       /**
+        * Remove all occurrences of the given character.  Note: this is done because some manufacturers embed double quotes
+        * in their descriptions or material names.  Those are stripped away because they cause all sorts of matching/lookup
+        * issues.
+        *
+        * @param target      the target string to be operated upon
+        * @param toBeRemoved the character to remove
+        *
+        * @return target, minus every occurrence of toBeRemoved
+        */
+       protected static String stripAll(String target, Character toBeRemoved) {
+               StringBuilder sb = new StringBuilder();
+               for (int i = 0; i < target.length(); i++) {
+                       Character c = target.charAt(i);
+                       if (!c.equals(toBeRemoved)) {
+                               sb.append(c);
+                       }
+               }
+               return sb.toString();
+       }
+
+       /**
+        * Convert all words in a given string to Camel Case (first letter capitalized). Words are assumed to be separated
+        * by a space.  Note: this is done because some manufacturers define their material name in Camel Case but the
+        * component part references the material in lower case.  That causes matching/lookup issues that's easiest handled
+        * this way (rather than converting everything to lower case.
+        *
+        * @param target the target string to be operated upon
+        *
+        * @return target, with the first letter of each word in uppercase
+        */
+       protected static String toCamelCase(String target) {
+               StringBuilder sb = new StringBuilder();
+               String[] t = target.split("[ ]");
+               if (t != null && t.length > 0) {
+                       for (String aT : t) {
+                               String s = aT;
+                               s = s.substring(0, 1).toUpperCase() + s.substring(1).toLowerCase();
+                               sb.append(s).append(" ");
+                       }
+                       return sb.toString().trim();
+               }
+               else {
+                       return target;
+               }
+       }
+
+}
+
+//Errata:
+//The oddities I've found thus far in the stock Rocksim data:
+//1. BTDATA.CSV - Totally Tubular goofed up their part no. and description columns (They messed up TCDATA also)
+//2. NCDATA.CSV - Estes Balsa nose cones are classified as G10 Fiberglass
+//3. TRDATA.CSV - Apogee Saturn LEM Transition has no part number; Balsa Machining transitions have blank diameter
diff --git a/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileTranslator.java b/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileTranslator.java
new file mode 100644 (file)
index 0000000..d84fa1d
--- /dev/null
@@ -0,0 +1,150 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.gui.util.SwingPreferences;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.xml.OpenRocketComponentSaver;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.startup.Startup;
+import net.sf.openrocket.util.ArrayList;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.util.List;
+
+public class RocksimComponentFileTranslator {
+
+    private static PrintStream LOGGER = System.err;
+
+    private static void printUsage() {
+        LOGGER.println("RocksimComponentFileLoader <dir> <file>");
+        LOGGER.println("<dir> is base directory for a set of Rocksim component csv files");
+        LOGGER.println("<file> is where the orc file is written");
+    }
+
+    public static void main(String[] args) throws Exception {
+
+        // How to control logging?
+
+        if (args.length < 2 || args.length > 2) {
+            printUsage();
+            throw new IllegalArgumentException("Invalid Command Line Params");
+        }
+
+        List<ComponentPreset> allPresets = new ArrayList<ComponentPreset>();
+
+        LOGGER.println("Loading csv files from directory " + args[0]);
+
+        Startup.initializeLogging();
+        Application.setPreferences(new SwingPreferences());
+
+        MaterialHolder materialMap = loadAll(allPresets, new File(args[0]));
+        LOGGER.println("\tMarshalling to XML");
+        String xml = new OpenRocketComponentSaver().marshalToOpenRocketComponent(new ArrayList<Material>(materialMap.values()), allPresets);
+
+        // Try parsing the file
+        LOGGER.println("\tValidating XML");
+        // Throw away the result, we're just parsing for validation.
+        new OpenRocketComponentSaver().unmarshalFromOpenRocketComponent(new StringReader(xml));
+
+        LOGGER.println("\tWriting to file " + args[1]);
+        File outfile = new File(args[1]);
+        FileWriter fos = new FileWriter(outfile);
+        fos.write(xml);
+        fos.flush();
+        fos.close();
+    }
+
+    /**
+     * Set a print stream as a logger.  Defaults to System.err.
+     *
+     * @param ps a stream to log to
+     */
+    public static void setLogger(PrintStream ps) {
+        if (ps != null) {
+            LOGGER = ps;
+        }
+    }
+
+    /**
+     * Load all presets.  The loaded presets are added to the list parameter.  The loaded materials are returned in the
+     * MaterialHolder instance.
+     *
+     * @param theAllPresets a list of ComponentPreset that gets populated as the result of loading; must not be null on
+     *                      invocation
+     *
+     * @return a holder of the materials loaded
+     */
+    public static MaterialHolder loadAll(final List<ComponentPreset> theAllPresets, File theBasePathToLoadFrom) {
+        MaterialLoader mats = new MaterialLoader(theBasePathToLoadFrom);
+        mats.load();
+
+        MaterialHolder materialMap = mats.getMaterialMap();
+        LOGGER.println("\tMaterial types loaded: " + materialMap.size());
+
+        {
+            BodyTubeLoader bts = new BodyTubeLoader(materialMap, theBasePathToLoadFrom);
+            bts.load();
+            theAllPresets.addAll(bts.getPresets());
+            LOGGER.println("\tBody Tubes loaded: " + bts.getPresets().size());
+        }
+        {
+            BulkHeadLoader bhs = new BulkHeadLoader(materialMap, theBasePathToLoadFrom);
+            bhs.load();
+            theAllPresets.addAll(bhs.getPresets());
+            LOGGER.println("\tBulkheads loaded: " + bhs.getPresets().size());
+        }
+        {
+            CenteringRingLoader crs = new CenteringRingLoader(materialMap, theBasePathToLoadFrom);
+            crs.load();
+            theAllPresets.addAll(crs.getPresets());
+            LOGGER.println("\tCentering Rings loaded: " + crs.getPresets().size());
+        }
+        {
+            TubeCouplerLoader tcs = new TubeCouplerLoader(materialMap, theBasePathToLoadFrom);
+            tcs.load();
+            theAllPresets.addAll(tcs.getPresets());
+            LOGGER.println("\tTube Couplers loaded: " + tcs.getPresets().size());
+        }
+        {
+            EngineBlockLoader ebs = new EngineBlockLoader(materialMap, theBasePathToLoadFrom);
+            ebs.load();
+            theAllPresets.addAll(ebs.getPresets());
+            LOGGER.println("\tEngine Blocks loaded: " + ebs.getPresets().size());
+        }
+        {
+            NoseConeLoader ncs = new NoseConeLoader(materialMap, theBasePathToLoadFrom);
+            ncs.load();
+            theAllPresets.addAll(ncs.getPresets());
+            LOGGER.println("\tNose Cones loaded: " + ncs.getPresets().size());
+        }
+        {
+            TransitionLoader trs = new TransitionLoader(materialMap, theBasePathToLoadFrom);
+            trs.load();
+            theAllPresets.addAll(trs.getPresets());
+            LOGGER.println("\tTransitions loaded: " + trs.getPresets().size());
+        }
+        {
+            LaunchLugLoader lls = new LaunchLugLoader(materialMap, theBasePathToLoadFrom);
+            lls.load();
+            theAllPresets.addAll(lls.getPresets());
+            LOGGER.println("\tLaunch Lugs loaded: " + lls.getPresets().size());
+        }
+        {
+            StreamerLoader sts = new StreamerLoader(materialMap, theBasePathToLoadFrom);
+            sts.load();
+            theAllPresets.addAll(sts.getPresets());
+            LOGGER.println("\tStreamers loaded: " + sts.getPresets().size());
+        }
+        {
+            ParachuteLoader pcs = new ParachuteLoader(materialMap, theBasePathToLoadFrom);
+            pcs.load();
+            theAllPresets.addAll(pcs.getPresets());
+            LOGGER.println("Parachutes loaded: " + pcs.getPresets().size());
+        }
+        return materialMap;
+    }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileType.java b/core/src/net/sf/openrocket/preset/loader/RocksimComponentFileType.java
new file mode 100644 (file)
index 0000000..13ac862
--- /dev/null
@@ -0,0 +1,77 @@
+package net.sf.openrocket.preset.loader;
+
+import java.util.Arrays;
+
+/**
+ * Definition of the typical Rocksim component files and their formats.
+ */
+public enum RocksimComponentFileType {
+    BODY_TUBE("BTDATA.CSV", "Mfg.", "Part No.", "Desc.", "Units", "ID", "OD", "Length", "Material", "Engine"),
+    BULKHEAD("BHDATA.CSV", "Mfg.", "Part No.", "Desc.", "Units", "ID", "OD", "Length", "Material", "Engine", "Engine",
+            "Engine", "Engine", "Engine", "Engine", "Engine", "Engine", "Engine", "Engine", "Engine"),
+    CENTERING_RING("CRDATA.CSV", "Mfg.", "Part No.", "Desc.", "Units", "ID", "OD", "Length", "Material", "AutoSize"),
+    CUSTOM_FIN("CSDATA.CSV"),
+    ENGINE_BLOCK("EBDATA.CSV", "Mfg.", "Part No.", "Desc.", "Units", "ID", "OD", "Length", "Material", "CG", "Mass Units", "Mass", "AutoSize"),
+    FIN("FSDATA.CSV"),
+    LAUNCH_LUG("LLDATA.CSV", "Mfg.", "Part No.", "Desc.", "Units", "ID", "OD", "Length", "Material"),
+    MASS_OBJECT("MODATA.CSV", "Mfg.", "Part no", "Desc", "Units", "Name", "Type", "Length", "Material", "Mass units", "Mass"),
+    MATERIAL("MATERIAL.CSV", "Material Name", "Units", "Density", "Low", "High", "Class", "Rocketry Use", "Body Tubes",
+            "Fin Sets", "Launch Lugs", "Cords", "Nose", "Chute", "Stream", "Trans", "Ring", "Bulkhead", "Engine Block", "Sleeve",
+            "Tube Coupler", "spare", "spare", "spare", "spare", "spare", "spare", "spare", "Known Dim type", "Known Dim Units", "Known Dim Value"),
+    NOSE_CONE("NCDATA.CSV", "Mfg.","Part No.","Desc.","Units","Length","Outer Dia","L/D Ratio","Insert Length","Insert OD",
+            "Thickness","Shape","Config","Material","CG Loc","Mass Units","Mass","Base Ext. Len"),
+    PARACHUTE("PCDATA.CSV"),
+    SLEEVE("SLDATA.CSV"),
+    STREAMER("STDATA.CSV", "Mfg.", "Part No.", "Desc.", "Units", "Length", "Width", "Thickness", "Count", "Material"),
+    TUBE_COUPLER("TCDATA.CSV", "Mfg.", "Part No.", "Desc.", "Units", "ID", "OD", "Length", "Material", "Mass Units", "CG", "Mass", "AutoSize"),
+    TRANSITION("TRDATA.CSV", "Mfg.", "Part No.", "Desc.", "Units", "Front Insert Len", "Front Insert OD", "Front OD", "Length",
+            "Rear OD", "Core Dia.", "Rear Insert Len", "Rear Insert OD", "Thickness", "Config", "Material", "CG Loc",
+            "Mass Units", "Mass", "Shape", "Shape", "Shape", "Shape", "Shape", "Shape", "Shape", "Shape", "Shape", "Shape", "Shape", "Shape");
+
+    /**
+     * The default filename for the type of data.
+     */
+    private final String defaultFileName;
+
+    /**
+     * The column names.
+     */
+    private final String[] columns;
+
+    /**
+     * Constructor.
+     *
+     * @param theDefaultFileName  the default filename
+     * @param theColumns the array of column names in the file
+     */
+    private RocksimComponentFileType(final String theDefaultFileName, String... theColumns) {
+        defaultFileName = theDefaultFileName;
+        columns = theColumns;
+    }
+
+    /**
+     * Get the typical file name used for this type of component data.
+     *
+     * @return a filename
+     */
+    public String getDefaultFileName() {
+        return defaultFileName;
+    }
+
+    /**
+     * Try to be omniscient and figure out what kind of data file it is given an array of header (column) names.
+     *
+     * @param headers an array of column names
+     * @return the data type of the file, or null if unable to match the header names
+     */
+    public static RocksimComponentFileType determineType(String[] headers) {
+        RocksimComponentFileType[] types = values();
+        for (int i = 0; i < types.length; i++) {
+            RocksimComponentFileType type = types[i];
+            if (Arrays.equals(headers, type.columns)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/ShapeColumnParser.java b/core/src/net/sf/openrocket/preset/loader/ShapeColumnParser.java
new file mode 100644 (file)
index 0000000..05ea4e8
--- /dev/null
@@ -0,0 +1,64 @@
+package net.sf.openrocket.preset.loader;
+
+import java.util.Locale;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.TypedPropertyMap;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.rocketcomponent.Transition.Shape;
+import net.sf.openrocket.util.BugException;
+
+public class ShapeColumnParser extends BaseColumnParser {
+
+       public ShapeColumnParser() {
+               super("Shape");
+       }
+
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               Transition.Shape shape = null;
+               String lc = columnData.toLowerCase(Locale.US);
+               if ( "ogive".equals(lc) ) {
+                       shape = Shape.OGIVE;
+               }
+               if ( "conical".equals(lc) ) {
+                       shape = Shape.CONICAL;
+               }
+               if ( "cone".equals(lc) ) {
+                       shape = Shape.CONICAL;
+               }
+               if ( "elliptical".equals(lc) ) {
+                       shape = Shape.ELLIPSOID;
+               }
+               if ( "parabolic".equals(lc) ) {
+                       shape = Shape.PARABOLIC;
+               }
+               if ( "sears-haack".equals(lc) ) {
+                       shape = Shape.HAACK;
+               }
+               if ( "power-series".equals(lc) ) {
+                       shape = Shape.POWER;
+               }
+               // guessing at what "ps" means.  I think it might be power series.
+               if ( "ps".equals(lc) ) {
+                       shape = Shape.POWER;
+               }
+               if ( "1".equals(lc) ) {
+                       shape = Shape.OGIVE;
+               }
+               if( "0". equals(lc) ) {
+                       shape = Shape.CONICAL;
+               }
+               if( "". equals(lc) ) {
+                       shape = Shape.CONICAL;
+               }
+               if ( "3".equals(lc) ) {
+                       shape = Shape.ELLIPSOID;
+               }
+               if ( shape == null ) {
+                       throw new BugException("Invalid shape parameter: " + columnData);
+               }
+               props.put(ComponentPreset.SHAPE, shape);
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/StreamerLoader.java b/core/src/net/sf/openrocket/preset/loader/StreamerLoader.java
new file mode 100644 (file)
index 0000000..403ea0f
--- /dev/null
@@ -0,0 +1,59 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import java.io.File;
+
+public class StreamerLoader extends BaseComponentLoader {
+
+       private final MaterialHolder materials;
+
+       public StreamerLoader(MaterialHolder theMaterials, File theBasePath) {
+               super(theMaterials, theBasePath);
+               materials = theMaterials;
+
+        //The base component loader adds a bulk material loader, which is incompatible with the surface loader
+        //for a streamer.  Remove the file column parser here so we can set your own in the code that follows.
+        for (int i = 0; i < fileColumns.size(); i++) {
+            RocksimComponentFileColumnParser rocksimComponentFileColumnParser = fileColumns.get(i);
+            if (rocksimComponentFileColumnParser instanceof MaterialColumnParser) {
+                fileColumns.remove(rocksimComponentFileColumnParser);
+            }
+        }
+
+               fileColumns.add(new SurfaceMaterialColumnParser(materials,"Material",ComponentPreset.MATERIAL));
+               fileColumns.add(new DoubleUnitColumnParser("Length","Units",ComponentPreset.LENGTH));
+               fileColumns.add(new DoubleUnitColumnParser("Width","Units",ComponentPreset.WIDTH));
+               fileColumns.add(new DoubleUnitColumnParser("Thickness","Units",ComponentPreset.THICKNESS));
+       }
+
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.STREAMER;
+       }
+
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.STREAMER;
+       }
+
+
+       @Override
+       protected void postProcess(TypedPropertyMap props) {
+               super.postProcess(props);
+
+               // Fix the material since some files use bulk materials for streamers.
+               Double thickness = props.get( ComponentPreset.THICKNESS );
+               Material.Surface myMaterial = (Material.Surface) props.get( ComponentPreset.MATERIAL );
+
+               Material.Surface m = materials.getSurfaceMaterial(myMaterial, thickness);
+
+               props.put(ComponentPreset.MATERIAL, m!=null? m : myMaterial);
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/StringColumnParser.java b/core/src/net/sf/openrocket/preset/loader/StringColumnParser.java
new file mode 100644 (file)
index 0000000..c4d96a7
--- /dev/null
@@ -0,0 +1,20 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+public class StringColumnParser extends BaseColumnParser {
+
+       private TypedKey<String> propKey;
+       
+       public StringColumnParser(String columnHeader, TypedKey<String> propKey) {
+               super(columnHeader);
+               this.propKey = propKey;
+       }
+
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               props.put(propKey, columnData);
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/SurfaceMaterialColumnParser.java b/core/src/net/sf/openrocket/preset/loader/SurfaceMaterialColumnParser.java
new file mode 100644 (file)
index 0000000..703d128
--- /dev/null
@@ -0,0 +1,34 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.TypedKey;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+public class SurfaceMaterialColumnParser extends BaseColumnParser {
+       
+       private final MaterialHolder materialMap;
+       
+       private final TypedKey<Material> param;
+       
+       public SurfaceMaterialColumnParser(MaterialHolder materialMap, String columnName, TypedKey<Material> param) {
+               super(columnName);
+               this.param = param;
+               this.materialMap = materialMap;
+       }
+       
+       
+       @Override
+       protected void doParse(String columnData, String[] data, TypedPropertyMap props) {
+               
+               if (columnData == null || "".equals(columnData.trim())) {
+                       return;
+               }
+               
+               Material.Surface myMaterial = (Material.Surface) Databases.findMaterial(Material.Type.SURFACE, columnData, 0.0);
+               Material.Surface m = materialMap.getSurfaceMaterial(myMaterial, null);
+               props.put(param, m != null ? m : myMaterial);
+               
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/TransitionLoader.java b/core/src/net/sf/openrocket/preset/loader/TransitionLoader.java
new file mode 100644 (file)
index 0000000..a67695b
--- /dev/null
@@ -0,0 +1,30 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+
+import java.io.File;
+
+public class TransitionLoader extends NoseConeLoader {
+
+       public TransitionLoader(MaterialHolder materials, File theBasePath) {
+               super(materials, theBasePath);
+               fileColumns.add(new DoubleUnitColumnParser("Front Insert Len","Units",ComponentPreset.FORE_SHOULDER_LENGTH));
+               fileColumns.add(new DoubleUnitColumnParser("Front Insert OD","Units",ComponentPreset.FORE_SHOULDER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("Front OD","Units",ComponentPreset.FORE_OUTER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("Rear Insert Len","Units",ComponentPreset.AFT_SHOULDER_LENGTH));
+               fileColumns.add(new DoubleUnitColumnParser("Rear Insert OD","Units",ComponentPreset.AFT_SHOULDER_DIAMETER));
+               fileColumns.add(new DoubleUnitColumnParser("Rear OD","Units",ComponentPreset.AFT_OUTER_DIAMETER));
+       }
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.TRANSITION;
+       }
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.TRANSITION;
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/loader/TubeCouplerLoader.java b/core/src/net/sf/openrocket/preset/loader/TubeCouplerLoader.java
new file mode 100644 (file)
index 0000000..3a5706b
--- /dev/null
@@ -0,0 +1,24 @@
+package net.sf.openrocket.preset.loader;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+
+import java.io.File;
+
+public class TubeCouplerLoader extends BodyTubeLoader {
+
+       public TubeCouplerLoader(MaterialHolder materials, File theBasePath) {
+               super(materials, theBasePath);
+       }
+
+       @Override
+       protected Type getComponentPresetType() {
+               return ComponentPreset.Type.TUBE_COUPLER;
+       }
+
+       @Override
+       protected RocksimComponentFileType getFileType() {
+               return RocksimComponentFileType.TUBE_COUPLER;
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/BaseComponentDTO.java b/core/src/net/sf/openrocket/preset/xml/BaseComponentDTO.java
new file mode 100644 (file)
index 0000000..ca8c18f
--- /dev/null
@@ -0,0 +1,282 @@
+package net.sf.openrocket.preset.xml;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+import javax.xml.bind.DatatypeConverter;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlInlineBinaryData;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+import net.sf.openrocket.unit.UnitGroup;
+
+/**
+ * Base class for the external representation of all component presets.
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+public abstract class BaseComponentDTO {
+       
+       @XmlElement(name = "Manufacturer")
+       private String manufacturer;
+       @XmlElement(name = "PartNumber")
+       private String partNo;
+       @XmlElement(name = "Description")
+       private String description;
+       @XmlElement(name = "Material")
+       private AnnotatedMaterialDTO material;
+       @XmlElement(name = "Mass")
+       private AnnotatedMassDTO mass;
+       @XmlElement(name = "Filled")
+       private Boolean filled;
+       @XmlInlineBinaryData
+       @XmlJavaTypeAdapter(Base64Adapter.class)
+       @XmlElement(name = "Thumbnail")
+       private byte[] image;
+       
+       /**
+        * Default constructor.
+        */
+       protected BaseComponentDTO() {
+       }
+       
+       /**
+        * Constructor.
+        *
+        * @param preset  the preset to use to pull data values out of
+        *
+        * @throws net.sf.openrocket.util.BugException thrown if the expected body tube keys are not in the preset
+        */
+       protected BaseComponentDTO(final ComponentPreset preset) {
+               setManufacturer(preset.getManufacturer().getSimpleName());
+               setPartNo(preset.getPartNo());
+               if (preset.has(ComponentPreset.DESCRIPTION)) {
+                       setDescription(preset.get(ComponentPreset.DESCRIPTION));
+               }
+               if (preset.has(ComponentPreset.MATERIAL)) {
+                       setMaterial(new AnnotatedMaterialDTO(preset.get(ComponentPreset.MATERIAL)));
+               }
+               if (preset.has(ComponentPreset.MASS)) {
+                       setMass(preset.get(ComponentPreset.MASS));
+               }
+               if (preset.has(ComponentPreset.FILLED)) {
+                       setFilled(preset.get(ComponentPreset.FILLED));
+               }
+               if (preset.has(ComponentPreset.IMAGE)) {
+                       setImageData(preset.get(ComponentPreset.IMAGE));
+               }
+       }
+       
+       public String getManufacturer() {
+               return manufacturer;
+       }
+       
+       public void setManufacturer(final String theManufacturer) {
+               manufacturer = theManufacturer;
+       }
+       
+       public String getPartNo() {
+               return partNo;
+       }
+       
+       public void setPartNo(final String thePartNo) {
+               partNo = thePartNo;
+       }
+       
+       public String getDescription() {
+               return description;
+       }
+       
+       public void setDescription(final String theDescription) {
+               description = theDescription;
+       }
+       
+       public AnnotatedMaterialDTO getMaterial() {
+               return material;
+       }
+       
+       public void setMaterial(final AnnotatedMaterialDTO theMaterial) {
+               material = theMaterial;
+       }
+       
+       public double getMass() {
+               return mass.getValue();
+       }
+       
+       public void setMass(final AnnotatedMassDTO theMass) {
+               mass = theMass;
+       }
+       
+       public void setMass(final double theMass) {
+               mass = new AnnotatedMassDTO(theMass);
+       }
+       
+       public Boolean getFilled() {
+               return filled;
+       }
+       
+       public void setFilled(Boolean filled) {
+               this.filled = filled;
+       }
+       
+       public byte[] getImageData() {
+               return image;
+       }
+       
+       public void setImageData(final byte[] theImage) {
+               image = theImage;
+       }
+       
+       public BufferedImage getImage() throws IOException {
+               if (image != null) {
+                       return ImageIO.read(new ByteArrayInputStream(image));
+               }
+               return null;
+       }
+       
+       public void setImage(BufferedImage theImage) throws IOException {
+               if (theImage != null) {
+                       final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+                       ImageIO.write(theImage, "png", byteArrayOutputStream);
+                       image = byteArrayOutputStream.toByteArray();
+               }
+       }
+       
+       public abstract ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException;
+       
+       void addProps(TypedPropertyMap props, List<MaterialDTO> materialList) {
+               props.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer(manufacturer));
+               props.put(ComponentPreset.PARTNO, partNo);
+               if (description != null) {
+                       props.put(ComponentPreset.DESCRIPTION, description);
+               }
+               Material m = find(materialList, material);
+               if (m != null) {
+                       props.put(ComponentPreset.MATERIAL, find(materialList, material));
+               }
+               if (mass != null) {
+                       props.put(ComponentPreset.MASS, getMass());
+               }
+               if (filled != null) {
+                       props.put(ComponentPreset.FILLED, getFilled());
+               }
+               if (image != null) {
+                       props.put(ComponentPreset.IMAGE, image);
+               }
+       }
+       
+       protected Material find(List<MaterialDTO> materialList, AnnotatedMaterialDTO dto) {
+               if (dto == null) {
+                       return null;
+               }
+               for (int i = 0; i < materialList.size(); i++) {
+                       MaterialDTO materialDTO = materialList.get(i);
+                       if (materialDTO.getType().name().equals(dto.type) && materialDTO.getName().equals(dto.material)) {
+                               return materialDTO.asMaterial();
+                       }
+               }
+               
+               // Don't have one, first check OR's database
+               Material m = Databases.findMaterial(dto.getORMaterialType(), dto.material);
+               if (m != null) {
+                       return m;
+               }
+               
+               return Databases.findMaterial(dto.getORMaterialType(), dto.material, 0.0);
+               
+       }
+       
+       static class AnnotatedMaterialDTO {
+               @XmlAttribute(name = "Type")
+               private String type;
+               @XmlValue
+               private String material;
+               
+               AnnotatedMaterialDTO() {
+               }
+               
+               AnnotatedMaterialDTO(Material theMaterial) {
+                       type = theMaterial.getType().name();
+                       material = theMaterial.getName();
+               }
+               
+               public Material.Type getORMaterialType() {
+                       if ("BULK".equals(type)) {
+                               return Material.Type.BULK;
+                       } else if ("SURFACE".equals(type)) {
+                               return Material.Type.SURFACE;
+                       } else if ("LINE".equals(type)) {
+                               return Material.Type.LINE;
+                       }
+                       throw new IllegalArgumentException("Inavlid material type " + type + " specified for Component");
+               }
+       }
+       
+       static class AnnotatedLengthDTO {
+               @XmlAttribute(name = "Unit", required = false)
+               private String unitName = "m";
+               @XmlValue
+               private double length;
+               
+               AnnotatedLengthDTO() {
+               }
+               
+               AnnotatedLengthDTO(double length) {
+                       this.length = length;
+               }
+               
+               public double getValue() {
+                       return UnitGroup.UNITS_LENGTH.getUnit(unitName).fromUnit(length);
+               }
+       }
+       
+       static class AnnotatedMassDTO {
+               @XmlAttribute(name = "Unit", required = false)
+               private String unitName = "kg";
+               @XmlValue
+               private double mass;
+               
+               AnnotatedMassDTO() {
+               }
+               
+               AnnotatedMassDTO(double mass) {
+                       this.mass = mass;
+               }
+               
+               public double getValue() {
+                       return UnitGroup.UNITS_MASS.getUnit(unitName).fromUnit(mass);
+               }
+       }
+       
+       static class Base64Adapter extends XmlAdapter<String, byte[]> {
+               @Override
+               public byte[] unmarshal(String s) {
+                       if (s == null) {
+                               return null;
+                       }
+                       return DatatypeConverter.parseBase64Binary(s);
+               }
+               
+               @Override
+               public String marshal(byte[] bytes) {
+                       if (bytes == null) {
+                               return null;
+                       }
+                       return DatatypeConverter.printBase64Binary(bytes);
+               }
+       }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/BodyTubeDTO.java b/core/src/net/sf/openrocket/preset/xml/BodyTubeDTO.java
new file mode 100644 (file)
index 0000000..536944f
--- /dev/null
@@ -0,0 +1,100 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * Body tube preset XML handler.
+ */
+@XmlRootElement(name = "BodyTube")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class BodyTubeDTO extends BaseComponentDTO {
+
+    @XmlElement(name = "InsideDiameter")
+    private AnnotatedLengthDTO insideDiameter;
+    @XmlElement(name = "OutsideDiameter")
+    private AnnotatedLengthDTO outsideDiameter;
+    @XmlElement(name = "Length")
+    private AnnotatedLengthDTO length;
+
+    /**
+     * Default constructor.
+     */
+    public BodyTubeDTO() {
+    }
+
+    /**
+     * Most-useful constructor that maps a BodyTube preset to a BodyTubeDTO.
+     *
+     * @param preset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected body tube keys are not in the preset
+     */
+    public BodyTubeDTO(final ComponentPreset preset) {
+        super(preset);
+        setInsideDiameter(preset.get(ComponentPreset.INNER_DIAMETER));
+        setOutsideDiameter(preset.get(ComponentPreset.OUTER_DIAMETER));
+        setLength(preset.get(ComponentPreset.LENGTH));
+    }
+
+    public double getInsideDiameter() {
+        return insideDiameter.getValue();
+    }
+
+    public void setInsideDiameter( final AnnotatedLengthDTO theLength ) {
+       insideDiameter = theLength;
+    }
+    
+    public void setInsideDiameter(final double theId) {
+        insideDiameter = new AnnotatedLengthDTO(theId);
+    }
+
+    public double getOutsideDiameter() {
+        return outsideDiameter.getValue();
+    }
+
+    public void setOutsideDiameter(final AnnotatedLengthDTO theOd) {
+        outsideDiameter = theOd;
+    }
+
+    public void setOutsideDiameter(final double theOd) {
+        outsideDiameter = new AnnotatedLengthDTO(theOd);
+    }
+
+    public double getLength() {
+        return length.getValue();
+    }
+
+    public void setLength(final AnnotatedLengthDTO theLength) {
+        length = theLength;
+    }
+
+    public void setLength(final double theLength) {
+        length = new AnnotatedLengthDTO(theLength);
+    }
+
+    @Override
+    public ComponentPreset asComponentPreset(java.util.List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        return asComponentPreset(ComponentPreset.Type.BODY_TUBE, materials);
+    }
+
+    public ComponentPreset asComponentPreset(ComponentPreset.Type type, List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        TypedPropertyMap props = new TypedPropertyMap();
+        addProps(props, materials);
+        props.put(ComponentPreset.INNER_DIAMETER, this.getInsideDiameter());
+        props.put(ComponentPreset.OUTER_DIAMETER, this.getOutsideDiameter());
+        props.put(ComponentPreset.LENGTH, this.getLength());
+        props.put(ComponentPreset.TYPE, type);
+
+        return ComponentPresetFactory.create(props);
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/BulkHeadDTO.java b/core/src/net/sf/openrocket/preset/xml/BulkHeadDTO.java
new file mode 100644 (file)
index 0000000..1db3dd7
--- /dev/null
@@ -0,0 +1,78 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * Bulkhead preset XML handler.
+ */
+@XmlRootElement(name = "BulkHead")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class BulkHeadDTO extends BaseComponentDTO {
+
+    @XmlElement(name = "OutsideDiameter")
+    private AnnotatedLengthDTO outsideDiameter;
+    @XmlElement(name = "Length")
+    private AnnotatedLengthDTO length;
+
+    public BulkHeadDTO() {
+    }
+
+    /**
+     * Most-useful constructor that maps a BulkHead preset to a BulkHeadDTO.
+     *
+     * @param thePreset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected bulk head keys are not in the preset
+     */
+    public BulkHeadDTO(final ComponentPreset thePreset) {
+        super(thePreset);
+        setOutsideDiameter(thePreset.get(ComponentPreset.OUTER_DIAMETER));
+        setLength(thePreset.get(ComponentPreset.LENGTH));
+    }
+
+    public double getOutsideDiameter() {
+        return outsideDiameter.getValue();
+    }
+
+    public void setOutsideDiameter(final AnnotatedLengthDTO theOutsideDiameter) {
+        outsideDiameter = theOutsideDiameter;
+    }
+
+    public void setOutsideDiameter(final double theOutsideDiameter) {
+        outsideDiameter = new AnnotatedLengthDTO(theOutsideDiameter);
+    }
+
+    public double getLength() {
+        return length.getValue();
+    }
+
+    public void setLength(final AnnotatedLengthDTO theLength) {
+        length = theLength;
+    }
+
+    public void setLength(final double theLength) {
+        length = new AnnotatedLengthDTO(theLength);
+    }
+
+    @Override
+    public ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        TypedPropertyMap props = new TypedPropertyMap();
+        addProps(props, materials);
+        props.put(ComponentPreset.OUTER_DIAMETER, this.getOutsideDiameter());
+        props.put(ComponentPreset.LENGTH, this.getLength());
+        props.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+
+        return ComponentPresetFactory.create(props);
+    }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/CenteringRingDTO.java b/core/src/net/sf/openrocket/preset/xml/CenteringRingDTO.java
new file mode 100644 (file)
index 0000000..9866a15
--- /dev/null
@@ -0,0 +1,41 @@
+
+package net.sf.openrocket.preset.xml;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+
+/**
+ * Centering Ring preset XML handler.
+ */
+@XmlRootElement(name = "CenteringRing")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class CenteringRingDTO extends BodyTubeDTO {
+
+    /**
+     * Default constructor.
+     */
+    public CenteringRingDTO() {
+    }
+
+    /**
+     * Most-useful constructor that maps a TubeCoupler preset to a TubeCouplerDTO.
+     *
+     * @param thePreset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected tube coupler keys are not in the preset
+     */
+    public CenteringRingDTO(ComponentPreset thePreset) {
+        super(thePreset);
+    }
+
+    @Override
+    public ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        return super.asComponentPreset(ComponentPreset.Type.CENTERING_RING, materials);
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/EngineBlockDTO.java b/core/src/net/sf/openrocket/preset/xml/EngineBlockDTO.java
new file mode 100644 (file)
index 0000000..6c3f61f
--- /dev/null
@@ -0,0 +1,40 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * Engine block preset XML handler.
+ */
+@XmlRootElement(name = "EngineBlock")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class EngineBlockDTO extends BodyTubeDTO {
+
+    /**
+     * Default constructor.
+     */
+    public EngineBlockDTO() {
+    }
+
+    /**
+     * Most-useful constructor that maps a EngineBlock preset to a EngineBlockDTO.
+     *
+     * @param thePreset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected engine block keys are not in the preset
+     */
+    public EngineBlockDTO(ComponentPreset thePreset) {
+        super(thePreset);
+    }
+
+    @Override
+    public ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        return super.asComponentPreset(ComponentPreset.Type.ENGINE_BLOCK, materials);
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/LaunchLugDTO.java b/core/src/net/sf/openrocket/preset/xml/LaunchLugDTO.java
new file mode 100644 (file)
index 0000000..e723861
--- /dev/null
@@ -0,0 +1,100 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * Body tube preset XML handler.
+ */
+@XmlRootElement(name = "LaunchLug")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class LaunchLugDTO extends BaseComponentDTO {
+
+    @XmlElement(name = "InsideDiameter")
+    private AnnotatedLengthDTO insideDiameter;
+    @XmlElement(name = "OutsideDiameter")
+    private AnnotatedLengthDTO outsideDiameter;
+    @XmlElement(name = "Length")
+    private AnnotatedLengthDTO length;
+
+    /**
+     * Default constructor.
+     */
+    public LaunchLugDTO() {
+    }
+
+    /**
+     * Most-useful constructor that maps a LaunchLug preset to a LaunchLugDTO.
+     *
+     * @param preset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected body tube keys are not in the preset
+     */
+    public LaunchLugDTO(final ComponentPreset preset) {
+        super(preset);
+        setInsideDiameter(preset.get(ComponentPreset.INNER_DIAMETER));
+        setOutsideDiameter(preset.get(ComponentPreset.OUTER_DIAMETER));
+        setLength(preset.get(ComponentPreset.LENGTH));
+    }
+
+    public double getInsideDiameter() {
+        return insideDiameter.getValue();
+    }
+
+    public void setInsideDiameter( final AnnotatedLengthDTO theLength ) {
+       insideDiameter = theLength;
+    }
+    
+    public void setInsideDiameter(final double theId) {
+        insideDiameter = new AnnotatedLengthDTO(theId);
+    }
+
+    public double getOutsideDiameter() {
+        return outsideDiameter.getValue();
+    }
+
+    public void setOutsideDiameter(final AnnotatedLengthDTO theOd) {
+        outsideDiameter = theOd;
+    }
+
+    public void setOutsideDiameter(final double theOd) {
+        outsideDiameter = new AnnotatedLengthDTO(theOd);
+    }
+
+    public double getLength() {
+        return length.getValue();
+    }
+
+    public void setLength(final AnnotatedLengthDTO theLength) {
+        length = theLength;
+    }
+
+    public void setLength(final double theLength) {
+        length = new AnnotatedLengthDTO(theLength);
+    }
+
+    @Override
+    public ComponentPreset asComponentPreset(java.util.List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        return asComponentPreset(ComponentPreset.Type.LAUNCH_LUG, materials);
+    }
+
+    public ComponentPreset asComponentPreset(ComponentPreset.Type type, List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        TypedPropertyMap props = new TypedPropertyMap();
+        addProps(props, materials);
+        props.put(ComponentPreset.INNER_DIAMETER, this.getInsideDiameter());
+        props.put(ComponentPreset.OUTER_DIAMETER, this.getOutsideDiameter());
+        props.put(ComponentPreset.LENGTH, this.getLength());
+        props.put(ComponentPreset.TYPE, type);
+
+        return ComponentPresetFactory.create(props);
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/MaterialDTO.java b/core/src/net/sf/openrocket/preset/xml/MaterialDTO.java
new file mode 100644 (file)
index 0000000..abcebda
--- /dev/null
@@ -0,0 +1,114 @@
+package net.sf.openrocket.preset.xml;
+
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import net.sf.openrocket.database.Databases;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.util.Chars;
+
+/**
+ * XML handler for materials.
+ */
+@XmlRootElement(name = "Material")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class MaterialDTO {
+       
+       @XmlElement(name = "Name")
+       private String name;
+       @XmlElement(name = "Density")
+       private double density;
+       @XmlElement(name = "Type")
+       private MaterialTypeDTO type;
+       @XmlAttribute(name = "UnitsOfMeasure")
+       private String uom;
+       
+       /**
+        * Default constructor.
+        */
+       public MaterialDTO() {
+       }
+       
+       public MaterialDTO(final Material theMaterial) {
+               this(theMaterial.getName(), theMaterial.getDensity(), MaterialTypeDTO.asDTO(theMaterial.getType()),
+                               theMaterial.getType().getUnitGroup().getDefaultUnit().toString());
+       }
+       
+       public MaterialDTO(final String theName, final double theDensity, final MaterialTypeDTO theType, final String theUom) {
+               name = theName;
+               density = theDensity;
+               type = theType;
+               uom = theUom;
+       }
+       
+       public String getName() {
+               return name;
+       }
+       
+       public void setName(final String theName) {
+               name = theName;
+       }
+       
+       public double getDensity() {
+               return density;
+       }
+       
+       public void setDensity(final double theDensity) {
+               density = theDensity;
+       }
+       
+       public MaterialTypeDTO getType() {
+               return type;
+       }
+       
+       public void setType(final MaterialTypeDTO theType) {
+               type = theType;
+       }
+       
+       public String getUom() {
+               return uom;
+       }
+       
+       public void setUom(final String theUom) {
+               uom = theUom;
+       }
+       
+       Material asMaterial() {
+               return Databases.findMaterial(type.getORMaterialType(), name, density);
+       }
+       
+       
+       /**
+        * Special directive to the JAXB system.  After the object is parsed from xml,
+        * we replace the '2' with Chars.SQUARED, and '3' with Chars.CUBED.  Just the 
+        * opposite transformation as doen in beforeMarshal.
+        * @param unmarshaller
+        * @param parent
+        */
+       @SuppressWarnings("unused")
+       private void afterUnmarshal(Unmarshaller unmarshaller, Object parent) {
+               if (uom != null) {
+                       uom = uom.replace('2', Chars.SQUARED);
+                       uom = uom.replace('3', Chars.CUBED);
+               }
+       }
+       
+       /**
+        * Special directive to the JAXB system.  Before the object is serialized into xml,
+        * we strip out the special unicode characters for cubed and squared so they appear
+        * as simple "3" and "2" chars.  The reverse transformation is done in afterUnmarshal.
+        * @param marshaller
+        */
+       @SuppressWarnings("unused")
+       private void beforeMarshal(Marshaller marshaller) {
+               if (uom != null) {
+                       uom = uom.replace(Chars.SQUARED, '2');
+                       uom = uom.replace(Chars.CUBED, '3');
+               }
+       }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/MaterialTypeDTO.java b/core/src/net/sf/openrocket/preset/xml/MaterialTypeDTO.java
new file mode 100644 (file)
index 0000000..93a83b3
--- /dev/null
@@ -0,0 +1,35 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.material.Material;
+
+/**
+ * A mirror enum of Material.Type, for the purposes of mapping to/from an XML representation.
+ */
+public enum MaterialTypeDTO {
+
+    LINE (Material.Type.LINE),
+    SURFACE (Material.Type.SURFACE),
+    BULK (Material.Type.BULK);
+
+    private Material.Type corollary;
+
+    private MaterialTypeDTO(final Material.Type theCorollary) {
+        corollary = theCorollary;
+    }
+
+    public static MaterialTypeDTO asDTO(Material.Type targetType) {
+        MaterialTypeDTO[] values = values();
+        for (int i = 0; i < values.length; i++) {
+            MaterialTypeDTO value = values[i];
+            if (value.corollary.equals(targetType)) {
+                return value;
+            }
+        }
+        return BULK; //default
+    }
+
+    public Material.Type getORMaterialType() {
+        return corollary;
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/NoseConeDTO.java b/core/src/net/sf/openrocket/preset/xml/NoseConeDTO.java
new file mode 100644 (file)
index 0000000..0a071d6
--- /dev/null
@@ -0,0 +1,154 @@
+package net.sf.openrocket.preset.xml;
+
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+/**
+ * A NoseCone preset XML handler.
+ */
+@XmlRootElement(name = "NoseCone")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class NoseConeDTO extends BaseComponentDTO {
+
+    @XmlElement(name = "Shape")
+    private ShapeDTO shape;
+    @XmlElement(name = "OutsideDiameter")
+    private AnnotatedLengthDTO outsideDiameter;
+    @XmlElement(name = "ShoulderDiameter")
+    private AnnotatedLengthDTO shoulderDiameter;
+    @XmlElement(name = "ShoulderLength")
+    private AnnotatedLengthDTO shoulderLength;
+    @XmlElement(name = "Length")
+    private AnnotatedLengthDTO length;
+
+    @XmlElement(name = "Thickness")
+    private AnnotatedLengthDTO thickness;
+    
+    /**
+     * Default constructor.
+     */
+    public NoseConeDTO() {
+    }
+
+    /**
+     * Constructor that
+     *
+     * @param thePreset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected body tube keys are not in the preset
+     */
+    public NoseConeDTO(final ComponentPreset thePreset) {
+        super(thePreset);
+        setShape(ShapeDTO.asDTO(thePreset.get(ComponentPreset.SHAPE)));
+        setOutsideDiameter(thePreset.get(ComponentPreset.AFT_OUTER_DIAMETER));
+        if ( thePreset.has(ComponentPreset.AFT_SHOULDER_DIAMETER)) {
+               setShoulderDiameter(thePreset.get(ComponentPreset.AFT_SHOULDER_DIAMETER));
+        }
+        if ( thePreset.has(ComponentPreset.AFT_SHOULDER_LENGTH)) {
+               setShoulderLength(thePreset.get(ComponentPreset.AFT_SHOULDER_LENGTH));
+        }
+        setLength(thePreset.get(ComponentPreset.LENGTH));
+        if ( thePreset.has(ComponentPreset.THICKNESS)) {
+               setThickness(thePreset.get(ComponentPreset.THICKNESS));
+        }
+    }
+
+    public ShapeDTO getShape() {
+        return shape;
+    }
+
+    public void setShape(final ShapeDTO theShape) {
+        shape = theShape;
+    }
+
+    public double getOutsideDiameter() {
+        return outsideDiameter.getValue();
+    }
+
+    public void setOutsideDiameter(final AnnotatedLengthDTO theOutsideDiameter) {
+        outsideDiameter = theOutsideDiameter;
+    }
+
+    public void setOutsideDiameter(final double theOutsideDiameter) {
+        outsideDiameter = new AnnotatedLengthDTO(theOutsideDiameter);
+    }
+
+    public double getShoulderDiameter() {
+        return shoulderDiameter.getValue();
+    }
+
+    public void setShoulderDiameter(final AnnotatedLengthDTO theShoulderDiameter) {
+        shoulderDiameter = theShoulderDiameter;
+    }
+
+    public void setShoulderDiameter(final double theShoulderDiameter) {
+        shoulderDiameter = new AnnotatedLengthDTO(theShoulderDiameter);
+    }
+
+    public double getShoulderLength() {
+        return shoulderLength.getValue();
+    }
+
+    public void setShoulderLength(final AnnotatedLengthDTO theShoulderLength) {
+       shoulderLength = theShoulderLength;
+    }
+
+    public void setShoulderLength(final double theShoulderLength) {
+       shoulderLength = new AnnotatedLengthDTO(theShoulderLength);
+    }
+
+    public double getLength() {
+        return length.getValue();
+    }
+
+    public void setLength(final AnnotatedLengthDTO theLength) {
+        length = theLength;
+    }
+
+    public void setLength(final double theLength) {
+        length = new AnnotatedLengthDTO(theLength);
+    }
+
+    public double getThickness() {
+               return thickness.getValue();
+       }
+
+       public void setThickness(AnnotatedLengthDTO thickness) {
+               this.thickness = thickness;
+       }
+
+       public void setThickness(double thickness) {
+               this.thickness = new AnnotatedLengthDTO(thickness);
+       }
+
+       @Override
+       public ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        TypedPropertyMap props = new TypedPropertyMap();
+        addProps(props, materials);
+        props.put(ComponentPreset.SHAPE, shape.getORShape());
+        props.put(ComponentPreset.AFT_OUTER_DIAMETER, this.getOutsideDiameter());
+        if ( shoulderLength != null ) {
+               props.put(ComponentPreset.AFT_SHOULDER_LENGTH, this.getShoulderLength());
+        }
+        if ( shoulderDiameter != null ) {
+               props.put(ComponentPreset.AFT_SHOULDER_DIAMETER, this.getShoulderDiameter());
+        }
+        props.put(ComponentPreset.LENGTH, this.getLength());
+        props.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+        if ( thickness != null ) {
+               props.put(ComponentPreset.THICKNESS, this.getThickness());
+        }
+
+        return ComponentPresetFactory.create(props);
+    }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/OpenRocketComponentDTO.java b/core/src/net/sf/openrocket/preset/xml/OpenRocketComponentDTO.java
new file mode 100644 (file)
index 0000000..69da4e8
--- /dev/null
@@ -0,0 +1,93 @@
+package net.sf.openrocket.preset.xml;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlElementRefs;
+import javax.xml.bind.annotation.XmlElementWrapper;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+
+/**
+ * The real 'root' element in an XML document.
+ */
+@XmlRootElement(name = "OpenRocketComponent")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class OpenRocketComponentDTO {
+
+    @XmlElement(name = "Version")
+    private final String version = "0.1";
+
+    @XmlElementWrapper(name = "Materials")
+    @XmlElement(name = "Material")
+    List<MaterialDTO> materials = new ArrayList<MaterialDTO>();
+
+    @XmlElementWrapper(name = "Components")
+    @XmlElementRefs({
+            @XmlElementRef(name = "BodyTubes", type = BodyTubeDTO.class),
+            @XmlElementRef(name = "TubeCouplers", type = TubeCouplerDTO.class),
+            @XmlElementRef(name = "NoseCones", type = NoseConeDTO.class),
+            @XmlElementRef(name = "Transitions", type = TransitionDTO.class),
+            @XmlElementRef(name = "BulkHeads", type = BulkHeadDTO.class),
+            @XmlElementRef(name = "CenteringRings", type = CenteringRingDTO.class),
+            @XmlElementRef(name = "EngineBlocks", type = EngineBlockDTO.class),
+            @XmlElementRef(name = "LaunchLugs", type = LaunchLugDTO.class),
+            @XmlElementRef(name = "Streamers", type = StreamerDTO.class),
+            @XmlElementRef(name = "Parachutes", type = ParachuteDTO.class)})
+    private List<BaseComponentDTO> components = new ArrayList<BaseComponentDTO>();
+
+    public OpenRocketComponentDTO() {
+    }
+
+    public OpenRocketComponentDTO(final List<MaterialDTO> theMaterials, final List<BaseComponentDTO> theComponents) {
+        materials = theMaterials;
+        components = theComponents;
+    }
+
+    public List<MaterialDTO> getMaterials() {
+        return materials;
+    }
+
+    public void addMaterial(final MaterialDTO theMaterial) {
+        materials.add(theMaterial);
+    }
+
+    public void setMaterials(final List<MaterialDTO> theMaterials) {
+        materials = theMaterials;
+    }
+
+    public List<BaseComponentDTO> getComponents() {
+        return components;
+    }
+
+    public void addComponent(final BaseComponentDTO theComponent) {
+        components.add(theComponent);
+    }
+
+    public void setComponents(final List<BaseComponentDTO> theComponents) {
+        components = theComponents;
+    }
+
+    public List<ComponentPreset> asComponentPresets() throws InvalidComponentPresetException {
+        List<ComponentPreset> result = new ArrayList<ComponentPreset>(components.size());
+        for (int i = 0; i < components.size(); i++) {
+            result.add(components.get(i).asComponentPreset(materials));
+        }
+        return result;
+    }
+    
+    public List<Material> asMaterialList() {
+       List<Material> result = new ArrayList<Material>( materials.size() );
+       for( MaterialDTO material : materials ) {
+               result.add( material.asMaterial() );
+       }
+       return result;
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/OpenRocketComponentLoader.java b/core/src/net/sf/openrocket/preset/xml/OpenRocketComponentLoader.java
new file mode 100644 (file)
index 0000000..a27712c
--- /dev/null
@@ -0,0 +1,44 @@
+package net.sf.openrocket.preset.xml;
+
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Collection;
+import java.util.List;
+
+import javax.xml.bind.JAXBException;
+
+import net.sf.openrocket.file.Loader;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.BugException;
+
+public class OpenRocketComponentLoader  implements Loader<ComponentPreset> {
+
+       private static final LogHelper log = Application.getLogger();
+
+       @Override
+       public Collection<ComponentPreset> load(InputStream stream,     String filename) {
+
+               log.debug("Loading presets from file " + filename);
+               
+               if ( ! (stream instanceof BufferedInputStream) ) {
+                       stream = new BufferedInputStream(stream);
+               }
+
+               try {
+                       List<ComponentPreset> presets;
+                       presets = (new OpenRocketComponentSaver().unmarshalFromOpenRocketComponent( new InputStreamReader (stream))).asComponentPresets();
+                       log.debug("ComponentPreset file " + filename + " contained " + presets.size() + " presets");
+                       return presets;
+               } catch (JAXBException e) {
+                       throw new BugException("Unable to parse file: "+ filename, e);
+               } catch (InvalidComponentPresetException e) {
+                       throw new BugException("Unable to parse file: "+ filename, e);
+               }
+
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/OpenRocketComponentSaver.java b/core/src/net/sf/openrocket/preset/xml/OpenRocketComponentSaver.java
new file mode 100644 (file)
index 0000000..934d4be
--- /dev/null
@@ -0,0 +1,206 @@
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.startup.Application;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * The active manager class that is the entry point for reading and writing *.orc files.
+ */
+public class OpenRocketComponentSaver {
+
+    /**
+     * The JAXBContext.  JAXBContext is thread-safe.
+     */
+    private static JAXBContext context = null;
+
+    static {
+        try {
+            context = JAXBContext.newInstance(OpenRocketComponentDTO.class);
+        }
+        catch (JAXBException jaxb) {
+            Application.getLogger().error("Unable to create JAXBContext for loading of *.orc files.", jaxb);
+        }
+    }
+
+    public boolean save(File file, List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
+                                                                                                     JAXBException,
+                                                                                                     IOException {
+        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
+        writer.write(marshalToOpenRocketComponent(theMaterialList, thePresetList));
+        writer.flush();
+        writer.close();
+        return true;
+    }
+
+    /**
+     * This method marshals a list of materials and ComponentPresets into an .orc formatted XML string.
+     *
+     * @param theMaterialList the list of materials to be included
+     * @param thePresetList   the list of presets to be included
+     *
+     * @return ORC-compliant XML
+     *
+     * @throws JAXBException
+     */
+    public String marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
+                                                                                                                    JAXBException {
+        /** The context is thread-safe, but marshallers are not.  Create a local one. */
+        Marshaller marshaller = context.createMarshaller();
+        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+        StringWriter sw = new StringWriter();
+
+        // We're going to sort the initial data since that makes the output much easier on the eyes.
+
+        Collections.sort(theMaterialList, new Comparator<Material>() {
+
+                       @Override
+                       public int compare(Material o1, Material o2) {
+                               return o1.getName().compareTo( o2.getName() );
+                       }
+
+        });
+
+        Collections.sort(thePresetList, new Comparator<ComponentPreset>() {
+
+                       @Override
+                       public int compare(ComponentPreset o1, ComponentPreset o2) {
+                               int manucmp = o1.getManufacturer().getSimpleName().compareTo( o2.getManufacturer().getSimpleName() );
+
+                               if ( manucmp != 0 ) {
+                                       return manucmp;
+                               }
+
+                               return o1.getPartNo().compareTo( o2.getPartNo());
+                       }
+
+        });
+
+        marshaller.marshal(toOpenRocketComponentDTO(theMaterialList, thePresetList), sw);
+        return sw.toString();
+
+    }
+
+    /**
+     * This method unmarshals from a Reader that is presumed to be open on an XML file in .orc format.
+     *
+     * @param is an open reader; StringBufferInputStream could not be used because it's deprecated and does not handle
+     *           UTF characters correctly
+     *
+     * @return a list of ComponentPresets
+     *
+     * @throws InvalidComponentPresetException
+     *
+     */
+    public OpenRocketComponentDTO unmarshalFromOpenRocketComponent(Reader is) throws JAXBException,
+                                                                                    InvalidComponentPresetException {
+        return fromOpenRocketComponent(is);
+    }
+
+    /**
+     * Write an XML representation of a list of presets.
+     *
+     * @param dest            the stream to write the data to
+     * @param theMaterialList the list of materials to be included
+     * @param thePresetList   the list of presets to be included
+     *
+     * @throws JAXBException
+     * @throws IOException   thrown if the stream could not be written
+     */
+    public void save(OutputStream dest, List<Material> theMaterialList, List<ComponentPreset> thePresetList) throws
+                                                                                                             IOException,
+                                                                                                             JAXBException {
+        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, "UTF-8"));
+        writer.write(marshalToOpenRocketComponent(theMaterialList, thePresetList));
+        writer.flush();
+        writer.close();
+    }
+
+    /**
+     * Read from an open Reader instance XML in .orc format and reconstruct an OpenRocketComponentDTO instance.
+     *
+     * @param is an open Reader; assumed to be opened on a file of XML in .orc format
+     *
+     * @return the OpenRocketComponentDTO that is a POJO representation of the XML; null if the data could not be read
+     *         or was in an invalid format
+     */
+    private OpenRocketComponentDTO fromOpenRocketComponent(Reader is) throws JAXBException {
+        /** The context is thread-safe, but unmarshallers are not.  Create a local one. */
+        Unmarshaller unmarshaller = context.createUnmarshaller();
+        return (OpenRocketComponentDTO) unmarshaller.unmarshal(is); //new StreamSource(is));
+    }
+
+    /**
+     * Root conversion method.  It iterates over all subcomponents.
+     *
+     * @return a corresponding ORC representation
+     */
+    private OpenRocketComponentDTO toOpenRocketComponentDTO(List<Material> theMaterialList, List<ComponentPreset> thePresetList) {
+        OpenRocketComponentDTO rsd = new OpenRocketComponentDTO();
+
+        if (theMaterialList != null) {
+            for (Material material : theMaterialList) {
+                rsd.addMaterial(new MaterialDTO(material));
+            }
+        }
+
+        if (thePresetList != null) {
+            for (ComponentPreset componentPreset : thePresetList) {
+                rsd.addComponent(toComponentDTO(componentPreset));
+            }
+        }
+        return rsd;
+    }
+
+    /**
+     * Factory method that maps a preset to the corresponding DTO handler.
+     *
+     * @param thePreset the preset for which a handler will be found
+     *
+     * @return a subclass of BaseComponentDTO that can be used for marshalling/unmarshalling a preset; null if not found
+     *         for the preset type
+     */
+    private static BaseComponentDTO toComponentDTO(ComponentPreset thePreset) {
+        switch (thePreset.getType()) {
+            case BODY_TUBE:
+                return new BodyTubeDTO(thePreset);
+            case TUBE_COUPLER:
+                return new TubeCouplerDTO(thePreset);
+            case NOSE_CONE:
+                return new NoseConeDTO(thePreset);
+            case TRANSITION:
+                return new TransitionDTO(thePreset);
+            case BULK_HEAD:
+                return new BulkHeadDTO(thePreset);
+            case CENTERING_RING:
+                return new CenteringRingDTO(thePreset);
+            case ENGINE_BLOCK:
+                return new EngineBlockDTO(thePreset);
+            case LAUNCH_LUG:
+                return new LaunchLugDTO(thePreset);
+            case STREAMER:
+                return new StreamerDTO(thePreset);
+            case PARACHUTE:
+                return new ParachuteDTO(thePreset);
+        }
+
+        return null;
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/ParachuteDTO.java b/core/src/net/sf/openrocket/preset/xml/ParachuteDTO.java
new file mode 100644 (file)
index 0000000..f7056c0
--- /dev/null
@@ -0,0 +1,140 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+import net.sf.openrocket.preset.xml.BaseComponentDTO.AnnotatedMaterialDTO;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * Streamer preset XML handler.
+ */
+@XmlRootElement(name = "Parachute")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class ParachuteDTO extends BaseComponentDTO {
+
+    @XmlElement(name = "Diameter")
+    private AnnotatedLengthDTO diameter;
+    @XmlElement(name = "Sides")
+    private Integer sides;
+    @XmlElement(name = "LineCount")
+    private Integer lineCount;
+    @XmlElement(name = "LineLength")
+    private AnnotatedLengthDTO lineLength;
+    
+    @XmlElement(name = "LineMaterial")
+       private AnnotatedMaterialDTO lineMaterial;
+
+    /**
+     * Default constructor.
+     */
+    public ParachuteDTO() {
+    }
+
+    public double getDiameter() {
+               return diameter.getValue();
+       }
+
+       public void setDiameter(AnnotatedLengthDTO diameter) {
+               this.diameter = diameter;
+       }
+       public void setDiameter(double diameter) {
+               this.diameter = new AnnotatedLengthDTO(diameter);
+       }
+
+       public Integer getSides() {
+               return sides;
+       }
+
+       public void setSides(Integer sides) {
+               this.sides = sides;
+       }
+
+       public Integer getLineCount() {
+               return lineCount;
+       }
+
+       public void setLineCount(Integer lineCount) {
+               this.lineCount = lineCount;
+       }
+
+       public double getLineLength() {
+               return lineLength.getValue();
+       }
+
+       public void setLineLength(AnnotatedLengthDTO lineLength) {
+               this.lineLength = lineLength;
+       }
+
+       public void setLineLength(double lineLength) {
+               this.lineLength = new AnnotatedLengthDTO(lineLength);
+       }
+
+       public AnnotatedMaterialDTO getLineMaterial() {
+               return lineMaterial;
+       }
+
+       public void setLineMaterial(AnnotatedMaterialDTO lineMaterial) {
+               this.lineMaterial = lineMaterial;
+       }
+
+       /**
+     * Most-useful constructor that maps a BodyTube preset to a BodyTubeDTO.
+     *
+     * @param preset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected body tube keys are not in the preset
+     */
+    public ParachuteDTO(final ComponentPreset preset) {
+        super(preset);
+        setDiameter(preset.get(ComponentPreset.DIAMETER));
+        setLineCount(preset.get(ComponentPreset.LINE_COUNT));
+        if ( preset.has(ComponentPreset.LINE_LENGTH)) {
+            setLineLength(preset.get(ComponentPreset.LINE_LENGTH));
+        }
+        if ( preset.has(ComponentPreset.SIDES)) {
+               setSides(preset.get(ComponentPreset.SIDES));
+        }
+        if ( preset.has(ComponentPreset.LINE_MATERIAL)) {
+               setLineMaterial(new AnnotatedMaterialDTO(preset.get(ComponentPreset.LINE_MATERIAL)));
+        }
+    }
+
+    @Override
+    public ComponentPreset asComponentPreset(java.util.List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        return asComponentPreset(ComponentPreset.Type.PARACHUTE, materials);
+    }
+
+    public ComponentPreset asComponentPreset(ComponentPreset.Type type, List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        TypedPropertyMap props = new TypedPropertyMap();
+        addProps(props, materials);
+        // TODO - seems some vendors use a bulk material for the sheet along with a Thickness.
+        // need to fix the MATERIAL packed into the componentpreset.
+        props.put(ComponentPreset.TYPE, type);
+        props.put(ComponentPreset.DIAMETER, this.getDiameter());
+        props.put(ComponentPreset.LINE_COUNT, this.getLineCount());
+        if ( this.lineLength != null ) {
+               props.put(ComponentPreset.LINE_LENGTH, this.getLineLength());
+        }
+        if ( this.sides != null ) {
+               props.put(ComponentPreset.SIDES, this.getSides());
+        }
+        if ( this.lineMaterial != null ) {
+               Material m = find(materials, this.lineMaterial);
+               if ( m != null ) {
+                       props.put(ComponentPreset.LINE_MATERIAL, m);
+               }
+        }
+
+        return ComponentPresetFactory.create(props);
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/ShapeDTO.java b/core/src/net/sf/openrocket/preset/xml/ShapeDTO.java
new file mode 100644 (file)
index 0000000..d85fbcb
--- /dev/null
@@ -0,0 +1,41 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.rocketcomponent.Transition;
+
+import javax.xml.bind.annotation.XmlEnum;
+
+/**
+ * A mirror class to Transition.Shape to adapt that class to/from XML.
+ */
+@XmlEnum(String.class)
+public enum ShapeDTO {
+
+    CONICAL (Transition.Shape.CONICAL),
+    OGIVE   (Transition.Shape.OGIVE),
+    ELLIPSOID (Transition.Shape.ELLIPSOID),
+    POWER (Transition.Shape.POWER),
+    PARABOLIC (Transition.Shape.PARABOLIC),
+    HAACK (Transition.Shape.HAACK);
+
+    private Transition.Shape corollary;
+
+    private ShapeDTO(Transition.Shape theShape) {
+        corollary = theShape;
+    }
+
+    public static ShapeDTO asDTO(Transition.Shape targetShape) {
+        ShapeDTO[] values = values();
+        for (int i = 0; i < values.length; i++) {
+            ShapeDTO value = values[i];
+            if (value.corollary.equals(targetShape)) {
+                return value;
+            }
+        }
+        return ELLIPSOID; //default
+    }
+
+    public Transition.Shape getORShape() {
+        return corollary;
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/StreamerDTO.java b/core/src/net/sf/openrocket/preset/xml/StreamerDTO.java
new file mode 100644 (file)
index 0000000..7ed0dd8
--- /dev/null
@@ -0,0 +1,102 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * Streamer preset XML handler.
+ */
+@XmlRootElement(name = "Streamer")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class StreamerDTO extends BaseComponentDTO {
+
+    @XmlElement(name = "Length")
+    private AnnotatedLengthDTO length;
+    @XmlElement(name = "Width")
+    private AnnotatedLengthDTO width;
+    @XmlElement(name = "Thickness")
+    private AnnotatedLengthDTO thickness;
+
+    /**
+     * Default constructor.
+     */
+    public StreamerDTO() {
+    }
+
+    /**
+     * Most-useful constructor that maps a BodyTube preset to a BodyTubeDTO.
+     *
+     * @param preset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected body tube keys are not in the preset
+     */
+    public StreamerDTO(final ComponentPreset preset) {
+        super(preset);
+        setWidth(preset.get(ComponentPreset.WIDTH));
+        setThickness(preset.get(ComponentPreset.THICKNESS));
+        setLength(preset.get(ComponentPreset.LENGTH));
+    }
+
+    public double getWidth() {
+        return width.getValue();
+    }
+
+    public void setWidth( final AnnotatedLengthDTO theWidth ) {
+       width = theWidth;
+    }
+    
+    public void setWidth(final double theId) {
+        width = new AnnotatedLengthDTO(theId);
+    }
+
+    public double getThickness() {
+        return thickness.getValue();
+    }
+
+    public void setThickness(final AnnotatedLengthDTO theThickness) {
+       thickness = theThickness;
+    }
+
+    public void setThickness(final double theThickness) {
+       thickness = new AnnotatedLengthDTO(theThickness);
+    }
+
+    public double getLength() {
+        return length.getValue();
+    }
+
+    public void setLength(final AnnotatedLengthDTO theLength) {
+        length = theLength;
+    }
+
+    public void setLength(final double theLength) {
+        length = new AnnotatedLengthDTO(theLength);
+    }
+
+    @Override
+    public ComponentPreset asComponentPreset(java.util.List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        return asComponentPreset(ComponentPreset.Type.STREAMER, materials);
+    }
+
+    public ComponentPreset asComponentPreset(ComponentPreset.Type type, List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        TypedPropertyMap props = new TypedPropertyMap();
+        addProps(props, materials);
+        // TODO - seems some vendors use a bulk material for the sheet along with a Thickness.
+        // need to fix the MATERIAL packed into the componentpreset.
+        props.put(ComponentPreset.WIDTH, this.getWidth());
+        props.put(ComponentPreset.THICKNESS, this.getThickness());
+        props.put(ComponentPreset.LENGTH, this.getLength());
+        props.put(ComponentPreset.TYPE, type);
+
+        return ComponentPresetFactory.create(props);
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/TransitionDTO.java b/core/src/net/sf/openrocket/preset/xml/TransitionDTO.java
new file mode 100644 (file)
index 0000000..1aaaac6
--- /dev/null
@@ -0,0 +1,197 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+import net.sf.openrocket.preset.TypedPropertyMap;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * Transition preset XML handler.
+ */
+@XmlRootElement(name = "Transition")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class TransitionDTO extends BaseComponentDTO {
+
+    @XmlElement(name = "Shape")
+    private ShapeDTO shape;
+
+    @XmlElement(name = "ForeOutsideDiameter")
+    private AnnotatedLengthDTO foreOutsideDiameter;
+    @XmlElement(name = "ForeShoulderDiameter")
+    private AnnotatedLengthDTO foreShoulderDiameter;
+    @XmlElement(name = "ForeShoulderLength")
+    private AnnotatedLengthDTO foreShoulderLength;
+
+    @XmlElement(name = "AftOutsideDiameter")
+    private AnnotatedLengthDTO aftOutsideDiameter;
+    @XmlElement(name = "AftShoulderDiameter")
+    private AnnotatedLengthDTO aftShoulderDiameter;
+    @XmlElement(name = "AftShoulderLength")
+    private AnnotatedLengthDTO aftShoulderLength;
+
+    @XmlElement(name = "Length")
+    private AnnotatedLengthDTO length;
+    
+    @XmlElement(name = "Thickness")
+    private AnnotatedLengthDTO thickness;
+
+
+    /**
+     * Default constructor.
+     */
+    public TransitionDTO() {
+    }
+
+    /**
+     * Most-useful constructor that maps a Transition preset to a TransitionDTO.
+     *
+     * @param thePreset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected transition keys are not in the preset
+     */
+    public TransitionDTO(final ComponentPreset thePreset) {
+        super(thePreset);
+        setShape(ShapeDTO.asDTO(thePreset.get(ComponentPreset.SHAPE)));
+        setForeOutsideDiameter(thePreset.get(ComponentPreset.FORE_OUTER_DIAMETER));
+        setForeShoulderDiameter(thePreset.get(ComponentPreset.FORE_SHOULDER_DIAMETER));
+        setForeShoulderLength(thePreset.get(ComponentPreset.FORE_SHOULDER_LENGTH));
+        setAftOutsideDiameter(thePreset.get(ComponentPreset.AFT_OUTER_DIAMETER));
+        setAftShoulderDiameter(thePreset.get(ComponentPreset.AFT_SHOULDER_DIAMETER));
+        setAftShoulderLength(thePreset.get(ComponentPreset.AFT_SHOULDER_LENGTH));
+        setLength(thePreset.get(ComponentPreset.LENGTH));
+        if ( thePreset.has(ComponentPreset.THICKNESS)) {
+               setThickness(thePreset.get(ComponentPreset.THICKNESS));
+        }
+    }
+
+    public ShapeDTO getShape() {
+        return shape;
+    }
+
+    public void setShape(final ShapeDTO theShape) {
+        shape = theShape;
+    }
+
+    public double getForeOutsideDiameter() {
+        return foreOutsideDiameter.getValue();
+    }
+
+    public void setForeOutsideDiameter(final AnnotatedLengthDTO theForeOutsideDiameter) {
+        foreOutsideDiameter = theForeOutsideDiameter;
+    }
+
+    public void setForeOutsideDiameter(final double theForeOutsideDiameter) {
+        foreOutsideDiameter = new AnnotatedLengthDTO(theForeOutsideDiameter);
+    }
+
+    public double getForeShoulderDiameter() {
+        return foreShoulderDiameter.getValue();
+    }
+
+    public void setForeShoulderDiameter(final AnnotatedLengthDTO theForeShoulderDiameter) {
+        foreShoulderDiameter = theForeShoulderDiameter;
+    }
+
+    public void setForeShoulderDiameter(final double theForeShoulderDiameter) {
+        foreShoulderDiameter = new AnnotatedLengthDTO(theForeShoulderDiameter);
+    }
+
+    public double getForeShoulderLength() {
+        return foreShoulderLength.getValue();
+    }
+
+    public void setForeShoulderLength(final AnnotatedLengthDTO theForeShoulderLength) {
+        foreShoulderLength = theForeShoulderLength;
+    }
+
+    public void setForeShoulderLength(final double theForeShoulderLength) {
+        foreShoulderLength = new AnnotatedLengthDTO(theForeShoulderLength);
+    }
+
+    public double getAftOutsideDiameter() {
+        return aftOutsideDiameter.getValue();
+    }
+
+    public void setAftOutsideDiameter(final AnnotatedLengthDTO theAftOutsideDiameter) {
+        aftOutsideDiameter = theAftOutsideDiameter;
+    }
+
+    public void setAftOutsideDiameter(final double theAftOutsideDiameter) {
+        aftOutsideDiameter = new AnnotatedLengthDTO(theAftOutsideDiameter);
+    }
+
+    public double getAftShoulderDiameter() {
+        return aftShoulderDiameter.getValue();
+    }
+
+    public void setAftShoulderDiameter(final AnnotatedLengthDTO theAftShoulderDiameter) {
+        aftShoulderDiameter = theAftShoulderDiameter;
+    }
+
+    public void setAftShoulderDiameter(final double theAftShoulderDiameter) {
+        aftShoulderDiameter = new AnnotatedLengthDTO(theAftShoulderDiameter);
+    }
+
+    public double getAftShoulderLength() {
+        return aftShoulderLength.getValue();
+    }
+
+    public void setAftShoulderLength(final AnnotatedLengthDTO theAftShoulderLength) {
+        aftShoulderLength = theAftShoulderLength;
+    }
+
+    public void setAftShoulderLength(final double theAftShoulderLength) {
+        aftShoulderLength = new AnnotatedLengthDTO(theAftShoulderLength);
+    }
+
+    public double getLength() {
+        return length.getValue();
+    }
+
+    public void setLength(final AnnotatedLengthDTO theLength) {
+        length = theLength;
+    }
+
+    public void setLength(final double theLength) {
+        length = new AnnotatedLengthDTO(theLength);
+    }
+
+    public double getThickness() {
+               return thickness.getValue();
+       }
+
+       public void setThickness(AnnotatedLengthDTO thickness) {
+               this.thickness = thickness;
+       }
+
+       public void setThickness(double thickness) {
+               this.thickness = new AnnotatedLengthDTO(thickness);
+       }
+
+       @Override
+       public ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        TypedPropertyMap props = new TypedPropertyMap();
+        addProps(props, materials);
+        props.put(ComponentPreset.SHAPE, shape.getORShape());
+        props.put(ComponentPreset.FORE_OUTER_DIAMETER, this.getForeOutsideDiameter());
+        props.put(ComponentPreset.FORE_SHOULDER_DIAMETER, this.getForeShoulderDiameter());
+        props.put(ComponentPreset.FORE_SHOULDER_LENGTH, this.getForeShoulderLength());
+        props.put(ComponentPreset.AFT_OUTER_DIAMETER, this.getAftOutsideDiameter());
+        props.put(ComponentPreset.AFT_SHOULDER_DIAMETER, this.getAftShoulderDiameter());
+        props.put(ComponentPreset.AFT_SHOULDER_LENGTH, this.getAftShoulderLength());
+        props.put(ComponentPreset.LENGTH, this.getLength());
+        props.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+        if ( thickness != null ) {
+               props.put(ComponentPreset.THICKNESS, this.getThickness());
+        }
+
+        return ComponentPresetFactory.create(props);
+    }
+}
diff --git a/core/src/net/sf/openrocket/preset/xml/TubeCouplerDTO.java b/core/src/net/sf/openrocket/preset/xml/TubeCouplerDTO.java
new file mode 100644 (file)
index 0000000..3cc0965
--- /dev/null
@@ -0,0 +1,40 @@
+
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.InvalidComponentPresetException;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+/**
+ * Tube coupler preset XML handler.
+ */
+@XmlRootElement(name = "TubeCoupler")
+@XmlAccessorType(XmlAccessType.FIELD)
+public class TubeCouplerDTO extends BodyTubeDTO {
+
+    /**
+     * Default constructor.
+     */
+    public TubeCouplerDTO() {
+    }
+
+    /**
+     * Most-useful constructor that maps a TubeCoupler preset to a TubeCouplerDTO.
+     *
+     * @param thePreset  the preset
+     *
+     * @throws net.sf.openrocket.util.BugException thrown if the expected tube coupler keys are not in the preset
+     */
+    public TubeCouplerDTO(ComponentPreset thePreset) {
+        super(thePreset);
+    }
+
+    @Override
+    public ComponentPreset asComponentPreset(List<MaterialDTO> materials) throws InvalidComponentPresetException {
+        return super.asComponentPreset(ComponentPreset.Type.TUBE_COUPLER, materials);
+    }
+}
index a102e87f720871ae46f1341a3f3f05280bb6c858..6f4d7dbe4a9df41d89ee933e8f9c1fd65e9942f0 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.rocketcomponent;
 
+import net.sf.openrocket.preset.ComponentPreset;
+
 
 
 /**
@@ -49,10 +51,7 @@ public abstract class BodyComponent extends ExternalComponent {
        
        
        @Override
-       protected void loadFromPreset(RocketComponent preset) {
-               BodyComponent c = (BodyComponent) preset;
-               this.setLength(c.getLength());
-               
+       protected void loadFromPreset(ComponentPreset preset) {
                super.loadFromPreset(preset);
        }
        
index 64c1b4a99c7608f602e676ce38909dad0cd22919..65317a3c2f6c79a19b24a3caab32dc18f5cdfde7 100644 (file)
@@ -6,6 +6,7 @@ import java.util.HashMap;
 
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
@@ -62,6 +63,11 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
        
        /************  Get/set component parameter methods ************/
        
+       @Override
+       public ComponentPreset.Type getPresetType() {
+               return ComponentPreset.Type.BODY_TUBE;
+       }
+
        /**
         * Return the outer radius of the body tube.
         *
@@ -134,14 +140,22 @@ public class BodyTube extends SymmetricComponent implements MotorMount, Coaxial
        
        
        @Override
-       protected void loadFromPreset(RocketComponent preset) {
-               BodyTube c = (BodyTube) preset;
-               this.setOuterRadius(c.getOuterRadius());
-               
+       protected void loadFromPreset(ComponentPreset preset) {
+               this.autoRadius = false;
+               if ( preset.has(ComponentPreset.OUTER_DIAMETER) )  {
+                       double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
+                       this.outerRadius = outerDiameter/2.0;
+                       if ( preset.has(ComponentPreset.INNER_DIAMETER) ) {
+                               double innerDiameter = preset.get(ComponentPreset.INNER_DIAMETER);
+                               this.thickness = (outerDiameter-innerDiameter) / 2.0;
+                       }
+               }
+
                super.loadFromPreset(preset);
+
+               fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
        
-       
        @Override
        public double getAftRadius() {
                return getOuterRadius();
index 24a1552ffd24460a36b2f54441d7a0828a9fded7..36822c4d0b6a6fe78de7b817761710f7160888a6 100644 (file)
@@ -1,6 +1,8 @@
 package net.sf.openrocket.rocketcomponent;
 
 import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
 import net.sf.openrocket.startup.Application;
 
 
@@ -12,6 +14,11 @@ public class Bulkhead extends RadiusRingComponent {
                setLength(0.002);
        }
        
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.BULK_HEAD;
+       }
+
        @Override
        public double getInnerRadius() {
                return 0;
@@ -25,6 +32,7 @@ public class Bulkhead extends RadiusRingComponent {
        @Override
        public void setOuterRadiusAutomatic(boolean auto) {
                super.setOuterRadiusAutomatic(auto);
+               clearPreset();
        }
        
        @Override
index 21b73e2af1daa65d70611b0f1400e7bf938153d5..0dc9e1ee34f8f1985d4f7bf3a7d66819608fc80f 100644 (file)
@@ -1,5 +1,9 @@
 package net.sf.openrocket.rocketcomponent;
 
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Coordinate;
 
 
@@ -10,6 +14,8 @@ public class CenteringRing extends RadiusRingComponent {
                setInnerRadiusAutomatic(true);
                setLength(0.002);
        }
+       
+       private static final Translator trans = Application.getTranslator();
 
 
        @Override
@@ -54,7 +60,7 @@ public class CenteringRing extends RadiusRingComponent {
 
        @Override
        public String getComponentName() {
-               return "Centering ring";
+               return trans.get ("CenteringRing.CenteringRing");
        }
 
        @Override
@@ -67,4 +73,9 @@ public class CenteringRing extends RadiusRingComponent {
                return false;
        }
 
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.CENTERING_RING;
+       }
+
 }
index 2c2c590b94c47843b251875060104a89c43e3932..660bbba15fd69bcbb01e249f69b132c365487322 100644 (file)
@@ -1,8 +1,15 @@
 package net.sf.openrocket.rocketcomponent;
 
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.startup.Application;
+
 
 public class EngineBlock extends ThicknessRingComponent {
        
+       private static final Translator trans = Application.getTranslator();
+
        public EngineBlock() {
                super();
                setOuterRadiusAutomatic(true);
@@ -17,7 +24,7 @@ public class EngineBlock extends ThicknessRingComponent {
        
        @Override
        public String getComponentName() {
-               return "Engine block";
+               return trans.get ("EngineBlock.EngineBlock");
        }
        
        @Override
@@ -30,4 +37,9 @@ public class EngineBlock extends ThicknessRingComponent {
                return false;
        }
        
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.ENGINE_BLOCK;
+       }
+
 }
index 8d958da6d0a96167f8bb711231cabbb3d07ab6cc..4377a8c31837718d3362be71390b4f001175433c 100644 (file)
@@ -4,7 +4,7 @@ import java.util.List;
 
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
-import net.sf.openrocket.material.Material.Type;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
 
@@ -17,7 +17,7 @@ import net.sf.openrocket.unit.UnitGroup;
  */
 
 public abstract class ExternalComponent extends RocketComponent {
-       
+
        public enum Finish {
                //// Rough
                ROUGH("ExternalComponent.Rough", 500e-6),
@@ -29,35 +29,35 @@ public abstract class ExternalComponent extends RocketComponent {
                SMOOTH("ExternalComponent.Smoothpaint", 20e-6),
                //// Polished
                POLISHED("ExternalComponent.Polished", 2e-6);
-               
+
                private static final Translator trans = Application.getTranslator();
                private final String name;
                private final double roughnessSize;
-               
+
                Finish(String name, double roughness) {
                        this.name = name;
                        this.roughnessSize = roughness;
                }
-               
+
                public double getRoughnessSize() {
                        return roughnessSize;
                }
-               
+
                @Override
                public String toString() {
                        return trans.get(name) + " (" + UnitGroup.UNITS_ROUGHNESS.toStringUnit(roughnessSize) + ")";
                }
        }
-       
-       
+
+
        /**
         * The material of the component.
         */
        protected Material material = null;
-       
+
        protected Finish finish = Finish.NORMAL;
-       
-       
+
+
 
        /**
         * Constructor that sets the relative position of the component.
@@ -66,13 +66,13 @@ public abstract class ExternalComponent extends RocketComponent {
                super(relativePosition);
                this.material = Application.getPreferences().getDefaultComponentMaterial(this.getClass(), Material.Type.BULK);
        }
-       
+
        /**
         * Returns the volume of the component.  This value is used in calculating the mass
         * of the object.
         */
        public abstract double getComponentVolume();
-       
+
        /**
         * Calculates the mass of the component as the product of the volume and interior density.
         */
@@ -80,7 +80,7 @@ public abstract class ExternalComponent extends RocketComponent {
        public double getComponentMass() {
                return material.getDensity() * getComponentVolume();
        }
-       
+
        /**
         * ExternalComponent has aerodynamic effect, so return true.
         */
@@ -88,7 +88,7 @@ public abstract class ExternalComponent extends RocketComponent {
        public boolean isAerodynamic() {
                return true;
        }
-       
+
        /**
         * ExternalComponent has effect on the mass, so return true.
         */
@@ -96,63 +96,66 @@ public abstract class ExternalComponent extends RocketComponent {
        public boolean isMassive() {
                return true;
        }
-       
-       
+
+
        public Material getMaterial() {
                return material;
        }
-       
+
        public void setMaterial(Material mat) {
                if (mat.getType() != Material.Type.BULK) {
                        throw new IllegalArgumentException("ExternalComponent requires a bulk material" +
                                        " type=" + mat.getType());
                }
-               
+
                if (material.equals(mat))
                        return;
                material = mat;
                clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
-               clearPreset();
        }
-       
+
        public Finish getFinish() {
                return finish;
        }
-       
+
        public void setFinish(Finish finish) {
                if (this.finish == finish)
                        return;
                this.finish = finish;
                fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
        }
-       
-       
+
+
        @Override
-       protected void loadFromPreset(RocketComponent preset) {
+       protected void loadFromPreset(ComponentPreset preset) {
                super.loadFromPreset(preset);
-               
+
                // Surface finish is left unchanged
-               
-               ExternalComponent c = (ExternalComponent) preset;
-               
-               Material mat = c.getMaterial();
-               if (c.isMassOverridden()) {
-                       double mass = c.getOverrideMass();
-                       double volume = getComponentVolume();
-                       double density;
-                       if (volume > 0.00001) {
-                               density = mass / volume;
-                       } else {
-                               density = 1000;
+
+               if ( preset.has(ComponentPreset.MATERIAL ) ) {
+                       Material mat = preset.get(ComponentPreset.MATERIAL);
+                       if ( mat != null ) {
+                               material = mat;
+                       } /*
+                       TODO - 
+                       else if (c.isMassOverridden()) {
+                               double mass = c.getOverrideMass();
+                               double volume = getComponentVolume();
+                               double density;
+                               if (volume > 0.00001) {
+                                       density = mass / volume;
+                               } else {
+                                       density = 1000;
+                               }
+                               mat = Material.newMaterial(Type.BULK, mat.getName(), density, true);
+                               setMaterial(mat);
                        }
-                       mat = Material.newMaterial(Type.BULK, mat.getName(), density, true);
+                       */
                }
-               
-               setMaterial(mat);
        }
-       
-       
+
+
        @Override
        protected List<RocketComponent> copyFrom(RocketComponent c) {
                ExternalComponent src = (ExternalComponent) c;
@@ -160,5 +163,5 @@ public abstract class ExternalComponent extends RocketComponent {
                this.material = src.material;
                return super.copyFrom(c);
        }
-       
+
 }
index 5e40810b4749fc1268648d7d9da484a049c7e3b1..4b8d58058cb98232e147b516f83ec538139481ea 100644 (file)
@@ -7,6 +7,7 @@ import java.util.List;
 
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.ArrayUtils;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.Transformation;
@@ -675,7 +676,7 @@ public abstract class FinSet extends ExternalComponent {
                double y = -getTabHeight();
                
                int n = points.length;
-               points = Arrays.copyOf(points, points.length + 4);
+               points = ArrayUtils.copyOf(points, points.length + 4);
                points[n] = new Coordinate(x2, 0);
                points[n + 1] = new Coordinate(x2, y);
                points[n + 2] = new Coordinate(x1, y);
index b0bb0ad716e639cefd2fa048605e311a55d32361..ac52a0f880dd3dcb83089643264285a9422de60e 100644 (file)
@@ -258,7 +258,7 @@ public class FreeformFinSet extends FinSet {
                
                if (index == 0) {
                        
-                       System.out.println("Set point zero to x:" + x);
+                       //System.out.println("Set point zero to x:" + x);
                        for (int i = 1; i < points.size(); i++) {
                                Coordinate c = points.get(i);
                                points.set(i, c.setX(c.x - x));
index 0b8c92d242fbca6150d342fdbdc29400408263cb..937edbf5e1c0a51b46b0d8594eda3621324326ca 100644 (file)
@@ -6,6 +6,7 @@ import java.util.List;
 
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.Coordinate;
@@ -77,7 +78,27 @@ public class InnerTube extends ThicknessRingComponent
                return InternalComponent.class.isAssignableFrom(type);
        }
        
-       
+       @Override
+       public ComponentPreset.Type getPresetType() {
+               return ComponentPreset.Type.BODY_TUBE;
+       }
+
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               if ( preset.has(ComponentPreset.OUTER_DIAMETER) )  {
+                       double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
+                       this.outerRadius = outerDiameter/2.0;
+                       if ( preset.has(ComponentPreset.INNER_DIAMETER) ) {
+                               double innerDiameter = preset.get(ComponentPreset.INNER_DIAMETER);
+                               this.thickness = (outerDiameter-innerDiameter) / 2.0;
+                       }
+               }
+
+               super.loadFromPreset(preset);
+
+               fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+       }
+
 
        /////////////  Cluster methods  //////////////
        
index 5614e07710c1cd0edfa1ed07818ce9e9684b181d..437094368d7483486b2936c596846b938d4d5d19 100644 (file)
@@ -4,6 +4,8 @@ import java.util.ArrayList;
 import java.util.Collection;
 
 import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
@@ -43,6 +45,7 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                        return;
                this.radius = radius;
                this.thickness = Math.min(this.thickness, this.radius);
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
        
@@ -65,6 +68,7 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
                if (MathUtil.equals(this.thickness, thickness))
                        return;
                this.thickness = MathUtil.clamp(thickness, 0, radius);
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
        
@@ -109,6 +113,29 @@ public class LaunchLug extends ExternalComponent implements Coaxial {
        
        
 
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               if ( preset.has(ComponentPreset.OUTER_DIAMETER) )  {
+                       double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
+                       this.radius = outerDiameter/2.0;
+                       if ( preset.has(ComponentPreset.INNER_DIAMETER) ) {
+                               double innerDiameter = preset.get(ComponentPreset.INNER_DIAMETER);
+                               this.thickness = (outerDiameter-innerDiameter) / 2.0;
+                       }
+               }
+
+               super.loadFromPreset(preset);
+
+               fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+       }
+
+
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.LAUNCH_LUG;
+       }
+
+
        @Override
        public Coordinate[] shiftCoordinates(Coordinate[] array) {
                array = super.shiftCoordinates(array);
index 49c139b0bbf1a06416e0c1bf36463f2b4cac45e1..81e5a63d820cb07ec637541cec69d0eafc0f0150 100644 (file)
@@ -40,6 +40,27 @@ public class MassComponent extends MassObject {
        }
        
        
+       public double getDensity() {
+               double d = getComponentMass() / getVolume();
+               if (Double.isNaN(d))
+                       d = 0;
+               return d;
+       }
+       
+       public void setDensity(double density) {
+               double m = density * getVolume();
+               m = MathUtil.clamp(m, 0, 1000000);
+               if (Double.isNaN(m))
+                       m = 0;
+               setComponentMass(m);
+       }
+       
+       
+       private double getVolume() {
+               return Math.PI * MathUtil.pow2(getRadius()) * getLength();
+       }
+       
+       
        @Override
        public String getComponentName() {
                //// Mass component
index a4de3a9c8aeabcded7bc652c14c99b24539d0120..6ef65ed24b363f63a93787207dff33ed8f82df1e 100644 (file)
@@ -1,6 +1,8 @@
 package net.sf.openrocket.rocketcomponent;
 
 import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
 import net.sf.openrocket.startup.Application;
 
 /**
@@ -111,6 +113,18 @@ public class NoseCone extends Transition {
 
        /********** RocketComponent methods **********/
        
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.NOSE_CONE;
+       }
+
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               
+               //Many parameters are handled by the super class Transition.loadFromPreset
+               super.loadFromPreset(preset);
+       }
+
        /**
         * Return component name.
         */
index 640810bb2e50e9d27e79e4b01a8023b3457cc1e0..aabb6117fda8f48d7d495876fd8e7b929e265fa5 100644 (file)
@@ -2,6 +2,8 @@ package net.sf.openrocket.rocketcomponent;
 
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.MathUtil;
 
@@ -32,6 +34,7 @@ public class Parachute extends RecoveryDevice {
                if (MathUtil.equals(this.diameter, d))
                        return;
                this.diameter = d;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
        
@@ -62,6 +65,7 @@ public class Parachute extends RecoveryDevice {
                if (this.lineCount == n)
                        return;
                this.lineCount = n;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
        
@@ -94,6 +98,7 @@ public class Parachute extends RecoveryDevice {
                if (MathUtil.equals(getArea(), area))
                        return;
                diameter = MathUtil.safeSqrt(area / Math.PI) * 2;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
        
@@ -118,5 +123,29 @@ public class Parachute extends RecoveryDevice {
        public boolean isCompatible(Class<? extends RocketComponent> type) {
                return false;
        }
+
+
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               if( preset.has( ComponentPreset.DIAMETER )) {
+                       this.diameter = preset.get( ComponentPreset.DIAMETER );
+               }
+               if( preset.has( ComponentPreset.LINE_COUNT )) {
+                       this.lineCount = preset.get( ComponentPreset.LINE_COUNT );
+               }
+               if( preset.has( ComponentPreset.LINE_LENGTH )) {
+                       this.lineLength = preset.get( ComponentPreset.LINE_LENGTH );
+               }
+               if( preset.has( ComponentPreset.LINE_MATERIAL )) {
+                       this.lineMaterial = preset.get( ComponentPreset.LINE_MATERIAL );
+               }
+               super.loadFromPreset(preset);
+       }
+
+
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.PARACHUTE;
+       }
        
 }
index 46a35143900afddd218c2cda1d29facf7139f4c7..6d0ccb657e96e1ec754e21b70049485f0013abb8 100644 (file)
@@ -1,5 +1,6 @@
 package net.sf.openrocket.rocketcomponent;
 
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
 
@@ -16,6 +17,22 @@ public abstract class RadiusRingComponent extends RingComponent implements Coaxi
        protected double outerRadius = 0;
        protected double innerRadius = 0;
 
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               super.loadFromPreset(preset);
+               if ( preset.has(ComponentPreset.OUTER_DIAMETER)) {
+                       this.outerRadius = preset.get(ComponentPreset.OUTER_DIAMETER) / 2.0;
+                       this.outerRadiusAutomatic = false;
+               }
+               this.innerRadiusAutomatic = false;
+               if ( preset.has(ComponentPreset.INNER_DIAMETER)) {
+                       this.innerRadius = preset.get(ComponentPreset.INNER_DIAMETER) / 2.0;
+               }
+
+               fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
+
+       }
+
        @Override
        public double getOuterRadius() {
                if (outerRadiusAutomatic && getParent() instanceof RadialParent) {
@@ -44,6 +61,7 @@ public abstract class RadiusRingComponent extends RingComponent implements Coaxi
                        innerRadiusAutomatic = false;
                }
 
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
 
@@ -65,6 +83,7 @@ public abstract class RadiusRingComponent extends RingComponent implements Coaxi
                        outerRadiusAutomatic = false;
                }
 
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
 
index 4156bfbe3167157ac6be8eab1d2a738f445ae1e9..3c5a88f1bc005e2deb39b0b5b85adb40a7d95890 100644 (file)
@@ -2,6 +2,7 @@ package net.sf.openrocket.rocketcomponent;
 
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.MathUtil;
@@ -22,16 +23,14 @@ import net.sf.openrocket.util.Pair;
  */
 public abstract class RecoveryDevice extends MassObject {
        private static final Translator trans = Application.getTranslator();
-
+       
        public static enum DeployEvent {
-               //// Launch (plus NN seconds)
                LAUNCH(trans.get("RecoveryDevice.DeployEvent.LAUNCH")) {
                        @Override
                        public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
                                return e.getType() == FlightEvent.Type.LAUNCH;
                        }
                },
-               //// First ejection charge of this stage
                EJECTION(trans.get("RecoveryDevice.DeployEvent.EJECTION")) {
                        @Override
                        public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
@@ -41,35 +40,42 @@ public abstract class RecoveryDevice extends MassObject {
                                return charge.getStageNumber() == source.getStageNumber();
                        }
                },
-               //// Apogee
                APOGEE(trans.get("RecoveryDevice.DeployEvent.APOGEE")) {
                        @Override
                        public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
                                return e.getType() == FlightEvent.Type.APOGEE;
                        }
                },
-               //// Specific altitude during descent
                ALTITUDE(trans.get("RecoveryDevice.DeployEvent.ALTITUDE")) {
                        @SuppressWarnings("unchecked")
                        @Override
                        public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
                                if (e.getType() != FlightEvent.Type.ALTITUDE)
                                        return false;
-
-                               double alt = ((RecoveryDevice)source).getDeployAltitude();
-                               Pair<Double,Double> altitude = (Pair<Double,Double>)e.getData();
+                               
+                               double alt = ((RecoveryDevice) source).getDeployAltitude();
+                               Pair<Double, Double> altitude = (Pair<Double, Double>) e.getData();
                                
                                return (altitude.getU() >= alt) && (altitude.getV() <= alt);
                        }
                },
-               //// Never
+               LOWER_STAGE_SEPARATION(trans.get("RecoveryDevice.DeployEvent.LOWER_STAGE_SEPARATION")) {
+                       @Override
+                       public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
+                               if (e.getType() != FlightEvent.Type.STAGE_SEPARATION)
+                                       return false;
+                               
+                               int separation = e.getSource().getStageNumber();
+                               int current = source.getStageNumber();
+                               return (current + 1 == separation);
+                       }
+               },
                NEVER(trans.get("RecoveryDevice.DeployEvent.NEVER")) {
                        @Override
                        public boolean isActivationEvent(FlightEvent e, RocketComponent source) {
                                return false;
                        }
-               }
-               ;
+               };
                
                private final String description;
                
@@ -83,7 +89,7 @@ public abstract class RecoveryDevice extends MassObject {
                public String toString() {
                        return description;
                }
-
+               
        }
        
        
@@ -96,7 +102,7 @@ public abstract class RecoveryDevice extends MassObject {
        
        
        private Material.Surface material;
-
+       
        
        public RecoveryDevice() {
                this(Application.getPreferences().getDefaultComponentMaterial(RecoveryDevice.class, Material.Type.SURFACE));
@@ -106,19 +112,19 @@ public abstract class RecoveryDevice extends MassObject {
                super();
                setMaterial(material);
        }
-
+       
        public RecoveryDevice(double length, double radius, Material material) {
                super(length, radius);
                setMaterial(material);
        }
        
        
-
+       
        
        public abstract double getArea();
        
        public abstract double getComponentCD(double mach);
-
+       
        
        
        public double getCD() {
@@ -130,7 +136,7 @@ public abstract class RecoveryDevice extends MassObject {
                        cd = getComponentCD(mach);
                return cd;
        }
-
+       
        public void setCD(double cd) {
                if (MathUtil.equals(this.cd, cd) && !isCDAutomatic())
                        return;
@@ -138,7 +144,7 @@ public abstract class RecoveryDevice extends MassObject {
                this.cdAutomatic = false;
                fireComponentChangeEvent(ComponentChangeEvent.AERODYNAMIC_CHANGE);
        }
-
+       
        
        public boolean isCDAutomatic() {
                return cdAutomatic;
@@ -159,11 +165,12 @@ public abstract class RecoveryDevice extends MassObject {
        
        public final void setMaterial(Material mat) {
                if (!(mat instanceof Material.Surface)) {
-                       throw new IllegalArgumentException("Attempted to set non-surface material "+mat);
+                       throw new IllegalArgumentException("Attempted to set non-surface material " + mat);
                }
                if (mat.equals(material))
                        return;
-               this.material = (Material.Surface)mat;
+               this.material = (Material.Surface) mat;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
        
@@ -173,7 +180,7 @@ public abstract class RecoveryDevice extends MassObject {
        public DeployEvent getDeployEvent() {
                return deployEvent;
        }
-
+       
        public void setDeployEvent(DeployEvent deployEvent) {
                if (this.deployEvent == deployEvent)
                        return;
@@ -181,11 +188,11 @@ public abstract class RecoveryDevice extends MassObject {
                fireComponentChangeEvent(ComponentChangeEvent.EVENT_CHANGE);
        }
        
-
+       
        public double getDeployAltitude() {
                return deployAltitude;
        }
-
+       
        public void setDeployAltitude(double deployAltitude) {
                if (MathUtil.equals(this.deployAltitude, deployAltitude))
                        return;
@@ -210,10 +217,21 @@ public abstract class RecoveryDevice extends MassObject {
        }
        
        
-
+       
        @Override
        public double getComponentMass() {
                return getArea() * getMaterial().getDensity();
        }
 
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               if ( preset.has(ComponentPreset.MATERIAL)) {
+                       Material m = preset.get(ComponentPreset.MATERIAL);
+                       this.material = (Material.Surface)m;
+               }
+               super.loadFromPreset(preset);
+               fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+
+       }
+
 }
index 226f9527c68ce585d722bcf380c0a5505fdefd22..d493ca493b98a563c25b7b5875f2a0a97b245260 100644 (file)
@@ -42,7 +42,7 @@ public class Rocket extends RocketComponent {
         * List of component change listeners.
         */
        private List<EventListener> listenerList = new ArrayList<EventListener>();
-       
+               
        /**
         * When freezeList != null, events are not dispatched but stored in the list.
         * When the structure is thawed, a single combined event will be fired.
@@ -121,9 +121,6 @@ public class Rocket extends RocketComponent {
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
        
-       
-
-
        /**
         * Return the number of stages in this rocket.
         *
index b1a57dbfc8e7445a75a8b30bd926f126b3bbc519..9000a5400fa2ef77672604f95c4409b2b9f6749b 100644 (file)
@@ -1,8 +1,6 @@
 package net.sf.openrocket.rocketcomponent;
 
-import java.util.ArrayDeque;
 import java.util.Collection;
-import java.util.Deque;
 import java.util.EventListener;
 import java.util.Iterator;
 import java.util.List;
@@ -21,13 +19,14 @@ import net.sf.openrocket.util.Invalidator;
 import net.sf.openrocket.util.LineStyle;
 import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.SafetyMutex;
+import net.sf.openrocket.util.SimpleStack;
 import net.sf.openrocket.util.UniqueID;
 
 
 public abstract class RocketComponent implements ChangeSource, Cloneable, Iterable<RocketComponent> {
        private static final LogHelper log = Application.getLogger();
        private static final Translator trans = Application.getTranslator();
-       
+
        /*
         * Text is suitable to the form
         *    Position relative to:  <title>
@@ -48,38 +47,38 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                /** Specify an absolute X-coordinate position. */
                //// Tip of the nose cone
                ABSOLUTE(trans.get("RocketComponent.Position.ABSOLUTE"));
-               
+
                private String title;
-               
+
                Position(String title) {
                        this.title = title;
                }
-               
+
                @Override
                public String toString() {
                        return title;
                }
        }
-       
+
        /**
         * A safety mutex that can be used to prevent concurrent access to this component.
         */
        protected SafetyMutex mutex = SafetyMutex.newInstance();
-       
+
        ////////  Parent/child trees
        /**
         * Parent component of the current component, or null if none exists.
         */
        private RocketComponent parent = null;
-       
+
        /**
         * List of child components of this component.
         */
        private ArrayList<RocketComponent> children = new ArrayList<RocketComponent>();
-       
-       
+
+
        ////////  Parameters common to all components:
-       
+
        /**
         * Characteristic length of the component.  This is used in calculating the coordinate
         * transformations and positions of other components in reference to this component.
@@ -87,56 +86,56 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * By default it is zero, i.e. no translation.
         */
        protected double length = 0;
-       
+
        /**
         * Positioning of this component relative to the parent component.
         */
        protected Position relativePosition;
-       
+
        /**
         * Offset of the position of this component relative to the normal position given by
         * relativePosition.  By default zero, i.e. no position change.
         */
        protected double position = 0;
-       
-       
+
+
        // Color of the component, null means to use the default color
        private Color color = null;
        private LineStyle lineStyle = null;
-       
-       
+
+
        // Override mass/CG
        private double overrideMass = 0;
        private boolean massOverriden = false;
        private double overrideCGX = 0;
        private boolean cgOverriden = false;
-       
+
        private boolean overrideSubcomponents = false;
-       
-       
+
+
        // User-given name of the component
        private String name = null;
-       
+
        // User-specified comment
        private String comment = "";
-       
+
        // Unique ID of the component
        private String id = null;
-       
+
        // Preset component this component is based upon
        private ComponentPreset presetComponent = null;
-       
-       
+
+
        /**
         * Used to invalidate the component after calling {@link #copyFrom(RocketComponent)}.
         */
        private Invalidator invalidator = new Invalidator(this);
-       
-       
+
+
        ////  NOTE !!!  All fields must be copied in the method copyFrom()!  ////
-       
-       
-       
+
+
+
        /**
         * Default constructor.  Sets the name of the component to the component's static name
         * and the relative position of the component.
@@ -147,26 +146,26 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.relativePosition = relativePosition;
                newID();
        }
-       
+
        ////////////  Methods that must be implemented  ////////////
-       
-       
+
+
        /**
         * Static component name.  The name may not vary of the parameters, it must be static.
         */
        public abstract String getComponentName(); // Static component type name
-       
+
        /**
         * Return the component mass (regardless of mass overriding).
         */
        public abstract double getComponentMass(); // Mass of non-overridden component
-       
+
        /**
         * Return the component CG and mass (regardless of CG or mass overriding).
         */
        public abstract Coordinate getComponentCG(); // CG of non-overridden component
-       
-       
+
+
        /**
         * Return the longitudinal (around the y- or z-axis) unitary moment of inertia.
         * The unitary moment of inertia is the moment of inertia with the assumption that
@@ -176,8 +175,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return   the longitudinal unitary moment of inertia of this component.
         */
        public abstract double getLongitudinalUnitInertia();
-       
-       
+
+
        /**
         * Return the rotational (around the x-axis) unitary moment of inertia.
         * The unitary moment of inertia is the moment of inertia with the assumption that
@@ -187,8 +186,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return   the rotational unitary moment of inertia of this component.
         */
        public abstract double getRotationalUnitInertia();
-       
-       
+
+
        /**
         * Test whether this component allows any children components.  This method must
         * return true if and only if {@link #isCompatible(Class)} returns true for any
@@ -197,7 +196,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return      <code>true</code> if children can be attached to this component, <code>false</code> otherwise.
         */
        public abstract boolean allowsChildren();
-       
+
        /**
         * Test whether the given component type can be added to this component.  This type safety
         * is enforced by the <code>addChild()</code> methods.  The return value of this method
@@ -208,8 +207,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return      Whether such a component can be added.
         */
        public abstract boolean isCompatible(Class<? extends RocketComponent> type);
-       
-       
+
+
        /* Non-abstract helper method */
        /**
         * Test whether the given component can be added to this component.  This is equivalent
@@ -223,9 +222,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return isCompatible(c.getClass());
        }
-       
-       
-       
+
+
+
        /**
         * Return a collection of bounding coordinates.  The coordinates must be such that
         * the component is fully enclosed in their convex hull.
@@ -233,24 +232,24 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * @return      a collection of coordinates that bound the component.
         */
        public abstract Collection<Coordinate> getComponentBounds();
-       
+
        /**
         * Return true if the component may have an aerodynamic effect on the rocket.
         */
        public abstract boolean isAerodynamic();
-       
+
        /**
         * Return true if the component may have an effect on the rocket's mass.
         */
        public abstract boolean isMassive();
-       
-       
-       
-       
-       
+
+
+
+
+
        ////////////  Methods that may be overridden  ////////////
-       
-       
+
+
        /**
         * Shift the coordinates in the array corresponding to radial movement.  A component
         * that has a radial position must shift the coordinates in this array suitably.
@@ -267,8 +266,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return c;
        }
-       
-       
+
+
        /**
         * Called when any component in the tree fires a ComponentChangeEvent.  This is by
         * default a no-op, but subclasses may override this method to e.g. invalidate
@@ -281,10 +280,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                // No-op
                checkState();
        }
-       
-       
-       
-       
+
+
+
+
        /**
         * Return the user-provided name of the component, or the component base
         * name if the user-provided name is empty.  This can be used in the UI.
@@ -299,8 +298,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                else
                        return name;
        }
-       
-       
+
+
        /**
         * Create a string describing the basic component structure from this component downwards.
         * @return      a string containing the rocket structure
@@ -315,7 +314,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        mutex.unlock("toDebugString");
                }
        }
-       
+
        private void toDebugString(StringBuilder sb) {
                sb.append(this.getClass().getSimpleName()).append('@').append(System.identityHashCode(this));
                sb.append("[\"").append(this.getName()).append('"');
@@ -325,8 +324,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                sb.append(']');
        }
-       
-       
+
+
        /**
         * Make a deep copy of the rocket component tree structure from this component
         * downwards for copying purposes.  Each component in the copy will be assigned
@@ -336,16 +335,16 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         */
        public final RocketComponent copy() {
                RocketComponent clone = copyWithOriginalID();
-               
+
                Iterator<RocketComponent> iterator = clone.iterator(true);
                while (iterator.hasNext()) {
                        iterator.next().newID();
                }
                return clone;
        }
-       
-       
-       
+
+
+
        /**
         * Make a deep copy of the rocket component tree structure from this component
         * downwards while maintaining the component ID's.  The purpose of this method is
@@ -372,14 +371,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        } catch (CloneNotSupportedException e) {
                                throw new BugException("CloneNotSupportedException encountered, report a bug!", e);
                        }
-                       
+
                        // Reset the mutex
                        clone.mutex = SafetyMutex.newInstance();
-                       
+
                        // Reset all parent/child information
                        clone.parent = null;
                        clone.children = new ArrayList<RocketComponent>();
-                       
+
                        // Add copied children to the structure without firing events.
                        for (RocketComponent child : this.children) {
                                RocketComponent childCopy = child.copyWithOriginalID();
@@ -387,23 +386,23 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                clone.children.add(childCopy);
                                childCopy.parent = clone;
                        }
-                       
+
                        this.checkComponentStructure();
                        clone.checkComponentStructure();
-                       
+
                        return clone;
                } finally {
                        mutex.unlock("copyWithOriginalID");
                }
        }
-       
-       
+
+
        //////////////  Methods that may not be overridden  ////////////
-       
-       
-       
+
+
+
        ////////// Common parameter setting/getting //////////
-       
+
        /**
         * Return the color of the object to use in 2D figures, or <code>null</code>
         * to use the default color.
@@ -412,7 +411,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return color;
        }
-       
+
        /**
         * Set the color of the object to use in 2D figures.
         */
@@ -420,18 +419,18 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if ((color == null && c == null) ||
                                (color != null && color.equals(c)))
                        return;
-               
+
                checkState();
                this.color = c;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
        public final LineStyle getLineStyle() {
                mutex.verify();
                return lineStyle;
        }
-       
+
        public final void setLineStyle(LineStyle style) {
                if (this.lineStyle == style)
                        return;
@@ -439,10 +438,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.lineStyle = style;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
-       
-       
+
+
+
+
        /**
         * Get the current override mass.  The mass is not necessarily in use
         * at the moment.
@@ -453,7 +452,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return overrideMass;
        }
-       
+
        /**
         * Set the current override mass.  The mass is not set to use by this
         * method.
@@ -468,7 +467,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (massOverriden)
                        fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        /**
         * Return whether mass override is active for this component.  This does NOT
         * take into account whether a parent component is overriding the mass.
@@ -479,7 +478,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return massOverriden;
        }
-       
+
        /**
         * Set whether the mass is currently overridden.
         *
@@ -493,11 +492,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                massOverriden = o;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
-       
-       
-       
+
+
+
+
+
        /**
         * Return the current override CG.  The CG is not necessarily overridden.
         *
@@ -507,7 +506,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return getComponentCG().setX(overrideCGX);
        }
-       
+
        /**
         * Return the x-coordinate of the current override CG.
         *
@@ -517,7 +516,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return overrideCGX;
        }
-       
+
        /**
         * Set the current override CG to (x,0,0).
         *
@@ -533,7 +532,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                else
                        fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
+
        /**
         * Return whether the CG is currently overridden.
         *
@@ -543,7 +542,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return cgOverriden;
        }
-       
+
        /**
         * Set whether the CG is currently overridden.
         *
@@ -557,9 +556,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                cgOverriden = o;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
-       
+
+
+
        /**
         * Return whether the mass and/or CG override overrides all subcomponent values
         * as well.  The default implementation is a normal getter/setter implementation,
@@ -574,8 +573,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return overrideSubcomponents;
        }
-       
-       
+
+
        /**
         * Set whether the mass and/or CG override overrides all subcomponent values
         * as well.  See {@link #getOverrideSubcomponents()} for details.
@@ -590,7 +589,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                overrideSubcomponents = override;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        /**
         * Return whether the option to override all subcomponents is enabled or not.
         * The default implementation returns <code>false</code> if neither mass nor
@@ -605,10 +604,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return isCGOverridden() || isMassOverridden();
        }
-       
-       
-       
-       
+
+
+
+
        /**
         * Get the user-defined name of the component.
         */
@@ -616,7 +615,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return name;
        }
-       
+
        /**
         * Set the user-defined name of the component.  If name==null, sets the name to
         * the default name, currently the component name.
@@ -632,8 +631,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        this.name = name;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
+
+
        /**
         * Return the comment of the component.  The component may contain multiple lines
         * using \n as a newline separator.
@@ -644,7 +643,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return comment;
        }
-       
+
        /**
         * Set the comment of the component.
         *
@@ -660,9 +659,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        this.comment = comment;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
-       
+
+
+
        /**
         * Return the preset component that this component is based upon.
         * 
@@ -671,7 +670,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final ComponentPreset getPresetComponent() {
                return presetComponent;
        }
-       
+
+       /**
+        * Return the most compatible preset type for this component.
+        * This method should be overridden by components which have presets
+        * 
+        * @return the most compatible ComponentPreset.Type or <code>null</code> if no presets are compatible.
+        */
+       public ComponentPreset.Type getPresetType() {
+               return null;
+       }
+
        /**
         * Set the preset component this component is based upon and load all of the 
         * preset values.
@@ -682,17 +691,20 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (presetComponent == preset) {
                        return;
                }
-               
+
                if (preset == null) {
                        clearPreset();
                        return;
                }
-               
+
+               // TODO - do we need to this compatibility check?
+               /*
                if (preset.getComponentClass() != this.getClass()) {
                        throw new IllegalArgumentException("Attempting to load preset of type " + preset.getComponentClass()
                                        + " into component of type " + this.getClass());
                }
-               
+                */
+
                RocketComponent root = getRoot();
                final Rocket rocket;
                if (root instanceof Rocket) {
@@ -700,25 +712,25 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                } else {
                        rocket = null;
                }
-               
+
                try {
                        if (rocket != null) {
                                rocket.freeze();
                        }
-                       
-                       loadFromPreset(preset.getPrototype());
-                       
+
+                       loadFromPreset(preset);
+
                        this.presetComponent = preset;
                        fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
-                       
+
                } finally {
                        if (rocket != null) {
                                rocket.thaw();
                        }
                }
        }
-       
-       
+
+
        /**
         * Load component properties from the specified preset.  The preset is guaranteed
         * to be of the correct type.
@@ -731,11 +743,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         * 
         * @param preset        the preset to load from
         */
-       protected void loadFromPreset(RocketComponent preset) {
-               // No-op
+       protected void loadFromPreset(ComponentPreset preset) {
+               if ( preset.has(ComponentPreset.LENGTH) ) {
+                       this.length = preset.get(ComponentPreset.LENGTH);
+               }
        }
-       
-       
+
+
        /**
         * Clear the current component preset.  This does not affect the component properties
         * otherwise.
@@ -746,9 +760,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                presetComponent = null;
                fireComponentChangeEvent(ComponentChangeEvent.NONFUNCTIONAL_CHANGE);
        }
-       
-       
-       
+
+
+
        /**
         * Returns the unique ID of the component.
         *
@@ -757,7 +771,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final String getID() {
                return id;
        }
-       
+
        /**
         * Generate a new ID for this component.
         */
@@ -765,10 +779,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                this.id = UniqueID.uuid();
        }
-       
-       
-       
-       
+
+
+
+
        /**
         * Get the characteristic length of the component, for example the length of a body tube
         * of the length of the root chord of a fin.  This is used in positioning the component
@@ -781,7 +795,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return length;
        }
-       
+
        /**
         * Get the positioning of the component relative to its parent component.
         * This is one of the enums of {@link Position}.  A setter method is not provided,
@@ -791,8 +805,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return relativePosition;
        }
-       
-       
+
+
        /**
         * Set the positioning of the component relative to its parent component.
         * The actual position of the component is maintained to the best ability.
@@ -808,38 +822,38 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (this.relativePosition == position)
                        return;
                checkState();
-               
+
                // Update position so as not to move the component
                if (this.parent != null) {
                        double thisPos = this.toRelative(Coordinate.NUL, this.parent)[0].x;
-                       
+
                        switch (position) {
                        case ABSOLUTE:
                                this.position = this.toAbsolute(Coordinate.NUL)[0].x;
                                break;
-                       
+
                        case TOP:
                                this.position = thisPos;
                                break;
-                       
+
                        case MIDDLE:
                                this.position = thisPos - (this.parent.length - this.length) / 2;
                                break;
-                       
+
                        case BOTTOM:
                                this.position = thisPos - (this.parent.length - this.length);
                                break;
-                       
+
                        default:
                                throw new BugException("Unknown position type: " + position);
                        }
                }
-               
+
                this.relativePosition = position;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        /**
         * Determine position relative to given position argument.  Note: This is a side-effect free method.  No state
         * is modified.
@@ -853,7 +867,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                double result = this.position;
                if (relativeTo != null) {
                        double thisPos = this.toRelative(Coordinate.NUL, relativeTo)[0].x;
-                       
+
                        switch (thePosition) {
                        case ABSOLUTE:
                                result = this.toAbsolute(Coordinate.NUL)[0].x;
@@ -873,7 +887,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return result;
        }
-       
+
        /**
         * Get the position value of the component.  The exact meaning of the value is
         * dependent on the current relative positioning.
@@ -884,8 +898,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                mutex.verify();
                return position;
        }
-       
-       
+
+
        /**
         * Set the position value of the component.  The exact meaning of the value
         * depends on the current relative positioning.
@@ -903,11 +917,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                this.position = value;
        }
-       
-       
-       
+
+
+
        ///////////  Coordinate changes  ///////////
-       
+
        /**
         * Returns coordinate c in absolute coordinates.  Equivalent to toComponent(c,null).
         */
@@ -915,8 +929,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return toRelative(c, null);
        }
-       
-       
+
+
        /**
         * Return coordinate <code>c</code> described in the coordinate system of
         * <code>dest</code>.  If <code>dest</code> is <code>null</code> returns
@@ -941,33 +955,33 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        RocketComponent search = dest;
                        Coordinate[] array = new Coordinate[1];
                        array[0] = c;
-                       
+
                        RocketComponent component = this;
                        while ((component != search) && (component.parent != null)) {
-                               
+
                                array = component.shiftCoordinates(array);
-                               
+
                                switch (component.relativePosition) {
                                case TOP:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position, 0, 0);
                                        }
                                        break;
-                               
+
                                case MIDDLE:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position +
                                                                (component.parent.length - component.length) / 2, 0, 0);
                                        }
                                        break;
-                               
+
                                case BOTTOM:
                                        for (int i = 0; i < array.length; i++) {
                                                array[i] = array[i].add(component.position +
                                                                (component.parent.length - component.length), 0, 0);
                                        }
                                        break;
-                               
+
                                case AFTER:
                                        // Add length of all previous brother-components with POSITION_RELATIVE_AFTER
                                        int index = component.parent.children.indexOf(component);
@@ -983,28 +997,28 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                                array[i] = array[i].add(component.position + component.parent.length, 0, 0);
                                        }
                                        break;
-                               
+
                                case ABSOLUTE:
                                        search = null; // Requires back-search if dest!=null
                                        if (Double.isNaN(absoluteX)) {
                                                absoluteX = component.position;
                                        }
                                        break;
-                               
+
                                default:
                                        throw new BugException("Unknown relative positioning type of component" +
                                                        component + ": " + component.relativePosition);
                                }
-                               
+
                                component = component.parent; // parent != null
                        }
-                       
+
                        if (!Double.isNaN(absoluteX)) {
                                for (int i = 0; i < array.length; i++) {
                                        array[i] = array[i].setX(absoluteX + c.x);
                                }
                        }
-                       
+
                        // Check whether destination has been found or whether to backtrack
                        // TODO: LOW: Backtracking into clustered components uses only one component
                        if ((dest != null) && (component != dest)) {
@@ -1013,14 +1027,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                        array[i] = array[i].sub(origin[0]);
                                }
                        }
-                       
+
                        return array;
                } finally {
                        mutex.unlock("toRelative");
                }
        }
-       
-       
+
+
        /**
         * Recursively sum the lengths of all subcomponents that have position
         * Position.AFTER.
@@ -1042,11 +1056,11 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        mutex.unlock("getTotalLength");
                }
        }
-       
-       
-       
+
+
+
        /////////// Total mass and CG calculation ////////////
-       
+
        /**
         * Return the (possibly overridden) mass of component.
         *
@@ -1058,7 +1072,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        return overrideMass;
                return getComponentMass();
        }
-       
+
        /**
         * Return the (possibly overridden) center of gravity and mass.
         *
@@ -1071,14 +1085,14 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                if (cgOverriden)
                        return getOverrideCG().setWeight(getMass());
-               
+
                if (massOverriden)
                        return getComponentCG().setWeight(getMass());
-               
+
                return getComponentCG();
        }
-       
-       
+
+
        /**
         * Return the longitudinal (around the y- or z-axis) moment of inertia of this component.
         * The moment of inertia is scaled in reference to the (possibly overridden) mass
@@ -1090,7 +1104,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return getLongitudinalUnitInertia() * getMass();
        }
-       
+
        /**
         * Return the rotational (around the y- or z-axis) moment of inertia of this component.
         * The moment of inertia is scaled in reference to the (possibly overridden) mass
@@ -1102,12 +1116,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return getRotationalUnitInertia() * getMass();
        }
-       
-       
-       
+
+
+
        ///////////  Children handling  ///////////
-       
-       
+
+
        /**
         * Adds a child to the rocket component tree.  The component is added to the end
         * of the component's child list.  This is a helper method that calls
@@ -1122,8 +1136,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                addChild(component, children.size());
        }
-       
-       
+
+
        /**
         * Adds a child to the rocket component tree.  The component is added to
         * the given position of the component's child list.
@@ -1138,32 +1152,32 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         */
        public void addChild(RocketComponent component, int index) {
                checkState();
-               
+
                if (component.parent != null) {
                        throw new IllegalArgumentException("component " + component.getComponentName() +
                                        " is already in a tree");
                }
-               
+
                // Ensure that the no loops are created in component tree [A -> X -> Y -> B, B.addChild(A)]
                if (this.getRoot().equals(component)) {
                        throw new IllegalStateException("Component " + component.getComponentName() +
                                        " is a parent of " + this.getComponentName() + ", attempting to create cycle in tree.");
                }
-               
+
                if (!isCompatible(component)) {
                        throw new IllegalStateException("Component " + component.getComponentName() +
                                        " not currently compatible with component " + getComponentName());
                }
-               
+
                children.add(index, component);
                component.parent = this;
-               
+
                this.checkComponentStructure();
                component.checkComponentStructure();
-               
+
                fireAddRemoveEvent(component);
        }
-       
+
        /**
         * Removes a child from the rocket component tree.
         *
@@ -1174,13 +1188,13 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                RocketComponent component = children.remove(n);
                component.parent = null;
-               
+
                this.checkComponentStructure();
                component.checkComponentStructure();
-               
+
                fireAddRemoveEvent(component);
        }
-       
+
        /**
         * Removes a child from the rocket component tree.  Does nothing if the component
         * is not present as a child.
@@ -1190,24 +1204,24 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         */
        public final boolean removeChild(RocketComponent component) {
                checkState();
-               
+
                component.checkComponentStructure();
-               
+
                if (children.remove(component)) {
                        component.parent = null;
-                       
+
                        this.checkComponentStructure();
                        component.checkComponentStructure();
-                       
+
                        fireAddRemoveEvent(component);
                        return true;
                }
                return false;
        }
-       
-       
-       
-       
+
+
+
+
        /**
         * Move a child to another position.
         *
@@ -1219,15 +1233,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                if (children.remove(component)) {
                        children.add(index, component);
-                       
+
                        this.checkComponentStructure();
                        component.checkComponentStructure();
-                       
+
                        fireAddRemoveEvent(component);
                }
        }
-       
-       
+
+
        /**
         * Fires an AERODYNAMIC_CHANGE, MASS_CHANGE or OTHER_CHANGE event depending on the
         * type of component removed.
@@ -1242,30 +1256,30 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        if (c.isMassive())
                                type |= ComponentChangeEvent.MASS_CHANGE;
                }
-               
+
                fireComponentChangeEvent(type);
        }
-       
-       
+
+
        public final int getChildCount() {
                checkState();
                this.checkComponentStructure();
                return children.size();
        }
-       
+
        public final RocketComponent getChild(int n) {
                checkState();
                this.checkComponentStructure();
                return children.get(n);
        }
-       
+
        public final List<RocketComponent> getChildren() {
                checkState();
                this.checkComponentStructure();
                return children.clone();
        }
-       
-       
+
+
        /**
         * Returns the position of the child in this components child list, or -1 if the
         * component is not a child of this component.
@@ -1278,7 +1292,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.checkComponentStructure();
                return children.indexOf(child);
        }
-       
+
        /**
         * Get the parent component of this component.  Returns <code>null</code> if the component
         * has no parent.
@@ -1289,7 +1303,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return parent;
        }
-       
+
        /**
         * Get the root component of the component tree.
         *
@@ -1302,7 +1316,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        gp = gp.parent;
                return gp;
        }
-       
+
        /**
         * Returns the root Rocket component of this component tree.  Throws an
         * IllegalStateException if the root component is not a Rocket.
@@ -1318,8 +1332,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                throw new IllegalStateException("getRocket() called with root component "
                                + r.getComponentName());
        }
-       
-       
+
+
        /**
         * Return the Stage component that this component belongs to.  Throws an
         * IllegalStateException if a Stage is not in the parentage of this component.
@@ -1337,7 +1351,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                throw new IllegalStateException("getStage() called without Stage as a parent.");
        }
-       
+
        /**
         * Return the stage number of the stage this component belongs to.  The stages
         * are numbered from zero upwards.
@@ -1349,7 +1363,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                if (parent == null) {
                        throw new IllegalArgumentException("getStageNumber() called for root component");
                }
-               
+
                RocketComponent stage = this;
                while (!(stage instanceof Stage)) {
                        stage = stage.parent;
@@ -1360,8 +1374,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return stage.parent.getChildPosition(stage);
        }
-       
-       
+
+
        /**
         * Find a component with the given ID.  The component tree is searched from this component
         * down (including this component) for the ID and the corresponding component is returned,
@@ -1380,8 +1394,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return null;
        }
-       
-       
+
+
        // TODO: Move these methods elsewhere (used only in SymmetricComponent)
        public final RocketComponent getPreviousComponent() {
                checkState();
@@ -1393,7 +1407,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        StringBuffer sb = new StringBuffer();
                        sb.append("Inconsistent internal state: ");
                        sb.append("this=").append(this).append('[')
-                                       .append(System.identityHashCode(this)).append(']');
+                       .append(System.identityHashCode(this)).append(']');
                        sb.append(" parent.children=[");
                        for (int i = 0; i < parent.children.size(); i++) {
                                RocketComponent c = parent.children.get(i);
@@ -1412,34 +1426,34 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        c = c.getChild(c.getChildCount() - 1);
                return c;
        }
-       
+
        // TODO: Move these methods elsewhere (used only in SymmetricComponent)
        public final RocketComponent getNextComponent() {
                checkState();
                if (getChildCount() > 0)
                        return getChild(0);
-               
+
                RocketComponent current = this;
                RocketComponent nextParent = this.parent;
-               
+
                while (nextParent != null) {
                        int pos = nextParent.getChildPosition(current);
                        if (pos < nextParent.getChildCount() - 1)
                                return nextParent.getChild(pos + 1);
-                       
+
                        current = nextParent;
                        nextParent = current.parent;
                }
                return null;
        }
-       
-       
+
+
        ///////////  Event handling  //////////
        //
        // Listener lists are provided by the root Rocket component,
        // a single listener list for the whole rocket.
        //
-       
+
        /**
         * Adds a ComponentChangeListener to the rocket tree.  The listener is added to the root
         * component, which must be of type Rocket (which overrides this method).  Events of all
@@ -1451,7 +1465,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                getRocket().addComponentChangeListener(l);
        }
-       
+
        /**
         * Removes a ComponentChangeListener from the rocket tree.  The listener is removed from
         * the root component, which must be of type Rocket (which overrides this method).
@@ -1465,8 +1479,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        getRoot().removeComponentChangeListener(l);
                }
        }
-       
-       
+
+
        /**
         * Adds a <code>ChangeListener</code> to the rocket tree.  This is identical to
         * <code>addComponentChangeListener()</code> except that it uses a
@@ -1481,7 +1495,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                getRocket().addChangeListener(l);
        }
-       
+
        /**
         * Removes a ChangeListener from the rocket tree.  This is identical to
         * removeComponentChangeListener() except it uses a ChangeListener.
@@ -1496,8 +1510,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        getRoot().removeChangeListener(l);
                }
        }
-       
-       
+
+
        /**
         * Fires a ComponentChangeEvent on the rocket structure.  The call is passed to the
         * root component, which must be of type Rocket (which overrides this method).
@@ -1518,8 +1532,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                getRoot().fireComponentChangeEvent(e);
        }
-       
-       
+
+
        /**
         * Fires a ComponentChangeEvent of the given type.  The source of the event is set to
         * this component.
@@ -1530,8 +1544,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        protected void fireComponentChangeEvent(int type) {
                fireComponentChangeEvent(new ComponentChangeEvent(this, type));
        }
-       
-       
+
+
        /**
         * Checks whether this component has been invalidated and should no longer be used.
         * This is a safety check that in-place replaced components are no longer used.
@@ -1544,8 +1558,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                invalidator.check(true);
                mutex.verify();
        }
-       
-       
+
+
        /**
         * Check that the local component structure is correct.  This can be called after changing
         * the component structure in order to verify the integrity.
@@ -1568,7 +1582,7 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                        }
                }
        }
-       
+
        // Check whether the list contains exactly the searched-for component (with == operator)
        private boolean containsExact(List<RocketComponent> haystack, RocketComponent needle) {
                for (RocketComponent c : haystack) {
@@ -1578,10 +1592,10 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                }
                return false;
        }
-       
-       
+
+
        ///////////  Iterators  //////////
-       
+
        /**
         * Returns an iterator that iterates over all children and sub-children.
         * <p>
@@ -1603,8 +1617,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final Iterator<RocketComponent> deepIterator(boolean returnSelf) {
                return iterator(returnSelf);
        }
-       
-       
+
+
        /**
         * Returns an iterator that iterates over all children and sub-children, including itself.
         * <p>
@@ -1619,9 +1633,9 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final Iterator<RocketComponent> deepIterator() {
                return iterator();
        }
-       
-       
-       
+
+
+
        /**
         * Returns an iterator that iterates over all children and sub-children.
         * <p>
@@ -1640,8 +1654,8 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                checkState();
                return new RocketComponentIterator(this, returnSelf);
        }
-       
-       
+
+
        /**
         * Returns an iterator that iterates over this component, its children and sub-children.
         * <p>
@@ -1653,11 +1667,30 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        public final Iterator<RocketComponent> iterator() {
                return iterator(true);
        }
-       
-       
-       
-       
-       
+
+       /**
+        * Retrieve the List of MotorMounts in the Rocket.
+        * 
+        * Each element returned will a RocketComponent which implements MotorMount.  Further isMotorMount()
+        * returns true.
+        * 
+        * @return List<MotorMount>
+        */
+       public final List<MotorMount> getMotorMounts() {
+               Iterator<RocketComponent> it = iterator();
+               List<MotorMount> mmts = new ArrayList<MotorMount>();
+
+               while (it.hasNext()) {
+                       RocketComponent c = it.next();
+                       if (c instanceof MotorMount) {
+                               if ( ((MotorMount)c).isMotorMount() ) {
+                                       mmts.add((MotorMount) c);
+                               }
+                       }
+               }
+               return mmts;
+       }
+
        /**
         * Compare component equality based on the ID of this component.  Only the
         * ID and class type is used for a basis of comparison.
@@ -1673,21 +1706,21 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                RocketComponent other = (RocketComponent) obj;
                return this.id.equals(other.id);
        }
-       
-       
-       
+
+
+
        @Override
        public int hashCode() {
                return id.hashCode();
        }
-       
-       
-       
+
+
+
        ////////////  Helper methods for subclasses
-       
-       
-       
-       
+
+
+
+
        /**
         * Helper method to add rotationally symmetric bounds at the specified coordinates.
         * The X-axis value is <code>x</code> and the radius at the specified position is
@@ -1699,37 +1732,41 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                bounds.add(new Coordinate(x, r, r));
                bounds.add(new Coordinate(x, -r, r));
        }
-       
-       
+
+
        protected static final Coordinate ringCG(double outerRadius, double innerRadius,
                        double x1, double x2, double density) {
                return new Coordinate((x1 + x2) / 2, 0, 0,
                                ringMass(outerRadius, innerRadius, x2 - x1, density));
        }
-       
+
+       protected static final double ringVolume( double outerRadius, double innerRadius, double length ) {
+               return ringMass( outerRadius, innerRadius, length, 1.0 );
+       }
+
        protected static final double ringMass(double outerRadius, double innerRadius,
                        double length, double density) {
                return Math.PI * (MathUtil.pow2(outerRadius) - MathUtil.pow2(innerRadius)) *
                                length * density;
        }
-       
+
        protected static final double ringLongitudinalUnitInertia(double outerRadius,
                        double innerRadius, double length) {
                // 1/12 * (3 * (r1^2 + r2^2) + h^2)
                return (3 * (MathUtil.pow2(innerRadius) + MathUtil.pow2(outerRadius)) + MathUtil.pow2(length)) / 12;
        }
-       
+
        protected static final double ringRotationalUnitInertia(double outerRadius,
                        double innerRadius) {
                // 1/2 * (r1^2 + r2^2)
                return (MathUtil.pow2(innerRadius) + MathUtil.pow2(outerRadius)) / 2;
        }
-       
-       
-       
+
+
+
        ////////////  OTHER
-       
-       
+
+
        /**
         * Loads the RocketComponent fields from the given component.  This method is meant
         * for in-place replacement of a component.  It is used with the undo/redo
@@ -1750,34 +1787,34 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
        protected List<RocketComponent> copyFrom(RocketComponent src) {
                checkState();
                List<RocketComponent> toInvalidate = new ArrayList<RocketComponent>();
-               
+
                if (this.parent != null) {
                        throw new UnsupportedOperationException("copyFrom called for non-root component, parent=" +
                                        this.parent.toDebugString() + ", this=" + this.toDebugString());
                }
-               
+
                // Add current structure to be invalidated
                Iterator<RocketComponent> iterator = this.iterator(false);
                while (iterator.hasNext()) {
                        toInvalidate.add(iterator.next());
                }
-               
+
                // Remove previous components
                for (RocketComponent child : this.children) {
                        child.parent = null;
                }
                this.children.clear();
-               
+
                // Copy new children to this component
                for (RocketComponent c : src.children) {
                        RocketComponent copy = c.copyWithOriginalID();
                        this.children.add(copy);
                        copy.parent = this;
                }
-               
+
                this.checkComponentStructure();
                src.checkComponentStructure();
-               
+
                // Set all parameters
                this.length = src.length;
                this.relativePosition = src.relativePosition;
@@ -1792,22 +1829,22 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                this.name = src.name;
                this.comment = src.comment;
                this.id = src.id;
-               
+
                // Add source components to invalidation tree
                for (RocketComponent c : src) {
                        toInvalidate.add(c);
                }
-               
+
                return toInvalidate;
        }
-       
+
        protected void invalidate() {
                invalidator.invalidate();
        }
-       
-       
+
+
        //////////  Iterator implementation  ///////////
-       
+
        /**
         * Private inner class to implement the Iterator.
         *
@@ -1815,17 +1852,17 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
         */
        private static class RocketComponentIterator implements Iterator<RocketComponent> {
                // Stack holds iterators which still have some components left.
-               private final Deque<Iterator<RocketComponent>> iteratorStack = new ArrayDeque<Iterator<RocketComponent>>();
-               
+               private final SimpleStack<Iterator<RocketComponent>> iteratorStack = new SimpleStack<Iterator<RocketComponent>>();
+
                private final Rocket root;
                private final int treeModID;
-               
+
                private final RocketComponent original;
                private boolean returnSelf = false;
-               
+
                // Construct iterator with component's child's iterator, if it has elements
                public RocketComponentIterator(RocketComponent c, boolean returnSelf) {
-                       
+
                        RocketComponent gp = c.getRoot();
                        if (gp instanceof Rocket) {
                                root = (Rocket) gp;
@@ -1834,15 +1871,15 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                root = null;
                                treeModID = -1;
                        }
-                       
+
                        Iterator<RocketComponent> i = c.children.iterator();
                        if (i.hasNext())
                                iteratorStack.push(i);
-                       
+
                        this.original = c;
                        this.returnSelf = returnSelf;
                }
-               
+
                @Override
                public boolean hasNext() {
                        checkID();
@@ -1850,38 +1887,38 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                return true;
                        return !iteratorStack.isEmpty(); // Elements remain if stack is not empty
                }
-               
+
                @Override
                public RocketComponent next() {
                        Iterator<RocketComponent> i;
-                       
+
                        checkID();
-                       
+
                        // Return original component first
                        if (returnSelf) {
                                returnSelf = false;
                                return original;
                        }
-                       
+
                        // Peek first iterator from stack, throw exception if empty
                        i = iteratorStack.peek();
                        if (i == null) {
                                throw new NoSuchElementException("No further elements in RocketComponent iterator");
                        }
-                       
+
                        // Retrieve next component of the iterator, remove iterator from stack if empty
                        RocketComponent c = i.next();
                        if (!i.hasNext())
                                iteratorStack.pop();
-                       
+
                        // Add iterator of component children to stack if it has children
                        i = c.children.iterator();
                        if (i.hasNext())
                                iteratorStack.push(i);
-                       
+
                        return c;
                }
-               
+
                private void checkID() {
                        if (root != null) {
                                if (root.getTreeModID() != treeModID) {
@@ -1889,12 +1926,12 @@ public abstract class RocketComponent implements ChangeSource, Cloneable, Iterab
                                }
                        }
                }
-               
+
                @Override
                public void remove() {
                        throw new UnsupportedOperationException("remove() not supported by " +
                                        "RocketComponent iterator");
                }
        }
-       
+
 }
index ec244ee0ecc5f8000a26f53c46d3cbaffa700b8f..f6f342c6054a80f5d78ef5ce311616a598b2de02 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.rocketcomponent;
 
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
 
@@ -12,6 +14,7 @@ import net.sf.openrocket.util.MathUtil;
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
 public class Sleeve extends RingComponent {
+       private static final Translator trans = Application.getTranslator();
        
        protected double innerRadius = 0;
        protected double thickness = 0;
@@ -91,7 +94,7 @@ public class Sleeve extends RingComponent {
        
        @Override
        public String getComponentName() {
-               return "Sleeve";
+               return trans.get ("Sleeve.Sleeve");
        }
        
        @Override
index 8d73c45718b009a44c80aa5314c0314a19de3833..058392e93e0b56c457c46a06251384dfe3052cca 100644 (file)
@@ -1,5 +1,9 @@
 package net.sf.openrocket.rocketcomponent;
 
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.MathUtil;
 
 public class Streamer extends RecoveryDevice {
@@ -8,6 +12,7 @@ public class Streamer extends RecoveryDevice {
        
        public static final double MAX_COMPUTED_CD = 0.4;
        
+       private static final Translator trans = Application.getTranslator();
 
        private double stripLength;
        private double stripWidth;
@@ -27,6 +32,7 @@ public class Streamer extends RecoveryDevice {
                if (MathUtil.equals(this.stripLength, stripLength))
                        return;
                this.stripLength = stripLength;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
        
@@ -39,6 +45,7 @@ public class Streamer extends RecoveryDevice {
                        return;
                this.stripWidth = stripWidth;
                this.length = stripWidth;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
        
@@ -83,6 +90,27 @@ public class Streamer extends RecoveryDevice {
        
        
 
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.STREAMER;
+       }
+
+
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               if ( preset.has(ComponentPreset.LENGTH)) {
+                       this.stripLength = preset.get(ComponentPreset.LENGTH);
+               }
+               if ( preset.has(ComponentPreset.WIDTH)) {
+                       this.stripWidth = preset.get(ComponentPreset.WIDTH);
+               }
+               super.loadFromPreset(preset);
+               // Fix the length to the stripWidth since RocketComponent assigns ComponentPreset.LENGTH to length.
+               this.length = this.stripWidth;
+               fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+       }
+
+
        @Override
        public double getComponentCD(double mach) {
                double density = this.getMaterial().getDensity();
@@ -95,7 +123,7 @@ public class Streamer extends RecoveryDevice {
        
        @Override
        public String getComponentName() {
-               return "Streamer";
+               return trans.get ("Streamer.Streamer");
        }
        
        @Override
index d37af27e5744829cddc44a9a8a108d5bc986838b..b7143c68297b50e8fb882aee058b4964866efa10 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.rocketcomponent;
 
 import net.sf.openrocket.material.Material;
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.startup.Application;
 
 public abstract class StructuralComponent extends InternalComponent {
@@ -12,6 +13,30 @@ public abstract class StructuralComponent extends InternalComponent {
                material = Application.getPreferences().getDefaultComponentMaterial(this.getClass(), Material.Type.BULK);
        }
        
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               super.loadFromPreset(preset);
+               if ( preset.has(ComponentPreset.MATERIAL ) ) {
+                       Material mat = preset.get(ComponentPreset.MATERIAL);
+                       if ( mat != null ) {
+                               this.material = mat;
+                       } /*
+                       TODO - 
+                       else if (c.isMassOverridden()) {
+                               double mass = c.getOverrideMass();
+                               double volume = getComponentVolume();
+                               double density;
+                               if (volume > 0.00001) {
+                                       density = mass / volume;
+                               } else {
+                                       density = 1000;
+                               }
+                               mat = Material.newMaterial(Type.BULK, mat.getName(), density, true);
+                               setMaterial(mat);
+                       }
+                       */
+               }
+       }
 
        public final Material getMaterial() {
                return material;
@@ -24,6 +49,7 @@ public abstract class StructuralComponent extends InternalComponent {
                if (mat.equals(material))
                        return;
                this.material = mat;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
 }
index 5dc1835463e9ed3bf2ad72207c0835607e2b167c..7b455fa8593f306e9c88d019bbda1d9b4bd61c07 100644 (file)
@@ -6,6 +6,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
 
@@ -146,10 +147,14 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
        
 
        @Override
-       protected void loadFromPreset(RocketComponent preset) {
-               SymmetricComponent c = (SymmetricComponent) preset;
-               this.setThickness(c.getThickness());
-               this.setFilled(c.isFilled());
+       protected void loadFromPreset(ComponentPreset preset) {
+               if ( preset.has(ComponentPreset.THICKNESS) ) {
+                       this.thickness = preset.get(ComponentPreset.THICKNESS);
+                       this.filled = false;
+               }
+               if ( preset.has(ComponentPreset.FILLED)) {
+                       this.filled = true;
+               }
                
                super.loadFromPreset(preset);
        }
@@ -293,9 +298,8 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
 
                // Integrate for volume, CG, wetted area and planform area
                
-               final double l = length / DIVISIONS;
-               final double pil = Math.PI * l; // PI * l
-               final double pil3 = Math.PI * l / 3; // PI * l/3
+               final double step = length / DIVISIONS;
+               final double pi3 = Math.PI / 3.0;
                r1 = getRadius(0);
                x = 0;
                wetArea = 0;
@@ -312,25 +316,44 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
                         * hyp is the length of the hypotenuse from r1 to r2
                         * height if the y-axis height of the component if not filled
                         */
+                       /*
+                        * l is the step size for the current loop.  Could also be called delta-x.
+                        * 
+                        * to account for accumulated errors in the x position during the loop
+                        * during the last iteration (n== DIVISIONS) we recompute l to be
+                        * whatever is left.
+                        */
+                       double l = (n==DIVISIONS) ? length -x : step;
 
-                       r2 = getRadius(x + l);
+                       // Further to prevent round off error from the previous statement,
+                       // we clamp r2 to length at the last iteration.
+                       r2 = getRadius((n==DIVISIONS) ? length : x + l);
+                       
                        final double hyp = MathUtil.hypot(r2 - r1, l);
                        
-
                        // Volume differential elements
                        final double dV;
                        final double dFullV;
                        
-                       dFullV = pil3 * (r1 * r1 + r1 * r2 + r2 * r2);
-                       if (filled || r1 < thickness || r2 < thickness) {
-                               // Filled piece
+                       dFullV = pi3 * l * (r1 * r1 + r1 * r2 + r2 * r2);
+                       
+                       if ( filled ) {
                                dV = dFullV;
                        } else {
-                               // Hollow piece
-                               final double height = thickness * hyp / l;
-                               dV = MathUtil.max(pil * height * (r1 + r2 - height), 0);
+                               // hollow
+                               // Thickness is normal to the surface of the component
+                               // here we use simple trig to project the Thickness
+                               // on to the y dimension (radius).
+                               double height = thickness * hyp / l;
+                               if (r1 < height || r2 < height) {
+                                       // Filled portion of piece
+                                       dV = dFullV;
+                               } else {
+                                       // Hollow portion of piece
+                                       dV = MathUtil.max(Math.PI* l * height * (r1 + r2 - height), 0);
+                               }
                        }
-                       
+
                        // Add to the volume-related components
                        volume += dV;
                        fullVolume += dFullV;
@@ -343,7 +366,7 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
                        final double p = l * (r1 + r2);
                        planArea += p;
                        planCenter += (x + l / 2) * p;
-                       
+
                        // Update for next iteration
                        r1 = r2;
                        x += l;
@@ -358,10 +381,10 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
                        volume = 0;
                        cg = new Coordinate(length / 2, 0, 0, 0);
                } else {
-                       // getComponentMass is safe now
-                       // Use super.getComponentMass() to ensure only the transition shape mass
-                       // is used, not the shoulders
-                       cg = new Coordinate(cgx / volume, 0, 0, super.getComponentMass());
+                       // the mass of this shape is the material density * volume.
+                       // it cannot come from super.getComponentMass() since that 
+                       // includes the shoulders
+                       cg = new Coordinate(cgx / volume, 0, 0, getMaterial().getDensity() * volume );
                }
        }
        
@@ -444,7 +467,7 @@ public abstract class SymmetricComponent extends BodyComponent implements Radial
                final double l = length / DIVISIONS;
                
                r1 = getRadius(0);
-               System.out.println(r1);
+               //System.out.println(r1);
                x = 0;
                
                longitudinalInertia = 0;
index 4bded7079e72173eb68e45e7519aa75c5631b7f8..c2d0a9bd46829c823da5acc749ff73f5fab6d6e8 100644 (file)
@@ -1,5 +1,6 @@
 package net.sf.openrocket.rocketcomponent;
 
+import net.sf.openrocket.preset.ComponentPreset;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
 
@@ -16,7 +17,24 @@ public abstract class ThicknessRingComponent extends RingComponent {
        protected double outerRadius = 0;
        protected double thickness = 0;
        
-       
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+               if ( preset.has(ComponentPreset.OUTER_DIAMETER) )  {
+                       this.outerRadiusAutomatic = false;
+                       this.innerRadiusAutomatic = false;
+                       double outerDiameter = preset.get(ComponentPreset.OUTER_DIAMETER);
+                       this.outerRadius = outerDiameter/2.0;
+                       if ( preset.has(ComponentPreset.INNER_DIAMETER) ) {
+                               double innerDiameter = preset.get(ComponentPreset.INNER_DIAMETER);
+                               this.thickness = (outerDiameter-innerDiameter) / 2.0;
+                       }
+               }
+               super.loadFromPreset(preset);
+
+               fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
+
+       }
+
        @Override
        public double getOuterRadius() {
                if (isOuterRadiusAutomatic() && getParent() instanceof RadialParent) {
@@ -45,6 +63,8 @@ public abstract class ThicknessRingComponent extends RingComponent {
                if (thickness > outerRadius)
                        thickness = outerRadius;
                
+               clearPreset();
+               
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
        
@@ -64,6 +84,8 @@ public abstract class ThicknessRingComponent extends RingComponent {
                
                this.thickness = thickness;
                
+               clearPreset();
+
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
 
index f3a6f9b6a8764925dcb53939fc0244922774da28..6b12f156ec15bc6963d109b0ffaa4cf453b67503 100644 (file)
@@ -1,28 +1,31 @@
 package net.sf.openrocket.rocketcomponent;
 
-import static java.lang.Math.sin;
-import static net.sf.openrocket.util.MathUtil.*;
-
-import java.util.Collection;
-
 import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.Coordinate;
 import net.sf.openrocket.util.MathUtil;
 
+import java.util.Collection;
+
+import static java.lang.Math.sin;
+import static net.sf.openrocket.util.MathUtil.pow2;
+import static net.sf.openrocket.util.MathUtil.pow3;
+
 
 public class Transition extends SymmetricComponent {
        private static final Translator trans = Application.getTranslator();
        private static final double CLIP_PRECISION = 0.0001;
-       
+
 
        private Shape type;
        private double shapeParameter;
        private boolean clipped; // Not to be read - use isClipped(), which may be overriden
-       
+
        private double radius1, radius2;
        private boolean autoRadius1, autoRadius2; // Whether the start radius is automatic
-                       
+
 
        private double foreShoulderRadius;
        private double foreShoulderThickness;
@@ -32,30 +35,39 @@ public class Transition extends SymmetricComponent {
        private double aftShoulderThickness;
        private double aftShoulderLength;
        private boolean aftShoulderCapped;
-       
+
 
        // Used to cache the clip length
        private double clipLength = -1;
-       
+
        public Transition() {
                super();
-               
+
                this.radius1 = DEFAULT_RADIUS;
                this.radius2 = DEFAULT_RADIUS;
                this.length = DEFAULT_RADIUS * 3;
                this.autoRadius1 = true;
                this.autoRadius2 = true;
-               
+
                this.type = Shape.CONICAL;
                this.shapeParameter = 0;
                this.clipped = true;
        }
-       
-       
+
+       ////////  Length  ////////
+       @Override
+       public void setLength( double length ) {
+               if ( this.length == length ) {
+                       return;
+               }
+               // Need to clearPreset when length changes.
+               clearPreset();
+               super.setLength( length );
+       }
 
 
        ////////  Fore radius  ////////
-       
+
 
        @Override
        public double getForeRadius() {
@@ -72,35 +84,39 @@ public class Transition extends SymmetricComponent {
                }
                return radius1;
        }
-       
+
        public void setForeRadius(double radius) {
                if ((this.radius1 == radius) && (autoRadius1 == false))
                        return;
-               
+
                this.autoRadius1 = false;
                this.radius1 = Math.max(radius, 0);
-               
+
                if (this.thickness > this.radius1 && this.thickness > this.radius2)
                        this.thickness = Math.max(this.radius1, this.radius2);
+
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        @Override
        public boolean isForeRadiusAutomatic() {
                return autoRadius1;
        }
-       
+
        public void setForeRadiusAutomatic(boolean auto) {
                if (autoRadius1 == auto)
                        return;
-               
+
                autoRadius1 = auto;
+
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
        ////////  Aft radius  /////////
-       
+
        @Override
        public double getAftRadius() {
                if (isAftRadiusAutomatic()) {
@@ -116,62 +132,66 @@ public class Transition extends SymmetricComponent {
                }
                return radius2;
        }
-       
-       
+
+
 
        public void setAftRadius(double radius) {
                if ((this.radius2 == radius) && (autoRadius2 == false))
                        return;
-               
+
                this.autoRadius2 = false;
                this.radius2 = Math.max(radius, 0);
-               
+
                if (this.thickness > this.radius1 && this.thickness > this.radius2)
                        this.thickness = Math.max(this.radius1, this.radius2);
+
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        @Override
        public boolean isAftRadiusAutomatic() {
                return autoRadius2;
        }
-       
+
        public void setAftRadiusAutomatic(boolean auto) {
                if (autoRadius2 == auto)
                        return;
-               
+
                autoRadius2 = auto;
+
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
-       
+
+
 
        //// Radius automatics
-       
+
        @Override
        protected double getFrontAutoRadius() {
                if (isAftRadiusAutomatic())
                        return -1;
                return getAftRadius();
        }
-       
-       
+
+
        @Override
        protected double getRearAutoRadius() {
                if (isForeRadiusAutomatic())
                        return -1;
                return getForeRadius();
        }
-       
-       
+
+
 
 
        ////////  Type & shape  /////////
-       
+
        public Shape getType() {
                return type;
        }
-       
+
        public void setType(Shape type) {
                if (type == null) {
                        throw new IllegalArgumentException("setType called with null argument");
@@ -183,142 +203,144 @@ public class Transition extends SymmetricComponent {
                this.shapeParameter = type.defaultParameter();
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        public double getShapeParameter() {
                return shapeParameter;
        }
-       
+
        public void setShapeParameter(double n) {
                if (shapeParameter == n)
                        return;
                this.shapeParameter = MathUtil.clamp(n, type.minParameter(), type.maxParameter());
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        public boolean isClipped() {
                if (!type.isClippable())
                        return false;
                return clipped;
        }
-       
+
        public void setClipped(boolean c) {
                if (clipped == c)
                        return;
                clipped = c;
                fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
        }
-       
+
        public boolean isClippedEnabled() {
                return type.isClippable();
        }
-       
+
        public double getShapeParameterMin() {
                return type.minParameter();
        }
-       
+
        public double getShapeParameterMax() {
                return type.maxParameter();
        }
-       
-       
+
+
        ////////  Shoulders  ////////
-       
+
        public double getForeShoulderRadius() {
                return foreShoulderRadius;
        }
-       
+
        public void setForeShoulderRadius(double foreShoulderRadius) {
                if (MathUtil.equals(this.foreShoulderRadius, foreShoulderRadius))
                        return;
                this.foreShoulderRadius = foreShoulderRadius;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public double getForeShoulderThickness() {
                return foreShoulderThickness;
        }
-       
+
        public void setForeShoulderThickness(double foreShoulderThickness) {
                if (MathUtil.equals(this.foreShoulderThickness, foreShoulderThickness))
                        return;
                this.foreShoulderThickness = foreShoulderThickness;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public double getForeShoulderLength() {
                return foreShoulderLength;
        }
-       
+
        public void setForeShoulderLength(double foreShoulderLength) {
                if (MathUtil.equals(this.foreShoulderLength, foreShoulderLength))
                        return;
                this.foreShoulderLength = foreShoulderLength;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public boolean isForeShoulderCapped() {
                return foreShoulderCapped;
        }
-       
+
        public void setForeShoulderCapped(boolean capped) {
                if (this.foreShoulderCapped == capped)
                        return;
                this.foreShoulderCapped = capped;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
 
 
        public double getAftShoulderRadius() {
                return aftShoulderRadius;
        }
-       
+
        public void setAftShoulderRadius(double aftShoulderRadius) {
                if (MathUtil.equals(this.aftShoulderRadius, aftShoulderRadius))
                        return;
                this.aftShoulderRadius = aftShoulderRadius;
+               clearPreset();
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public double getAftShoulderThickness() {
                return aftShoulderThickness;
        }
-       
+
        public void setAftShoulderThickness(double aftShoulderThickness) {
                if (MathUtil.equals(this.aftShoulderThickness, aftShoulderThickness))
                        return;
                this.aftShoulderThickness = aftShoulderThickness;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public double getAftShoulderLength() {
                return aftShoulderLength;
        }
-       
+
        public void setAftShoulderLength(double aftShoulderLength) {
                if (MathUtil.equals(this.aftShoulderLength, aftShoulderLength))
                        return;
                this.aftShoulderLength = aftShoulderLength;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
+
        public boolean isAftShoulderCapped() {
                return aftShoulderCapped;
        }
-       
+
        public void setAftShoulderCapped(boolean capped) {
                if (this.aftShoulderCapped == capped)
                        return;
                this.aftShoulderCapped = capped;
                fireComponentChangeEvent(ComponentChangeEvent.MASS_CHANGE);
        }
-       
-       
+
+
 
 
        ///////////   Shape implementations   ////////////
-       
+
 
 
        /**
@@ -328,20 +350,20 @@ public class Transition extends SymmetricComponent {
        public double getRadius(double x) {
                if (x < 0 || x > length)
                        return 0;
-               
+
                double r1 = getForeRadius();
                double r2 = getAftRadius();
-               
+
                if (r1 == r2)
                        return r1;
-               
+
                if (r1 > r2) {
                        x = length - x;
                        double tmp = r1;
                        r1 = r2;
                        r2 = tmp;
                }
-               
+
                if (isClipped()) {
                        // Check clip calculation
                        if (clipLength < 0)
@@ -352,7 +374,7 @@ public class Transition extends SymmetricComponent {
                        return r1 + type.getRadius(x, r2 - r1, length, shapeParameter);
                }
        }
-       
+
        /**
         * Numerically solve clipLength from the equation
         *     r1 == type.getRadius(clipLength,r2,clipLength+length)
@@ -360,27 +382,27 @@ public class Transition extends SymmetricComponent {
         */
        private void calculateClip(double r1, double r2) {
                double min = 0, max = length;
-               
+
                if (r1 >= r2) {
                        double tmp = r1;
                        r1 = r2;
                        r2 = tmp;
                }
-               
+
                if (r1 == 0) {
                        clipLength = 0;
                        return;
                }
-               
+
                if (length <= 0) {
                        clipLength = 0;
                        return;
                }
-               
+
                // Required:
                //    getR(min,min+length,r2) - r1 < 0
                //    getR(max,max+length,r2) - r1 > 0
-               
+
                int n = 0;
                while (type.getRadius(max, r2, max + length, shapeParameter) - r1 < 0) {
                        min = max;
@@ -389,7 +411,7 @@ public class Transition extends SymmetricComponent {
                        if (n > 10)
                                break;
                }
-               
+
                while (true) {
                        clipLength = (min + max) / 2;
                        if ((max - min) < CLIP_PRECISION)
@@ -402,14 +424,14 @@ public class Transition extends SymmetricComponent {
                        }
                }
        }
-       
-       
+
+
        @Override
        public double getInnerRadius(double x) {
                return Math.max(getRadius(x) - thickness, 0);
        }
-       
-       
+
+
 
        @Override
        public Collection<Coordinate> getComponentBounds() {
@@ -420,33 +442,33 @@ public class Transition extends SymmetricComponent {
                        addBound(bounds, getLength() + aftShoulderLength, aftShoulderRadius);
                return bounds;
        }
-       
+
        @Override
-       public double getComponentMass() {
-               double mass = super.getComponentMass();
+       public double getComponentVolume() {
+               double volume =  super.getComponentVolume();
                if (getForeShoulderLength() > 0.001) {
                        final double or = getForeShoulderRadius();
                        final double ir = Math.max(getForeShoulderRadius() - getForeShoulderThickness(), 0);
-                       mass += ringMass(or, ir, getForeShoulderLength(), getMaterial().getDensity());
+                       volume += ringVolume( or, ir, getForeShoulderLength() );
                }
                if (isForeShoulderCapped()) {
                        final double ir = Math.max(getForeShoulderRadius() - getForeShoulderThickness(), 0);
-                       mass += ringMass(ir, 0, getForeShoulderThickness(), getMaterial().getDensity());
+                       volume += ringVolume(ir, 0, getForeShoulderThickness() );
                }
-               
+
                if (getAftShoulderLength() > 0.001) {
                        final double or = getAftShoulderRadius();
                        final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
-                       mass += ringMass(or, ir, getAftShoulderLength(), getMaterial().getDensity());
+                       volume += ringVolume(or, ir, getAftShoulderLength() );
                }
                if (isAftShoulderCapped()) {
                        final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
-                       mass += ringMass(ir, 0, getAftShoulderThickness(), getMaterial().getDensity());
+                       volume += ringVolume(ir, 0, getAftShoulderThickness() );
                }
-               
-               return mass;
+
+               return volume;
        }
-       
+
        @Override
        public Coordinate getComponentCG() {
                Coordinate cg = super.getComponentCG();
@@ -461,7 +483,7 @@ public class Transition extends SymmetricComponent {
                                        getForeShoulderThickness() - getForeShoulderLength(),
                                        getMaterial().getDensity()));
                }
-               
+
                if (getAftShoulderLength() > 0.001) {
                        final double ir = Math.max(getAftShoulderRadius() - getAftShoulderThickness(), 0);
                        cg = cg.average(ringCG(getAftShoulderRadius(), ir, getLength(),
@@ -475,8 +497,8 @@ public class Transition extends SymmetricComponent {
                }
                return cg;
        }
-       
-       
+
+
        /*
         * The moments of inertia are not explicitly corrected for the shoulders.
         * However, since the mass is corrected, the inertia is automatically corrected
@@ -493,13 +515,13 @@ public class Transition extends SymmetricComponent {
                //// Transition
                return trans.get("Transition.Transition");
        }
-       
+
        @Override
        protected void componentChanged(ComponentChangeEvent e) {
                super.componentChanged(e);
                clipLength = -1;
        }
-       
+
        /**
         * Check whether the given type can be added to this component.  Transitions allow any
         * InternalComponents to be added.
@@ -513,8 +535,63 @@ public class Transition extends SymmetricComponent {
                        return true;
                return false;
        }
-       
-       
+
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.TRANSITION;
+       }
+
+
+       @Override
+       protected void loadFromPreset(ComponentPreset preset) {
+
+               boolean presetFilled = false;
+               if ( preset.has(ComponentPreset.FILLED ) ) {
+                       presetFilled = preset.get( ComponentPreset.FILLED);
+               }
+
+               if ( preset.has(ComponentPreset.SHAPE) ) {
+                       Shape s = preset.get(ComponentPreset.SHAPE);
+                       this.setType(s);
+               }
+               if ( preset.has(ComponentPreset.AFT_OUTER_DIAMETER) )  {
+                       double outerDiameter = preset.get(ComponentPreset.AFT_OUTER_DIAMETER);
+                       this.setAftRadiusAutomatic(false);
+                       this.setAftRadius(outerDiameter/2.0);
+               }
+               if ( preset.has(ComponentPreset.AFT_SHOULDER_LENGTH) ) {
+                       double d = preset.get(ComponentPreset.AFT_SHOULDER_LENGTH);
+                       this.setAftShoulderLength(d);
+               }
+               if ( preset.has(ComponentPreset.AFT_SHOULDER_DIAMETER) ) {
+                       double d = preset.get(ComponentPreset.AFT_SHOULDER_DIAMETER);
+                       this.setAftShoulderRadius(d/2.0);
+                       if ( presetFilled ) {
+                               this.setAftShoulderThickness(d/2.0);
+                       }
+               }
+               if ( preset.has(ComponentPreset.FORE_OUTER_DIAMETER) )  {
+                       double outerDiameter = preset.get(ComponentPreset.FORE_OUTER_DIAMETER);
+                       this.setForeRadiusAutomatic(false);
+                       this.setForeRadius(outerDiameter/2.0);
+               }
+               if ( preset.has(ComponentPreset.FORE_SHOULDER_LENGTH) ) {
+                       double d = preset.get(ComponentPreset.FORE_SHOULDER_LENGTH);
+                       this.setForeShoulderLength(d);
+               }
+               if ( preset.has(ComponentPreset.FORE_SHOULDER_DIAMETER) ) {
+                       double d = preset.get(ComponentPreset.FORE_SHOULDER_DIAMETER);
+                       this.setForeShoulderRadius(d/2.0);
+                       if ( presetFilled ) {
+                               this.setForeShoulderThickness(d/2.0);
+                       }
+               }
+
+               super.loadFromPreset(preset);
+
+               fireComponentChangeEvent(ComponentChangeEvent.BOTH_CHANGE);
+
+       }
 
        /**
         * An enumeration listing the possible shapes of transitions.
@@ -522,7 +599,7 @@ public class Transition extends SymmetricComponent {
         * @author Sampo Niskanen <sampo.niskanen@iki.fi>
         */
        public static enum Shape {
-               
+
                /**
                 * Conical shape.
                 */
@@ -540,7 +617,7 @@ public class Transition extends SymmetricComponent {
                                return radius * x / length;
                        }
                },
-               
+
                /**
                 * Ogive shape.  The shape parameter is the portion of an extended tangent ogive
                 * that will be used.  That is, for param==1 a tangent ogive will be produced, and
@@ -556,12 +633,12 @@ public class Transition extends SymmetricComponent {
                        public boolean usesParameter() {
                                return true; // Range 0...1 is default
                        }
-                       
+
                        @Override
                        public double defaultParameter() {
                                return 1.0; // Tangent ogive by default
                        }
-                       
+
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -569,17 +646,17 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 1;
-                               
+
                                // Impossible to calculate ogive for length < radius, scale instead
                                // TODO: LOW: secant ogive could be calculated lower
                                if (length < radius) {
                                        x = x * radius / length;
                                        length = radius;
                                }
-                               
+
                                if (param < 0.001)
                                        return CONICAL.getRadius(x, radius, length, param);
-                               
+
                                // Radius of circle is:
                                double R = MathUtil.safeSqrt((pow2(length) + pow2(radius)) *
                                                (pow2((2 - param) * length) + pow2(param * radius)) / (4 * pow2(param * radius)));
@@ -589,7 +666,7 @@ public class Transition extends SymmetricComponent {
                                return MathUtil.safeSqrt(R * R - (L - x) * (L - x)) - y0;
                        }
                },
-               
+
                /**
                 * Ellipsoidal shape.
                 */
@@ -597,7 +674,7 @@ public class Transition extends SymmetricComponent {
                ELLIPSOID(trans.get("Shape.Ellipsoid"),
                                //// An ellipsoidal nose cone has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.
                                trans.get("Shape.Ellipsoid.desc1"),
-                               //// An ellipsoidal transition has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the transition is not clipped, then the profile is extended at the center by the corresponding radius.         
+                               //// An ellipsoidal transition has a profile of a half-ellipse with major axes of lengths 2&times;<i>Length</i> and <i>Diameter</i>.  If the transition is not clipped, then the profile is extended at the center by the corresponding radius.
                                trans.get("Shape.Ellipsoid.desc2"), true) {
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
@@ -608,7 +685,7 @@ public class Transition extends SymmetricComponent {
                                return MathUtil.safeSqrt(2 * radius * x - x * x); // radius/length * sphere
                        }
                },
-               
+
                //// Power series
                POWER(trans.get("Shape.Powerseries"),
                                trans.get("Shape.Powerseries.desc1"),
@@ -617,12 +694,12 @@ public class Transition extends SymmetricComponent {
                        public boolean usesParameter() { // Range 0...1
                                return true;
                        }
-                       
+
                        @Override
                        public double defaultParameter() {
                                return 0.5;
                        }
-                       
+
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -638,29 +715,29 @@ public class Transition extends SymmetricComponent {
                                }
                                return radius * Math.pow(x / length, param);
                        }
-                       
+
                },
-               
+
                //// Parabolic series
                PARABOLIC(trans.get("Shape.Parabolicseries"),
                                ////A parabolic series nose cone has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> nose cone.
                                trans.get("Shape.Parabolicseries.desc1"),
                                ////A parabolic series transition has a profile of a parabola.  The shape parameter defines the segment of the parabola to utilize.  The shape parameter 1.0 produces a <b>full parabola</b> which is tangent to the body tube at the aft end, 0.75 produces a <b>3/4 parabola</b>, 0.5 procudes a <b>1/2 parabola</b> and 0 produces a <b>conical</b> transition.
                                trans.get("Shape.Parabolicseries.desc2")) {
-                       
+
                        // In principle a parabolic transition is clippable, but the difference is
                        // negligible.
-                       
+
                        @Override
                        public boolean usesParameter() { // Range 0...1
                                return true;
                        }
-                       
+
                        @Override
                        public double defaultParameter() {
                                return 1.0;
                        }
-                       
+
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -668,28 +745,28 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 1;
-                               
+
                                return radius * ((2 * x / length - param * pow2(x / length)) / (2 - param));
                        }
                },
-               
+
                //// Haack series
                HAACK(trans.get("Shape.Haackseries"),
                                //// The Haack series nose cones are designed to minimize drag.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> nose cone, which minimizes drag for fixed length and diameter, while a value of 0.333 produces an <b>LV-Haack</b> nose cone, which minimizes drag for fixed length and volume.
                                trans.get("Shape.Haackseries.desc1"),
-                               //// The Haack series <i>nose cones</i> are designed to minimize drag.  These transition shapes are their equivalents, but do not necessarily produce optimal drag for transitions.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, while a value of 0.333 produces an <b>LV-Haack</b> shape.            
+                               //// The Haack series <i>nose cones</i> are designed to minimize drag.  These transition shapes are their equivalents, but do not necessarily produce optimal drag for transitions.  The shape parameter 0 produces an <b>LD-Haack</b> or <b>Von Karman</b> shape, while a value of 0.333 produces an <b>LV-Haack</b> shape.
                                trans.get("Shape.Haackseries.desc2"), true) {
-                       
+
                        @Override
                        public boolean usesParameter() {
                                return true;
                        }
-                       
+
                        @Override
                        public double maxParameter() {
                                return 1.0 / 3.0; // Range 0...1/3
                        }
-                       
+
                        @Override
                        public double getRadius(double x, double radius, double length, double param) {
                                assert x >= 0;
@@ -697,7 +774,7 @@ public class Transition extends SymmetricComponent {
                                assert radius >= 0;
                                assert param >= 0;
                                assert param <= 2;
-                               
+
                                double theta = Math.acos(1 - 2 * x / length);
                                if (MathUtil.equals(param, 0)) {
                                        return radius * MathUtil.safeSqrt((theta - sin(2 * theta) / 2) / Math.PI);
@@ -705,7 +782,7 @@ public class Transition extends SymmetricComponent {
                                return radius * MathUtil.safeSqrt((theta - sin(2 * theta) / 2 + param * pow3(sin(theta))) / Math.PI);
                        }
                },
-               
+
                //              POLYNOMIAL("Smooth polynomial",
                //                              "A polynomial is fitted such that the nose cone profile is horizontal "+
                //                              "at the aft end of the transition.  The angle at the tip is defined by "+
@@ -737,18 +814,18 @@ public class Transition extends SymmetricComponent {
                //                      }
                //              }
                ;
-               
+
                // Privete fields of the shapes
                private final String name;
                private final String transitionDesc;
                private final String noseconeDesc;
                private final boolean canClip;
-               
+
                // Non-clippable constructor
                Shape(String name, String noseconeDesc, String transitionDesc) {
                        this(name, noseconeDesc, transitionDesc, false);
                }
-               
+
                // Clippable constructor
                Shape(String name, String noseconeDesc, String transitionDesc, boolean canClip) {
                        this.name = name;
@@ -756,29 +833,29 @@ public class Transition extends SymmetricComponent {
                        this.noseconeDesc = noseconeDesc;
                        this.transitionDesc = transitionDesc;
                }
-               
-               
+
+
                /**
                 * Return the name of the transition shape name.
                 */
                public String getName() {
                        return name;
                }
-               
+
                /**
                 * Get a description of the Transition shape.
                 */
                public String getTransitionDescription() {
                        return transitionDesc;
                }
-               
+
                /**
                 * Get a description of the NoseCone shape.
                 */
                public String getNoseConeDescription() {
                        return noseconeDesc;
                }
-               
+
                /**
                 * Check whether the shape differs in clipped mode.  The clipping should be
                 * enabled by default if possible.
@@ -786,35 +863,35 @@ public class Transition extends SymmetricComponent {
                public boolean isClippable() {
                        return canClip;
                }
-               
+
                /**
                 * Return whether the shape uses the shape parameter.  (Default false.)
                 */
                public boolean usesParameter() {
                        return false;
                }
-               
+
                /**
                 * Return the minimum value of the shape parameter.  (Default 0.)
                 */
                public double minParameter() {
                        return 0.0;
                }
-               
+
                /**
                 * Return the maximum value of the shape parameter.  (Default 1.)
                 */
                public double maxParameter() {
                        return 1.0;
                }
-               
+
                /**
                 * Return the default value of the shape parameter.  (Default 0.)
                 */
                public double defaultParameter() {
                        return 0.0;
                }
-               
+
                /**
                 * Calculate the basic radius of a transition with the given radius, length and
                 * shape parameter at the point x from the tip of the component.  It is assumed
@@ -828,8 +905,8 @@ public class Transition extends SymmetricComponent {
                 * @return       The basic radius at the given position.
                 */
                public abstract double getRadius(double x, double radius, double length, double param);
-               
-               
+
+
                /**
                 * Returns the name of the shape (same as getName()).
                 */
@@ -837,5 +914,22 @@ public class Transition extends SymmetricComponent {
                public String toString() {
                        return name;
                }
+
+        /**
+         * Lookup the Shape given the localized name.  This differs from the standard valueOf as that looks up
+         * based on the canonical name, not the localized name which is an instance var.
+         *
+         * @param localizedName
+         * @return
+         */
+        public static Shape toShape(String localizedName) {
+            Shape[] values = Shape.values();
+            for (Shape value : values) {
+                if (value.getName().equals(localizedName)) {
+                    return value;
+                }
+            }
+            return null;
+        }
        }
 }
index 5e22ec0c1cfb3e13e7fecc745e479f54dcb61c04..4f50099c3f5a67c19ee623af5c14ef9e074b6fab 100644 (file)
@@ -1,6 +1,8 @@
 package net.sf.openrocket.rocketcomponent;
 
 import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPreset.Type;
 import net.sf.openrocket.startup.Application;
 
 
@@ -13,7 +15,12 @@ public class TubeCoupler extends ThicknessRingComponent implements RadialParent
                setLength(0.06);
        }
        
-       
+       @Override
+       public Type getPresetType() {
+               return ComponentPreset.Type.TUBE_COUPLER;
+       }
+
+
        // Make setter visible
        @Override
        public void setOuterRadiusAutomatic(boolean auto) {
index 85be91201282613b629491f40c9f82eb53e1ca3d..0aab853ac46fa485088747145a25d485eaf4cc83 100644 (file)
@@ -115,7 +115,7 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
        protected MassData calculateMassData(SimulationStatus status) throws SimulationException {
                MassData mass;
                Coordinate cg;
-               double longitudinalInertia, rotationalInertia;
+               double longitudinalInertia, rotationalInertia, propellantMass;
                
                // Call pre-listener
                mass = SimulationListenerHelper.firePreMassCalculation(status);
@@ -127,7 +127,8 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
                cg = calc.getCG(status.getConfiguration(), status.getMotorConfiguration());
                longitudinalInertia = calc.getLongitudinalInertia(status.getConfiguration(), status.getMotorConfiguration());
                rotationalInertia = calc.getRotationalInertia(status.getConfiguration(), status.getMotorConfiguration());
-               mass = new MassData(cg, longitudinalInertia, rotationalInertia);
+               propellantMass = calc.getPropellantMass(status.getConfiguration(), status.getMotorConfiguration());
+               mass = new MassData(cg, longitudinalInertia, rotationalInertia, propellantMass);
                
                // Call post-listener
                mass = SimulationListenerHelper.firePostMassCalculation(status, mass);
@@ -135,6 +136,7 @@ public abstract class AbstractSimulationStepper implements SimulationStepper {
                checkNaN(mass.getCG());
                checkNaN(mass.getLongitudinalInertia());
                checkNaN(mass.getRotationalInertia());
+               checkNaN(mass.getPropellantMass());
                
                return mass;
        }
index 305516ad78b0a8ff122064086258ae245f642250..1735206246bccaefdae5ffe922df29a2b61cb44f 100644 (file)
@@ -6,6 +6,7 @@ import java.util.Set;
 
 import net.sf.openrocket.aerodynamics.FlightConditions;
 import net.sf.openrocket.aerodynamics.Warning;
+import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.motor.Motor;
 import net.sf.openrocket.motor.MotorId;
@@ -31,6 +32,7 @@ import net.sf.openrocket.util.Quaternion;
 
 public class BasicEventSimulationEngine implements SimulationEngine {
        
+       private static final Translator trans = Application.getTranslator();
        private static final LogHelper log = Application.getLogger();
        
        // TODO: MEDIUM: Allow selecting steppers
@@ -468,15 +470,14 @@ public class BasicEventSimulationEngine implements SimulationEngine {
                                        
                                        // Check for launch rod
                                        if (!status.isLaunchRodCleared()) {
-                                               status.getWarnings().add(Warning.fromString("Recovery device device deployed while on " +
-                                                               "the launch guide."));
+                                               status.getWarnings().add(Warning.RECOVERY_LAUNCH_ROD);
                                        }
                                        
                                        // Check current velocity
                                        if (status.getRocketVelocity().length() > 20) {
                                                // TODO: LOW: Custom warning.
-                                               status.getWarnings().add(Warning.fromString("Recovery device deployment at high " +
-                                                               "speed ("
+                                               status.getWarnings().add(Warning.fromString(trans.get("Warning.RECOVERY_HIGH_SPEED") +
+                                                               " ("
                                                                + UnitGroup.UNITS_VELOCITY.toStringUnit(status.getRocketVelocity().length())
                                                                + ")."));
                                        }
index dc67e85375c60cdc8c2e15d1937f433c8db999ec..0d9c3954b5bff15ee04f4dcbbe4a8f9d74f628ff 100644 (file)
@@ -109,6 +109,8 @@ public class BasicLandingStepper extends AbstractSimulationStepper {
 
                data.setValue(FlightDataType.TYPE_LATITUDE, status.getRocketWorldPosition().getLatitudeRad());
                data.setValue(FlightDataType.TYPE_LONGITUDE, status.getRocketWorldPosition().getLongitudeRad());
+               data.setValue(FlightDataType.TYPE_GRAVITY, gravity);
+               
                if (status.getSimulationConditions().getGeodeticComputation() != GeodeticComputationStrategy.FLAT) {
                        data.setValue(FlightDataType.TYPE_CORIOLIS_ACCELERATION, coriolisAcceleration.length());
                }
@@ -121,6 +123,7 @@ public class BasicLandingStepper extends AbstractSimulationStepper {
                data.setValue(FlightDataType.TYPE_MACH_NUMBER, mach);
                
                data.setValue(FlightDataType.TYPE_MASS, mass);
+               data.setValue(FlightDataType.TYPE_PROPELLANT_MASS, 0.0); // Is this a reasonable assumption? Probably.
                
                data.setValue(FlightDataType.TYPE_THRUST_FORCE, 0);
                data.setValue(FlightDataType.TYPE_DRAG_FORCE, dragForce);
index f3eb3d9c751d1a7b0d6ef5faf6f3dff0e9ea22c3..76bef7642841cc5150969b912d1efd19032b8796 100644 (file)
@@ -68,7 +68,16 @@ public class FlightDataBranch implements Monitorable {
                }
        }
        
-       
+       /**
+        * Makes an 'empty' flight data branch which has no data but all built in data types are defined.
+        */
+       public FlightDataBranch() {
+               branchName = "Empty branch";
+               for (FlightDataType type : FlightDataType.ALL_TYPES){
+                       this.setValue(type, Double.NaN);
+               }
+               this.immute();
+       }
 
        /**
         * Adds a new point into the data branch.  The value for all types is set to NaN by default.
@@ -97,8 +106,8 @@ public class FlightDataBranch implements Monitorable {
                mutable.check();
                
                ArrayList<Double> list = values.get(type);
+               
                if (list == null) {
-                       
                        list = new ArrayList<Double>();
                        int n = getLength();
                        for (int i = 0; i < n; i++) {
@@ -106,10 +115,13 @@ public class FlightDataBranch implements Monitorable {
                        }
                        values.put(type, list);
                        minValues.put(type, value);
-                       maxValues.put(type, value);
-                       
+                       maxValues.put(type, value);             
                }
-               list.set(list.size() - 1, value);
+               
+               if (list.size() > 0){
+                       list.set(list.size() - 1, value);
+               }
+               
                double min = minValues.get(type);
                double max = maxValues.get(type);
                
index 26862420cd9b1cd0e70b4fecccb1ef17ef548e64..adb4b51bc88eae89612fce7ed2df8b03833b89b5 100644 (file)
@@ -1,9 +1,11 @@
 package net.sf.openrocket.simulation;
 
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 
 import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.unit.UnitGroup;
 
@@ -22,221 +24,355 @@ import net.sf.openrocket.unit.UnitGroup;
  */
 public class FlightDataType implements Comparable<FlightDataType> {
        private static final Translator trans = Application.getTranslator();
+       private static final LogHelper log = Application.getLogger();
        
        /** Priority of custom-created variables */
        private static final int DEFAULT_PRIORITY = 999;
        
        /** List of existing types.  MUST BE DEFINED BEFORE ANY TYPES!! */
+       /** NOTE: The String key here is now the symbol */
        private static final Map<String, FlightDataType> EXISTING_TYPES = new HashMap<String, FlightDataType>();
        
-
-
+       
        //// Time
-       public static final FlightDataType TYPE_TIME = newType(trans.get("FlightDataType.TYPE_TIME"), UnitGroup.UNITS_FLIGHT_TIME, 1);
+       public static final FlightDataType TYPE_TIME = newType(trans.get("FlightDataType.TYPE_TIME"), "t", UnitGroup.UNITS_FLIGHT_TIME, 1);
        
-
        //// Vertical position and motion
        //// Altitude
-       public static final FlightDataType TYPE_ALTITUDE = newType(trans.get("FlightDataType.TYPE_ALTITUDE"), UnitGroup.UNITS_DISTANCE, 10);
+       public static final FlightDataType TYPE_ALTITUDE = newType(trans.get("FlightDataType.TYPE_ALTITUDE"), "h", UnitGroup.UNITS_DISTANCE, 10);
        //// Vertical velocity
-       public static final FlightDataType TYPE_VELOCITY_Z = newType(trans.get("FlightDataType.TYPE_VELOCITY_Z"), UnitGroup.UNITS_VELOCITY, 11);
+       public static final FlightDataType TYPE_VELOCITY_Z = newType(trans.get("FlightDataType.TYPE_VELOCITY_Z"), "Vz", UnitGroup.UNITS_VELOCITY, 11);
        //// Vertical acceleration
-       public static final FlightDataType TYPE_ACCELERATION_Z = newType(trans.get("FlightDataType.TYPE_ACCELERATION_Z"), UnitGroup.UNITS_ACCELERATION, 12);
+       public static final FlightDataType TYPE_ACCELERATION_Z = newType(trans.get("FlightDataType.TYPE_ACCELERATION_Z"), "Az", UnitGroup.UNITS_ACCELERATION, 12);
+       
        
-
        //// Total motion
        //// Total velocity
-       public static final FlightDataType TYPE_VELOCITY_TOTAL = newType(trans.get("FlightDataType.TYPE_VELOCITY_TOTAL"), UnitGroup.UNITS_VELOCITY, 20);
+       public static final FlightDataType TYPE_VELOCITY_TOTAL = newType(trans.get("FlightDataType.TYPE_VELOCITY_TOTAL"), "Vt", UnitGroup.UNITS_VELOCITY, 20);
        //// Total acceleration
-       public static final FlightDataType TYPE_ACCELERATION_TOTAL = newType(trans.get("FlightDataType.TYPE_ACCELERATION_TOTAL"), UnitGroup.UNITS_ACCELERATION, 21);
+       public static final FlightDataType TYPE_ACCELERATION_TOTAL = newType(trans.get("FlightDataType.TYPE_ACCELERATION_TOTAL"), "At", UnitGroup.UNITS_ACCELERATION, 21);
+       
        
-
        //// Lateral position and motion
        //// Position upwind
-       public static final FlightDataType TYPE_POSITION_X = newType(trans.get("FlightDataType.TYPE_POSITION_X"), UnitGroup.UNITS_DISTANCE, 30);
+       public static final FlightDataType TYPE_POSITION_X = newType(trans.get("FlightDataType.TYPE_POSITION_X"), "Px", UnitGroup.UNITS_DISTANCE, 30);
        //// Position parallel to wind
-       public static final FlightDataType TYPE_POSITION_Y = newType(trans.get("FlightDataType.TYPE_POSITION_Y"), UnitGroup.UNITS_DISTANCE, 31);
+       public static final FlightDataType TYPE_POSITION_Y = newType(trans.get("FlightDataType.TYPE_POSITION_Y"), "Py", UnitGroup.UNITS_DISTANCE, 31);
        //// Lateral distance
-       public static final FlightDataType TYPE_POSITION_XY = newType(trans.get("FlightDataType.TYPE_POSITION_XY"), UnitGroup.UNITS_DISTANCE, 32);
+       public static final FlightDataType TYPE_POSITION_XY = newType(trans.get("FlightDataType.TYPE_POSITION_XY"), "Pl", UnitGroup.UNITS_DISTANCE, 32);
        //// Lateral direction
-       public static final FlightDataType TYPE_POSITION_DIRECTION = newType(trans.get("FlightDataType.TYPE_POSITION_DIRECTION"), UnitGroup.UNITS_ANGLE, 33);
+       public static final FlightDataType TYPE_POSITION_DIRECTION = newType(trans.get("FlightDataType.TYPE_POSITION_DIRECTION"), "\u03b8l", UnitGroup.UNITS_ANGLE, 33);
        //// Lateral velocity
-       public static final FlightDataType TYPE_VELOCITY_XY = newType(trans.get("FlightDataType.TYPE_VELOCITY_XY"), UnitGroup.UNITS_VELOCITY, 34);
+       public static final FlightDataType TYPE_VELOCITY_XY = newType(trans.get("FlightDataType.TYPE_VELOCITY_XY"), "Vl", UnitGroup.UNITS_VELOCITY, 34);
        //// Lateral acceleration
-       public static final FlightDataType TYPE_ACCELERATION_XY = newType(trans.get("FlightDataType.TYPE_ACCELERATION_XY"), UnitGroup.UNITS_ACCELERATION, 35);
+       public static final FlightDataType TYPE_ACCELERATION_XY = newType(trans.get("FlightDataType.TYPE_ACCELERATION_XY"), "Al", UnitGroup.UNITS_ACCELERATION, 35);
        //// Latitude
-       public static final FlightDataType TYPE_LATITUDE = newType(trans.get("FlightDataType.TYPE_LATITUDE"), UnitGroup.UNITS_ANGLE, 36);
+       public static final FlightDataType TYPE_LATITUDE = newType(trans.get("FlightDataType.TYPE_LATITUDE"), "\u03c6", UnitGroup.UNITS_ANGLE, 36);
        //// Longitude
-       public static final FlightDataType TYPE_LONGITUDE = newType(trans.get("FlightDataType.TYPE_LONGITUDE"), UnitGroup.UNITS_ANGLE, 37);
+       public static final FlightDataType TYPE_LONGITUDE = newType(trans.get("FlightDataType.TYPE_LONGITUDE"), "\u03bb", UnitGroup.UNITS_ANGLE, 37);
+       
+       //// Gravity
+       public static final FlightDataType TYPE_GRAVITY = newType(trans.get("FlightDataType.TYPE_GRAVITY"), "g", UnitGroup.UNITS_ACCELERATION, 38);
        
        //// Angular motion
        //// Angle of attack
-       public static final FlightDataType TYPE_AOA = newType(trans.get("FlightDataType.TYPE_AOA"), UnitGroup.UNITS_ANGLE, 40);
+       public static final FlightDataType TYPE_AOA = newType(trans.get("FlightDataType.TYPE_AOA"), "\u03b1", UnitGroup.UNITS_ANGLE, 40);
        //// Roll rate
-       public static final FlightDataType TYPE_ROLL_RATE = newType(trans.get("FlightDataType.TYPE_ROLL_RATE"), UnitGroup.UNITS_ROLL, 41);
+       public static final FlightDataType TYPE_ROLL_RATE = newType(trans.get("FlightDataType.TYPE_ROLL_RATE"), "d\u03a6", UnitGroup.UNITS_ROLL, 41);
        //// Pitch rate
-       public static final FlightDataType TYPE_PITCH_RATE = newType(trans.get("FlightDataType.TYPE_PITCH_RATE"), UnitGroup.UNITS_ROLL, 42);
+       public static final FlightDataType TYPE_PITCH_RATE = newType(trans.get("FlightDataType.TYPE_PITCH_RATE"), "d\u03b8", UnitGroup.UNITS_ROLL, 42);
        //// Yaw rate
-       public static final FlightDataType TYPE_YAW_RATE = newType(trans.get("FlightDataType.TYPE_YAW_RATE"), UnitGroup.UNITS_ROLL, 43);
+       public static final FlightDataType TYPE_YAW_RATE = newType(trans.get("FlightDataType.TYPE_YAW_RATE"), "d\u03a8", UnitGroup.UNITS_ROLL, 43);
+       
        
-
        //// Stability information
        //// Mass
-       public static final FlightDataType TYPE_MASS = newType(trans.get("FlightDataType.TYPE_MASS"), UnitGroup.UNITS_MASS, 50);
+       public static final FlightDataType TYPE_MASS = newType(trans.get("FlightDataType.TYPE_MASS"), "m", UnitGroup.UNITS_MASS, 50);
+       //// Propellant mass
+       public static final FlightDataType TYPE_PROPELLANT_MASS = newType(trans.get("FlightDataType.TYPE_PROPELLANT_MASS"), "mp", UnitGroup.UNITS_MASS, 51);
        //// Longitudinal moment of inertia
-       public static final FlightDataType TYPE_LONGITUDINAL_INERTIA = newType(trans.get("FlightDataType.TYPE_LONGITUDINAL_INERTIA"), UnitGroup.UNITS_INERTIA, 51);
+       public static final FlightDataType TYPE_LONGITUDINAL_INERTIA = newType(trans.get("FlightDataType.TYPE_LONGITUDINAL_INERTIA"), "Il", UnitGroup.UNITS_INERTIA, 52);
        //// Rotational moment of inertia
-       public static final FlightDataType TYPE_ROTATIONAL_INERTIA = newType(trans.get("FlightDataType.TYPE_ROTATIONAL_INERTIA"), UnitGroup.UNITS_INERTIA, 52);
+       public static final FlightDataType TYPE_ROTATIONAL_INERTIA = newType(trans.get("FlightDataType.TYPE_ROTATIONAL_INERTIA"), "Ir", UnitGroup.UNITS_INERTIA, 53);
        //// CP location
-       public static final FlightDataType TYPE_CP_LOCATION = newType(trans.get("FlightDataType.TYPE_CP_LOCATION"), UnitGroup.UNITS_LENGTH, 53);
+       public static final FlightDataType TYPE_CP_LOCATION = newType(trans.get("FlightDataType.TYPE_CP_LOCATION"), "Cp", UnitGroup.UNITS_LENGTH, 54);
        //// CG location
-       public static final FlightDataType TYPE_CG_LOCATION = newType(trans.get("FlightDataType.TYPE_CG_LOCATION"), UnitGroup.UNITS_LENGTH, 54);
+       public static final FlightDataType TYPE_CG_LOCATION = newType(trans.get("FlightDataType.TYPE_CG_LOCATION"), "Cg", UnitGroup.UNITS_LENGTH, 55);
        //// Stability margin calibers
-       public static final FlightDataType TYPE_STABILITY = newType(trans.get("FlightDataType.TYPE_STABILITY"), UnitGroup.UNITS_COEFFICIENT, 55);
+       public static final FlightDataType TYPE_STABILITY = newType(trans.get("FlightDataType.TYPE_STABILITY"), "S", UnitGroup.UNITS_COEFFICIENT, 56);
+       
        
-
        //// Characteristic numbers
        //// Mach number
-       public static final FlightDataType TYPE_MACH_NUMBER = newType(trans.get("FlightDataType.TYPE_MACH_NUMBER"), UnitGroup.UNITS_COEFFICIENT, 60);
+       public static final FlightDataType TYPE_MACH_NUMBER = newType(trans.get("FlightDataType.TYPE_MACH_NUMBER"), "M", UnitGroup.UNITS_COEFFICIENT, 60);
        //// Reynolds number
-       public static final FlightDataType TYPE_REYNOLDS_NUMBER = newType(trans.get("FlightDataType.TYPE_REYNOLDS_NUMBER"), UnitGroup.UNITS_COEFFICIENT, 61);
+       public static final FlightDataType TYPE_REYNOLDS_NUMBER = newType(trans.get("FlightDataType.TYPE_REYNOLDS_NUMBER"), "R", UnitGroup.UNITS_COEFFICIENT, 61);
+       
        
-
        //// Thrust and drag
        //// Thrust
-       public static final FlightDataType TYPE_THRUST_FORCE = newType(trans.get("FlightDataType.TYPE_THRUST_FORCE"), UnitGroup.UNITS_FORCE, 70);
+       public static final FlightDataType TYPE_THRUST_FORCE = newType(trans.get("FlightDataType.TYPE_THRUST_FORCE"), "Ft", UnitGroup.UNITS_FORCE, 70);
        //// Drag force
-       public static final FlightDataType TYPE_DRAG_FORCE = newType(trans.get("FlightDataType.TYPE_DRAG_FORCE"), UnitGroup.UNITS_FORCE, 71);
+       public static final FlightDataType TYPE_DRAG_FORCE = newType(trans.get("FlightDataType.TYPE_DRAG_FORCE"), "Fd", UnitGroup.UNITS_FORCE, 71);
        //// Drag coefficient
-       public static final FlightDataType TYPE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 72);
+       public static final FlightDataType TYPE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_DRAG_COEFF"), "Cd", UnitGroup.UNITS_COEFFICIENT, 72);
        //// Axial drag coefficient
-       public static final FlightDataType TYPE_AXIAL_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_AXIAL_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 73);
+       public static final FlightDataType TYPE_AXIAL_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_AXIAL_DRAG_COEFF"), "Cda", UnitGroup.UNITS_COEFFICIENT, 73);
+       
        
-
        ////  Component drag coefficients
        //// Friction drag coefficient
-       public static final FlightDataType TYPE_FRICTION_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_FRICTION_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 80);
+       public static final FlightDataType TYPE_FRICTION_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_FRICTION_DRAG_COEFF"), "Cdf", UnitGroup.UNITS_COEFFICIENT, 80);
        //// Pressure drag coefficient
-       public static final FlightDataType TYPE_PRESSURE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_PRESSURE_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 81);
+       public static final FlightDataType TYPE_PRESSURE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_PRESSURE_DRAG_COEFF"), "Cdp", UnitGroup.UNITS_COEFFICIENT, 81);
        //// Base drag coefficient
-       public static final FlightDataType TYPE_BASE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_BASE_DRAG_COEFF"), UnitGroup.UNITS_COEFFICIENT, 82);
+       public static final FlightDataType TYPE_BASE_DRAG_COEFF = newType(trans.get("FlightDataType.TYPE_BASE_DRAG_COEFF"), "Cdb", UnitGroup.UNITS_COEFFICIENT, 82);
+       
        
-
        ////  Other coefficients
        //// Normal force coefficient
-       public static final FlightDataType TYPE_NORMAL_FORCE_COEFF = newType(trans.get("FlightDataType.TYPE_NORMAL_FORCE_COEFF"), UnitGroup.UNITS_COEFFICIENT, 90);
+       public static final FlightDataType TYPE_NORMAL_FORCE_COEFF = newType(trans.get("FlightDataType.TYPE_NORMAL_FORCE_COEFF"), "Cn", UnitGroup.UNITS_COEFFICIENT, 90);
        //// Pitch moment coefficient
-       public static final FlightDataType TYPE_PITCH_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_PITCH_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 91);
+       public static final FlightDataType TYPE_PITCH_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_PITCH_MOMENT_COEFF"), "C\u03b8", UnitGroup.UNITS_COEFFICIENT, 91);
        //// Yaw moment coefficient
-       public static final FlightDataType TYPE_YAW_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_YAW_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 92);
+       public static final FlightDataType TYPE_YAW_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_YAW_MOMENT_COEFF"), "C\u03c4\u03a8", UnitGroup.UNITS_COEFFICIENT, 92);
        //// Side force coefficient
-       public static final FlightDataType TYPE_SIDE_FORCE_COEFF = newType(trans.get("FlightDataType.TYPE_SIDE_FORCE_COEFF"), UnitGroup.UNITS_COEFFICIENT, 93);
+       public static final FlightDataType TYPE_SIDE_FORCE_COEFF = newType(trans.get("FlightDataType.TYPE_SIDE_FORCE_COEFF"), "C\u03c4s", UnitGroup.UNITS_COEFFICIENT, 93);
        //// Roll moment coefficient
-       public static final FlightDataType TYPE_ROLL_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 94);
+       public static final FlightDataType TYPE_ROLL_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_MOMENT_COEFF"), "C\u03c4\u03a6", UnitGroup.UNITS_COEFFICIENT, 94);
        //// Roll forcing coefficient
-       public static final FlightDataType TYPE_ROLL_FORCING_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_FORCING_COEFF"), UnitGroup.UNITS_COEFFICIENT, 95);
+       public static final FlightDataType TYPE_ROLL_FORCING_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_FORCING_COEFF"), "Cf\u03a6", UnitGroup.UNITS_COEFFICIENT, 95);
        //// Roll damping coefficient
-       public static final FlightDataType TYPE_ROLL_DAMPING_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_DAMPING_COEFF"), UnitGroup.UNITS_COEFFICIENT, 96);
+       public static final FlightDataType TYPE_ROLL_DAMPING_COEFF = newType(trans.get("FlightDataType.TYPE_ROLL_DAMPING_COEFF"), "C\u03b6\u03a6", UnitGroup.UNITS_COEFFICIENT, 96);
        
        //// Pitch damping coefficient
-       public static final FlightDataType TYPE_PITCH_DAMPING_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 97);
+       public static final FlightDataType TYPE_PITCH_DAMPING_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_PITCH_DAMPING_MOMENT_COEFF"), "C\u03b6\u03b8", UnitGroup.UNITS_COEFFICIENT, 97);
        //// Yaw damping coefficient
-       public static final FlightDataType TYPE_YAW_DAMPING_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF"), UnitGroup.UNITS_COEFFICIENT, 98);
+       public static final FlightDataType TYPE_YAW_DAMPING_MOMENT_COEFF = newType(trans.get("FlightDataType.TYPE_YAW_DAMPING_MOMENT_COEFF"), "C\u03b6\u03a8", UnitGroup.UNITS_COEFFICIENT, 98);
        
        //// Coriolis acceleration
-       public static final FlightDataType TYPE_CORIOLIS_ACCELERATION = newType(trans.get("FlightDataType.TYPE_CORIOLIS_ACCELERATION"), UnitGroup.UNITS_ACCELERATION, 99);
+       public static final FlightDataType TYPE_CORIOLIS_ACCELERATION = newType(trans.get("FlightDataType.TYPE_CORIOLIS_ACCELERATION"), "Ac", UnitGroup.UNITS_ACCELERATION, 99);
+       
        
-
        ////  Reference length + area
        //// Reference length
-       public static final FlightDataType TYPE_REFERENCE_LENGTH = newType(trans.get("FlightDataType.TYPE_REFERENCE_LENGTH"), UnitGroup.UNITS_LENGTH, 100);
+       public static final FlightDataType TYPE_REFERENCE_LENGTH = newType(trans.get("FlightDataType.TYPE_REFERENCE_LENGTH"), "Lr", UnitGroup.UNITS_LENGTH, 100);
        //// Reference area
-       public static final FlightDataType TYPE_REFERENCE_AREA = newType(trans.get("FlightDataType.TYPE_REFERENCE_AREA"), UnitGroup.UNITS_AREA, 101);
+       public static final FlightDataType TYPE_REFERENCE_AREA = newType(trans.get("FlightDataType.TYPE_REFERENCE_AREA"), "Ar", UnitGroup.UNITS_AREA, 101);
+       
        
-
        ////  Orientation
        //// Vertical orientation (zenith)
-       public static final FlightDataType TYPE_ORIENTATION_THETA = newType(trans.get("FlightDataType.TYPE_ORIENTATION_THETA"), UnitGroup.UNITS_ANGLE, 106);
+       public static final FlightDataType TYPE_ORIENTATION_THETA = newType(trans.get("FlightDataType.TYPE_ORIENTATION_THETA"), "\u0398", UnitGroup.UNITS_ANGLE, 106);
        //// Lateral orientation (azimuth)
-       public static final FlightDataType TYPE_ORIENTATION_PHI = newType(trans.get("FlightDataType.TYPE_ORIENTATION_PHI"), UnitGroup.UNITS_ANGLE, 107);
+       public static final FlightDataType TYPE_ORIENTATION_PHI = newType(trans.get("FlightDataType.TYPE_ORIENTATION_PHI"), "\u03a6", UnitGroup.UNITS_ANGLE, 107);
+       
        
-
        ////  Atmospheric conditions
        //// Wind velocity
-       public static final FlightDataType TYPE_WIND_VELOCITY = newType(trans.get("FlightDataType.TYPE_WIND_VELOCITY"), UnitGroup.UNITS_VELOCITY, 110);
+       public static final FlightDataType TYPE_WIND_VELOCITY = newType(trans.get("FlightDataType.TYPE_WIND_VELOCITY"), "Vw", UnitGroup.UNITS_VELOCITY, 110);
        //// Air temperature
-       public static final FlightDataType TYPE_AIR_TEMPERATURE = newType(trans.get("FlightDataType.TYPE_AIR_TEMPERATURE"), UnitGroup.UNITS_TEMPERATURE, 111);
+       public static final FlightDataType TYPE_AIR_TEMPERATURE = newType(trans.get("FlightDataType.TYPE_AIR_TEMPERATURE"), "T", UnitGroup.UNITS_TEMPERATURE, 111);
        //// Air pressure
-       public static final FlightDataType TYPE_AIR_PRESSURE = newType(trans.get("FlightDataType.TYPE_AIR_PRESSURE"), UnitGroup.UNITS_PRESSURE, 112);
+       public static final FlightDataType TYPE_AIR_PRESSURE = newType(trans.get("FlightDataType.TYPE_AIR_PRESSURE"), "P", UnitGroup.UNITS_PRESSURE, 112);
        //// Speed of sound
-       public static final FlightDataType TYPE_SPEED_OF_SOUND = newType(trans.get("FlightDataType.TYPE_SPEED_OF_SOUND"), UnitGroup.UNITS_VELOCITY, 113);
+       public static final FlightDataType TYPE_SPEED_OF_SOUND = newType(trans.get("FlightDataType.TYPE_SPEED_OF_SOUND"), "Vs", UnitGroup.UNITS_VELOCITY, 113);
        
        ////  Simulation information
        //// Simulation time step
-       public static final FlightDataType TYPE_TIME_STEP = newType(trans.get("FlightDataType.TYPE_TIME_STEP"), UnitGroup.UNITS_TIME_STEP, 200);
+       public static final FlightDataType TYPE_TIME_STEP = newType(trans.get("FlightDataType.TYPE_TIME_STEP"), "dt", UnitGroup.UNITS_TIME_STEP, 200);
        //// Computation time
-       public static final FlightDataType TYPE_COMPUTATION_TIME = newType(trans.get("FlightDataType.TYPE_COMPUTATION_TIME"), UnitGroup.UNITS_SHORT_TIME, 201);
-       
+       public static final FlightDataType TYPE_COMPUTATION_TIME = newType(trans.get("FlightDataType.TYPE_COMPUTATION_TIME"), "tc", UnitGroup.UNITS_SHORT_TIME, 201);   
+       
+       // An array of all the built in types
+       public static final FlightDataType[] ALL_TYPES = { 
+               TYPE_TIME,
+               TYPE_ALTITUDE ,
+               TYPE_VELOCITY_Z ,
+               TYPE_ACCELERATION_Z, 
+               TYPE_VELOCITY_TOTAL, 
+               TYPE_ACCELERATION_TOTAL, 
+               TYPE_POSITION_X, 
+               TYPE_POSITION_Y,  
+               TYPE_POSITION_XY, 
+               TYPE_POSITION_DIRECTION, 
+               TYPE_VELOCITY_XY, 
+               TYPE_ACCELERATION_XY, 
+               TYPE_LATITUDE, 
+               TYPE_LONGITUDE,
+               TYPE_GRAVITY,
+               TYPE_AOA,
+               TYPE_ROLL_RATE,
+               TYPE_PITCH_RATE,
+               TYPE_YAW_RATE,
+               TYPE_MASS,
+               TYPE_PROPELLANT_MASS,
+               TYPE_LONGITUDINAL_INERTIA,
+               TYPE_ROTATIONAL_INERTIA,
+               TYPE_CP_LOCATION,
+               TYPE_CG_LOCATION,
+               TYPE_STABILITY,
+               TYPE_MACH_NUMBER,
+               TYPE_REYNOLDS_NUMBER,
+               TYPE_THRUST_FORCE,
+               TYPE_DRAG_FORCE,
+               TYPE_DRAG_COEFF,
+               TYPE_AXIAL_DRAG_COEFF,
+               TYPE_FRICTION_DRAG_COEFF,
+               TYPE_PRESSURE_DRAG_COEFF,
+               TYPE_BASE_DRAG_COEFF,
+               TYPE_NORMAL_FORCE_COEFF,
+               TYPE_PITCH_MOMENT_COEFF,
+               TYPE_YAW_MOMENT_COEFF,
+               TYPE_SIDE_FORCE_COEFF,
+               TYPE_ROLL_MOMENT_COEFF,
+               TYPE_ROLL_FORCING_COEFF,
+               TYPE_ROLL_DAMPING_COEFF,
+               TYPE_PITCH_DAMPING_MOMENT_COEFF,
+               TYPE_YAW_DAMPING_MOMENT_COEFF,
+               TYPE_CORIOLIS_ACCELERATION,
+               TYPE_REFERENCE_LENGTH,
+               TYPE_REFERENCE_AREA,
+               TYPE_ORIENTATION_THETA,
+               TYPE_ORIENTATION_PHI,
+               TYPE_WIND_VELOCITY,
+               TYPE_AIR_TEMPERATURE,
+               TYPE_AIR_PRESSURE,
+               TYPE_SPEED_OF_SOUND,
+               TYPE_TIME_STEP,
+               TYPE_COMPUTATION_TIME
+               };
        
-
        /**
-        * Return a {@link FlightDataType} based on a string description.  This returns known data types
-        * if possible, or a new type otherwise.
+        * Return a {@link FlightDataType} with a given string description, symbol and unitgroup.
+        * This returns an existing data type if the symbol matches that of an existing type. 
+        * 
+        * If the symbol matches but the unit and description information differ, then the old stored datatype
+        * is erased and the updated version based on the given parametes is returned.
+        * The only exception is if the description or unitgroup are undefined (null or empty string). In this case 
+        * we just get these parameters from the existing type when making the new one.
         * 
         * @param s             the string description of the type.
         * @param u             the unit group the new type should belong to if a new group is created.
         * @return              a data type.
         */
-       public static synchronized FlightDataType getType(String s, UnitGroup u) {
-               FlightDataType type = EXISTING_TYPES.get(s.toLowerCase());
+       @SuppressWarnings("null")
+       public static synchronized FlightDataType getType(String s, String symbol, UnitGroup u) {
+
+               // if symbol is null : try finding by name
+               // if unit is null : don't do anything to the unit if found, just return datatype if found and generate an error and an empty unit otherwise
+               int oldPriority = DEFAULT_PRIORITY;
+               
+               //FlightDataType type = findFromSymbol(symbol);
+               FlightDataType type = EXISTING_TYPES.get(symbol);
+               
                if (type != null) {
-                       return type;
+                       // found it from symbol
+                       
+                       // if name was not given (empty string), can use the one we found
+                       if ( s == null || s.isEmpty()){
+                               s = type.getName();
+                       }
+                       if ( u == null ){
+                               u = type.getUnitGroup();
+                       }
+                       
+                       // if something has changed, then we need to remove the old one
+                       // otherwise, just return what we found
+                       if ( !u.equals(type.getUnitGroup()) )
+                          {
+                               oldPriority = type.priority;
+                               EXISTING_TYPES.remove(type);
+                               log.info("Unitgroup of type "+type.getName() + 
+                                                ", has changed from "+type.getUnitGroup().toString() + 
+                                                " to "+u.toString() +
+                                                ". Removing old version.");
+                       }
+                       else if (!s.equals(type.getName())) {
+                               oldPriority = type.priority;
+                               EXISTING_TYPES.remove(type);
+                               log.info("Name of type "+type.getName()+", has changed to "+s+". Removing old version.");
+                       }
+                       else{
+                               return type;
+                       }
                }
-               type = newType(s, u, DEFAULT_PRIORITY);
-               return type;
+               
+               if (u == null){
+                       u = UnitGroup.UNITS_NONE;
+                       log.error("Made a new flightdatatype, but did not know what units to use.");
+               }
+               
+               // make a new one
+               type = newType(s, symbol, u, oldPriority);
+               return type;    
        }
        
+       /*
+        * Get the flightdatatype from existing types based on the symbol.
+        */
+       /*
+       private static FlightDataType findFromSymbol(String symbol){
+               for (FlightDataType t : EXISTING_TYPES.values()){
+                       if (t.getSymbol().equals(symbol)){
+                               return t;
+                       }
+               }
+               return null;
+       }
+       */
+       
        /**
         * Used while initializing the class.
         */
-       private static synchronized FlightDataType newType(String s, UnitGroup u, int priority) {
-               FlightDataType type = new FlightDataType(s, u, priority);
-               EXISTING_TYPES.put(s.toLowerCase(), type);
+       private static synchronized FlightDataType newType(String s, String symbol, UnitGroup u, int priority) {
+               FlightDataType type = new FlightDataType(s, symbol, u, priority);
+               //EXISTING_TYPES.put(s.toLowerCase(Locale.ENGLISH), type);
+               EXISTING_TYPES.put(symbol, type);
                return type;
        }
        
        
        private final String name;
+       private final String symbol;
        private final UnitGroup units;
        private final int priority;
        private final int hashCode;
        
        
-       private FlightDataType(String typeName, UnitGroup units, int priority) {
+       private FlightDataType(String typeName, String symbol, UnitGroup units, int priority) {
                if (typeName == null)
                        throw new IllegalArgumentException("typeName is null");
                if (units == null)
                        throw new IllegalArgumentException("units is null");
                this.name = typeName;
+               this.symbol = symbol;
                this.units = units;
                this.priority = priority;
-               this.hashCode = this.name.toLowerCase().hashCode();
+               this.hashCode = this.name.toLowerCase(Locale.ENGLISH).hashCode();
        }
        
+       /*
+       public void setPriority(int p){
+               this.priority = p;
+       }
+       */
        
-
-
        public String getName() {
                return name;
        }
        
+       public String getSymbol(){
+               return symbol;
+       }
+       
        public UnitGroup getUnitGroup() {
                return units;
        }
        
        @Override
        public String toString() {
-               return name;
+               return name; //+" ("+symbol+") "+units.getDefaultUnit().toString();
        }
        
        @Override
index 1d910df0a751f0a0e1edfe84f8647002c4697115..74386364d3ffc07369dc7f0bd7493afae5c9cff4 100644 (file)
@@ -13,15 +13,17 @@ public class MassData {
        private final Coordinate cg;
        private final double longitudinalInertia;
        private final double rotationalInertia;
+       private final double propellantMass;
        
        
-       public MassData(Coordinate cg, double longitudinalInertia, double rotationalInertia) {
+       public MassData(Coordinate cg, double longitudinalInertia, double rotationalInertia, double propellantMass) {
                if (cg == null) {
                        throw new IllegalArgumentException("cg is null");
                }
                this.cg = cg;
                this.longitudinalInertia = longitudinalInertia;
                this.rotationalInertia = rotationalInertia;
+               this.propellantMass = propellantMass;
        }
 
        
@@ -39,6 +41,9 @@ public class MassData {
                return rotationalInertia;
        }
 
+       public double getPropellantMass() {
+               return propellantMass;
+       }
        
        
        @Override
@@ -50,20 +55,20 @@ public class MassData {
                
                MassData other = (MassData) obj;
                return (this.cg.equals(other.cg) && MathUtil.equals(this.longitudinalInertia, other.longitudinalInertia) &&
-                               MathUtil.equals(this.rotationalInertia, other.rotationalInertia));
+                               MathUtil.equals(this.rotationalInertia, other.rotationalInertia)) && MathUtil.equals(this.propellantMass, other.propellantMass) ;
        }
 
        
        @Override
        public int hashCode() {
-               return (int) (cg.hashCode() ^ Double.doubleToLongBits(longitudinalInertia) ^ Double.doubleToLongBits(rotationalInertia));
+               return (int) (cg.hashCode() ^ Double.doubleToLongBits(longitudinalInertia) ^ Double.doubleToLongBits(rotationalInertia) ^ Double.doubleToLongBits(propellantMass) );
        }
 
 
        @Override
        public String toString() {
                return "MassData [cg=" + cg + ", longitudinalInertia=" + longitudinalInertia
-                               + ", rotationalInertia=" + rotationalInertia + "]";
+                               + ", rotationalInertia=" + rotationalInertia + ", propellantMass="+propellantMass + "]";
        }
        
 }
index 6b7aad9d8312adcb7170f5556ab46ce5d9577357..8548ec91ef5feb6f34e31dfce524a59108f1592f 100644 (file)
@@ -605,12 +605,14 @@ public class RK4SimulationStepper extends AbstractSimulationStepper {
                }
                if (store.massData != null) {
                        data.setValue(FlightDataType.TYPE_MASS, store.massData.getCG().weight);
+                       data.setValue(FlightDataType.TYPE_PROPELLANT_MASS, store.massData.getPropellantMass());
                        data.setValue(FlightDataType.TYPE_LONGITUDINAL_INERTIA, store.massData.getLongitudinalInertia());
                        data.setValue(FlightDataType.TYPE_ROTATIONAL_INERTIA, store.massData.getRotationalInertia());
                }
                
                data.setValue(FlightDataType.TYPE_THRUST_FORCE, store.thrustForce);
                data.setValue(FlightDataType.TYPE_DRAG_FORCE, store.dragForce);
+               data.setValue(FlightDataType.TYPE_GRAVITY, store.gravity);
                
                if (status.isLaunchRodCleared() && store.forces != null) {
                        if (store.massData != null && store.flightConditions != null) {
index f2412717a34a55bcfe6200c1a924eecd09829267..ffd9e003a6593a37621cc96b66520796267b57fb 100644 (file)
@@ -4,6 +4,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
+import net.sf.openrocket.document.Simulation;
 import net.sf.openrocket.masscalc.MassCalculator;
 import net.sf.openrocket.models.atmosphere.AtmosphericModel;
 import net.sf.openrocket.models.gravity.GravityModel;
@@ -27,6 +28,7 @@ public class SimulationConditions implements Monitorable, Cloneable {
        private Rocket rocket;
        private String motorID = null;
        
+       private Simulation simulation; // The parent simulation 
 
        private double launchRodLength = 1;
        
@@ -262,9 +264,14 @@ public class SimulationConditions implements Monitorable, Cloneable {
                this.modID++;
        }
        
-       
-
+       public void setSimulation(Simulation sim) {
+               this.simulation = sim;
+       }
 
+       public Simulation getSimulation(){
+               return this.simulation;
+       }
+       
        // TODO: HIGH: Make cleaner
        public List<SimulationListener> getSimulationListenerList() {
                return simulationListeners;
index 7734ec5dac778921b32d17eae70fdc0bbe5dded8..a1b6bae91d22f03fd3827a8d6a751c03875893b9 100644 (file)
@@ -5,8 +5,10 @@ import java.util.EventListener;
 import java.util.EventObject;
 import java.util.List;
 import java.util.Random;
+import java.util.Set;
 
 import net.sf.openrocket.aerodynamics.BarrowmanCalculator;
+import net.sf.openrocket.logging.LogHelper;
 import net.sf.openrocket.masscalc.BasicMassCalculator;
 import net.sf.openrocket.models.atmosphere.AtmosphericModel;
 import net.sf.openrocket.models.atmosphere.ExtendedISAModel;
@@ -14,6 +16,7 @@ import net.sf.openrocket.models.gravity.GravityModel;
 import net.sf.openrocket.models.gravity.WGSGravityModel;
 import net.sf.openrocket.models.wind.PinkNoiseWindModel;
 import net.sf.openrocket.rocketcomponent.Rocket;
+import net.sf.openrocket.startup.Application;
 import net.sf.openrocket.util.BugException;
 import net.sf.openrocket.util.ChangeSource;
 import net.sf.openrocket.util.GeodeticComputationStrategy;
@@ -31,6 +34,8 @@ import net.sf.openrocket.util.WorldCoordinate;
  */
 public class SimulationOptions implements ChangeSource, Cloneable {
        
+       private static final LogHelper log = Application.getLogger();
+       
        public static final double MAX_LAUNCH_ROD_ANGLE = Math.PI / 3;
        
        /**
@@ -93,7 +98,6 @@ public class SimulationOptions implements ChangeSource, Cloneable {
                this.rocket = rocket;
        }
        
-       
        public Rocket getRocket() {
                return rocket;
        }
diff --git a/core/src/net/sf/openrocket/simulation/customexpression/CustomExpression.java b/core/src/net/sf/openrocket/simulation/customexpression/CustomExpression.java
new file mode 100644 (file)
index 0000000..e233def
--- /dev/null
@@ -0,0 +1,528 @@
+package net.sf.openrocket.simulation.customexpression;
+
+import java.util.List;
+import java.util.regex.*;
+
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.unit.FixedUnitGroup;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.ArrayList;
+import de.congrace.exp4j.Calculable;
+import de.congrace.exp4j.ExpressionBuilder;
+import de.congrace.exp4j.UnknownFunctionException;
+import de.congrace.exp4j.UnparsableExpressionException;
+import de.congrace.exp4j.Variable;
+
+/**
+ * Represents a single custom expression
+ * @author Richard Graham
+ *
+ */
+public class CustomExpression implements Cloneable{
+       
+       private static final LogHelper log = Application.getLogger();
+       
+       private OpenRocketDocument doc;
+       private String name, symbol, unit;
+
+       protected String expression;
+       private ExpressionBuilder builder;
+       private List<CustomExpression> subExpressions = new ArrayList<CustomExpression>();
+       
+       public CustomExpression(OpenRocketDocument doc){
+               this.doc = doc;
+               
+               setName("");
+               setSymbol("");
+               setUnit("");
+               setExpression("");
+       }
+       
+       public CustomExpression(OpenRocketDocument doc, 
+                                                       String name, 
+                                                       String symbol, 
+                                                       String unit, 
+                                                       String expression) {
+               this.doc = doc;
+               
+               setName(name);
+               setSymbol(symbol);
+               setUnit(unit);
+               setExpression(expression);
+       }
+       
+       /*
+        * Sets the long name of this expression, e.g. 'Kinetic energy'  
+        */
+       public void setName(String name){
+               this.name = name;
+       }
+       
+       /*
+        * Sets the string for the units of the result of this expression.
+        */
+       public void setUnit(String unit){
+               this.unit = unit;
+       }
+       
+       /*
+        * Sets the symbol string. This is the short, locale independent symbol for this whole expression
+        */
+       public void setSymbol(String symbol){
+               this.symbol = symbol;
+       }
+       
+       /*
+        * Sets the actual expression string for this expression
+        */
+       public void setExpression(String expression){
+               
+               // This is the expression as supplied
+               this.expression = expression;
+               
+               // Replace any indexed variables
+               expression = subTimeIndexes(expression);
+               expression = subTimeRanges(expression);
+               
+               builder = new ExpressionBuilder(expression);
+               for (String n : getAllSymbols()){
+                       builder.withVariable(new Variable(n));
+               }
+               for (CustomExpression exp : this.subExpressions){
+                       builder.withVariable(new Variable(exp.hash()));
+               }
+       
+               builder.withCustomFunctions(Functions.getInstance().getAllFunction());
+               log.info("Built expression "+expression);
+       }
+       
+       /*
+        * Replaces expressions of the form:
+        *   a[x:y]  with a hash and creates an associated RangeExpression from x to y
+        */
+       private String subTimeRanges(String str){
+               
+               Pattern p = Pattern.compile(variableRegex()+"\\[[^\\]]*:.*?\\]");
+               Matcher m = p.matcher(str);
+               
+               // for each match, make a new custom expression (in subExpressions) with a hashed name
+               // and replace the expression and variable in the original expression string with [hash].
+               while (m.find()){
+                       String match = m.group();
+                       
+                       int start = match.indexOf("[");
+                       int end = match.indexOf("]");
+                       int colon = match.indexOf(":");
+                       
+                       String startTime = match.substring(start+1, colon);
+                       String endTime = match.substring(colon+1, end);
+                       String variableType = match.substring(0, start);
+                       
+                       RangeExpression exp = new RangeExpression(doc, startTime, endTime, variableType);
+                       subExpressions.add( exp );
+                       str = str.replace(match, exp.hash());
+               }
+               return str;
+       }
+       
+       /*
+        * Replaces expressions of the form
+        *   a[x]    with a hash and creates an associated IndexExpression with x
+        */
+       private String subTimeIndexes(String str){
+               
+               // find any matches of the time-indexed variable notation, e.g. m[1.2] for mass at 1.2 sec
+               Pattern p = Pattern.compile(variableRegex()+"\\[[^:]*?\\]");
+               Matcher m = p.matcher(str);
+                               
+               // for each match, make a new custom expression (in subExpressions) with a hashed name
+               // and replace the expression and variable in the original expression string with [hash].
+               while (m.find()){
+                       String match = m.group();
+                       // just the index part (in the square brackets) :
+                       String indexText = match.substring(match.indexOf("[")+1, match.length()-1);
+                       // just the flight data type
+                       String typeText = match.substring(0, match.indexOf("[")); 
+                                               
+                       // Do the replacement and add a corresponding new IndexExpression to the list
+                       IndexExpression exp = new IndexExpression(doc, indexText, typeText);
+                       subExpressions.add( exp );
+                       str = str.replace(match, exp.hash());
+               }
+               return str;
+       }
+       
+       /*
+        * Returns a string of the form (t|a| ... ) with all variable symbols available
+        * This is useful for regex evaluation
+        */
+       protected String variableRegex(){
+               String regex = "(";
+               for (String s : getAllSymbols()){
+                       regex = regex + s + "|";
+               }
+               regex = regex.substring(0, regex.length()-1) + ")";
+               return regex;
+       }
+       
+       // get a list of all the names of all the available variables
+       protected ArrayList<String> getAllNames(){
+               ArrayList<String> names = new ArrayList<String>();
+               /*
+               for (FlightDataType type : FlightDataType.ALL_TYPES)
+                       names.add(type.getName());
+
+               if (doc != null){
+                       List<CustomExpression> expressions = doc.getCustomExpressions();
+                       for (CustomExpression exp : expressions ){
+                               if (exp != this)
+                                       names.add(exp.getName());
+                       }
+               }
+               */
+               for (FlightDataType type : doc.getFlightDataTypes()){
+                       String symb = type.getName();
+                       if (name == null) continue;
+                       
+                       if (!name.equals( this.getName() )){
+                               names.add(symb);
+                       }
+               }
+               return names;
+       }
+       
+       // get a list of all the symbols of the available variables ignoring this one
+       protected ArrayList<String> getAllSymbols(){
+               ArrayList<String> symbols = new ArrayList<String>();
+               /*
+               for (FlightDataType type : FlightDataType.ALL_TYPES)
+                       symbols.add(type.getSymbol());
+               
+               if (doc != null){
+                       for (CustomExpression exp : doc.getCustomExpressions() ){
+                               if (exp != this)
+                                       symbols.add(exp.getSymbol());
+                       }
+               }
+               */
+               for (FlightDataType type : doc.getFlightDataTypes()){
+                       String symb = type.getSymbol();                 
+                       if (!symb.equals( this.getSymbol() )){
+                               symbols.add(symb);
+                       }
+               }
+               
+               return symbols;
+       }
+       
+       public boolean checkSymbol(){
+               if ("".equals(symbol.trim()))
+                       return false;
+               
+               // No bad characters
+               for (char c : "0123456789.,()[]{}<>:#@%^&*$ ".toCharArray())
+                       if (symbol.indexOf(c) != -1 )
+                               return false;
+               
+               // No operators (ignoring brackets)
+               for (String s : Functions.AVAILABLE_OPERATORS.keySet()){
+                       if (symbol.equals(s.trim().replaceAll("\\(|\\)|\\]|\\[|:", "")))
+                               return false;
+               }
+               
+               // No already defined symbols
+               ArrayList<String> symbols = getAllSymbols().clone();
+               if (symbols.contains(symbol.trim())){
+                       int index = symbols.indexOf(symbol.trim());
+                       log.user("Symbol "+symbol+" already exists, found "+symbols.get(index));
+                       return false;
+               }
+               
+               return true;
+       }
+       
+       public boolean checkName(){
+               if ("".equals(name.trim()))
+                       return false;
+               
+               // No characters that could mess things up saving etc
+               for (char c : ",()[]{}<>#$".toCharArray())
+                       if (name.indexOf(c) != -1 )
+                               return false;
+               
+               ArrayList<String> names = getAllNames().clone();
+               if (names.contains(name.trim())){
+                       int index = names.indexOf(name.trim());
+                       log.user("Name "+name+" already exists, found "+names.get(index));
+                       return false;
+               }
+               
+               return true;
+       }
+       
+       // Currently no restrictions on unit
+       public boolean checkUnit(){
+               return true;
+       }
+       
+       public boolean checkAll(){
+               return checkUnit() && checkSymbol() && checkName() && checkExpression();
+       }
+       
+       public String getName(){
+               return name;
+       }
+       
+       public String getSymbol(){
+               return symbol;
+       }
+       
+       public String getUnit(){
+               return unit;
+       }
+       
+       public String getExpressionString(){
+               return expression;
+       }
+       
+       /**
+        * Performs a basic check to see if the current expression string is valid
+        * This includes checking for bad characters and balanced brackets and test
+        * building the expression.
+        */
+       public boolean checkExpression(){
+               if ("".equals(expression.trim())){
+                       return false;
+               }
+               
+               int round = 0, square = 0; // count of bracket openings
+               for (char c : expression.toCharArray()){
+                       switch (c) {
+                               case '(' : round++; break;
+                               case ')' : round--; break;
+                               case '[' : square++; break;
+                               case ']' : square--; break;
+                               case ':' : 
+                                       if (square <= 0){
+                                               log.user(": found outside range expression");
+                                               return false;
+                                       }
+                                       else break;
+                               case '#' : return false;
+                               case '$' : return false;
+                               case '=' : return false;
+                       }
+               }
+               if (round != 0 || square != 0) {
+                       log.user("Expression has unballanced brackets");
+                       return false;
+               }
+               
+               
+               //// Define the available variables as empty
+               // The built in data types
+               /*
+               for (FlightDataType type : FlightDataType.ALL_TYPES){
+                       builder.withVariable(new Variable(type.getSymbol()));
+               }
+               
+               for (String symb : getAllSymbols()){
+                       builder.withVariable(new Variable(symb));
+               }
+               */
+               for (FlightDataType type : doc.getFlightDataTypes()){
+                       builder.withVariable(new Variable(type.getSymbol()));
+               }
+               
+               // Try to build
+               try {
+                       builder.build();
+               } catch (Exception e) {
+                       log.user("Custom expression " + this.toString() + " invalid : " + e.toString());
+                       return false;
+               }
+               
+               
+               // Otherwise, all OK
+               return true;
+       }
+       
+       public Double evaluateDouble(SimulationStatus status){
+               double result = evaluate(status).getDoubleValue();
+               if (result == Double.NEGATIVE_INFINITY || result == Double.POSITIVE_INFINITY) result = Double.NaN;
+               return result;
+       }
+       
+       /*
+        * Builds the expression, done automatically during evaluation. Logs any errors. Returns null in case of error.
+        */
+       protected Calculable buildExpression(){
+               return buildExpression(builder);
+       }
+       
+       /*
+        * Builds a specified expression, log any errors and returns null in case of error.
+        */
+       protected Calculable buildExpression(ExpressionBuilder b){
+               Calculable calc = null;
+               try {
+                       calc = b.build();
+               } catch (UnknownFunctionException e1) {
+                       log.user("Unknown function. Could not build custom expression "+this.toString());
+                       return null;
+               } catch (UnparsableExpressionException e1) {
+                       log.user("Unparsable expression. Could not build custom expression "+this.toString()+". "+e1.getMessage());
+                       return null;
+               }
+               
+               return calc;
+       }
+       
+       /*
+        * Evaluate the expression using the last variable values from the simulation status.
+        * Returns NaN on any error.
+        */
+       public Variable evaluate(SimulationStatus status){
+               
+               Calculable calc = buildExpression(builder);
+               if (calc == null){
+                       return new Variable("Unknown");
+               }
+               
+               // Evaluate any sub expressions and set associated variables in the calculable
+               for (CustomExpression expr : this.subExpressions){
+                       calc.setVariable( expr.evaluate(status) );
+               }
+                       
+               // Set all the built-in variables. Strictly we surely won't need all of them
+               // Going through and checking them to include only the ones used *might* give a speedup
+               for (FlightDataType type : status.getFlightData().getTypes()){
+                       double value = status.getFlightData().getLast(type); 
+                       calc.setVariable( new Variable(type.getSymbol(), value ) );
+               }
+               
+               double result = Double.NaN;
+               try{
+                       result = calc.calculate().getDoubleValue();
+               }
+               catch (java.util.EmptyStackException e){
+                       log.user("Unable to calculate expression "+this.expression+" due to empty stack exception");
+               }
+                       
+               return new Variable(name, result);
+       }
+       
+       /*
+        * Returns the new flight data type corresponding to this calculated data
+        * If the unit matches a SI unit string then the datatype will have the corresponding unitgroup.
+        * Otherwise, a fixed unit group will be created
+        */
+       public FlightDataType getType(){
+               
+               
+               UnitGroup ug = UnitGroup.SIUNITS.get(unit); 
+               if ( ug == null ){
+                       log.debug("SI unit not found for "+unit+" in expression "+toString()+". Making a new fixed unit.");
+                       ug = new FixedUnitGroup(unit);
+               }
+               //UnitGroup ug = new FixedUnitGroup(unit);
+               
+               FlightDataType type = FlightDataType.getType(name, symbol, ug);
+               
+               //log.debug(this.getClass().getSimpleName()+" returned type "+type.getName()+" (" + type.getSymbol() + ")" );           
+               
+               return type;
+       }
+       
+       /*
+        * Add this expression to the document if valid and not in document already
+        */
+       public void addToDocument(){
+               // Abort if exact expression already in
+               List<CustomExpression> expressions = doc.getCustomExpressions();
+               if ( !expressions.isEmpty() ) {
+                       // check if expression already exists
+                       if ( expressions.contains(this) ){
+                               log.user("Expression already in document. This unit : "+this.getUnit()+", existing unit : "+expressions.get(0).getUnit());
+                               return;
+                       }
+               }
+                       
+               if (this.checkAll()){
+                       log.user("Custom expression added to rocket document");
+                       doc.addCustomExpression( this );
+               }
+       }
+       
+       /*
+        * Removes this expression from the document, replacing it with a given new expression
+        */
+       public void overwrite(CustomExpression newExpression){
+               if (!doc.getCustomExpressions().contains(this)) 
+                       return;
+               else {
+                       int index = doc.getCustomExpressions().indexOf(this);
+                       doc.getCustomExpressions().set(index, newExpression);
+               }
+       }
+       
+       @Override
+       public String toString(){
+               return "[Expression name="+this.name.toString()+ " expression=" + this.expression+" unit="+this.unit+"]";
+       }
+       
+       @Override
+       /*
+        * Clone method makes a deep copy of everything except the reference to the document.
+        * If you want to apply this to another simulation, set simulation manually after cloning.
+        * @see java.lang.Object#clone()
+        */
+       public Object clone() {
+             try {
+                 return super.clone();
+             }
+             catch( CloneNotSupportedException e )
+             {
+                 return new CustomExpression(  doc  , 
+                               new String(this.getName()), 
+                               new String(this.getSymbol()),
+                               new String(this.getUnit()),
+                               new String(this.getExpressionString()));
+             }
+       } 
+       
+       /*
+        * Returns a simple all upper case string hash code with a proceeding $ mark.
+        * Used for temporary substitution when evaluating index and range expressions.
+        */
+       public String hash(){
+               Integer hashint = new Integer(this.getExpressionString().hashCode() + symbol.hashCode());
+               String hash = "$";
+               for (char c : hashint.toString().toCharArray()){
+                       if (c == '-') c = '0';
+                       char newc = (char) (c + 17);
+                       hash = hash + newc;
+               }
+               return hash;
+       }
+       
+       @Override
+       public boolean equals(Object obj){
+               CustomExpression other = (CustomExpression) obj;
+               
+               return ( this.getName().equals( other.getName() ) && 
+                                this.getSymbol().equals( other.getSymbol() ) &&
+                                this.getExpressionString().equals( other.getExpressionString() ) &&
+                                this.getUnit().equals( other.getUnit() )
+                               );
+       }
+
+       @Override
+       public int hashCode() {
+               return hash().hashCode();
+       }
+}
diff --git a/core/src/net/sf/openrocket/simulation/customexpression/CustomExpressionSimulationListener.java b/core/src/net/sf/openrocket/simulation/customexpression/CustomExpressionSimulationListener.java
new file mode 100644 (file)
index 0000000..243f7b1
--- /dev/null
@@ -0,0 +1,44 @@
+package net.sf.openrocket.simulation.customexpression;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.simulation.FlightDataBranch;
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.simulation.exception.SimulationException;
+import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
+import net.sf.openrocket.startup.Application;
+
+public class CustomExpressionSimulationListener extends        AbstractSimulationListener {
+
+       private static final LogHelper log = Application.getLogger();
+       private final List<CustomExpression> expressions;
+       
+       public CustomExpressionSimulationListener(List<CustomExpression> expressions) {
+               super();
+               this.expressions = expressions;
+       }
+
+       @Override
+       public void postStep(SimulationStatus status) throws SimulationException {
+               if ( expressions == null || expressions.size() == 0 ) {
+                       return;
+               }
+               // Calculate values for custom expressions
+               FlightDataBranch data = status.getFlightData();
+               for (CustomExpression expression : expressions ) {
+                       double value = expression.evaluateDouble(status);
+                       //log.debug("Setting value of custom expression "+expression.toString()+" = "+value);
+                       data.setValue(expression.getType(), value);
+               }
+               
+
+       }
+
+       @Override
+       public boolean isSystemListener(){
+               return true;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/simulation/customexpression/Functions.java b/core/src/net/sf/openrocket/simulation/customexpression/Functions.java
new file mode 100644 (file)
index 0000000..6e638d9
--- /dev/null
@@ -0,0 +1,269 @@
+package net.sf.openrocket.simulation.customexpression;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import net.sf.openrocket.l10n.Translator;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.ArrayUtils;
+
+import de.congrace.exp4j.CustomFunction;
+import de.congrace.exp4j.InvalidCustomFunctionException;
+import de.congrace.exp4j.Variable;
+
+/*
+ * This is a singleton class which contains all the functions for custom expressions not provided by exp4j
+ */
+public class Functions {
+       private static Functions instance = null;
+       
+       private static final LogHelper log = Application.getLogger();
+       private static final Translator trans = Application.getTranslator();
+       
+       private List<CustomFunction> allFunctions = new ArrayList<CustomFunction>();
+
+       public static Functions getInstance() {
+               if(instance == null) {
+                       try {
+                               instance = new Functions();
+                       } catch (InvalidCustomFunctionException e) {
+                               log.error("Invalid custom function.");
+                       }
+               }
+               return instance;
+       }
+       
+       public List<CustomFunction> getAllFunction(){
+               return allFunctions;
+       }
+       
+       // A map of available operator strings (keys) and description of function (value)
+       public static final SortedMap<String, String> AVAILABLE_OPERATORS = new TreeMap<String, String>() {{
+           put("+"             , trans.get("Operator.plus"));
+           put("-"                     , trans.get("Operator.minus"));
+           put("*"                     , trans.get("Operator.star"));
+           put("/"                     , trans.get("Operator.div"));
+           put("%"                     , trans.get("Operator.mod"));
+           put("^"                     , trans.get("Operator.pow"));
+           put("abs()"         , trans.get("Operator.abs"));
+           put("ceil()"        , trans.get("Operator.ceil"));
+           put("floor()"       , trans.get("Operator.floor"));
+           put("sqrt()"        , trans.get("Operator.sqrt"));
+           put("cbrt()"        , trans.get("Operator.cbrt"));
+           put("exp()"         , trans.get("Operator.exp"));
+           put("log()"         , trans.get("Operator.ln"));
+           put("sin()"         , trans.get("Operator.sin"));
+           put("cos()"         , trans.get("Operator.cos"));
+           put("tan()"         , trans.get("Operator.tan"));
+           put("asin()"        , trans.get("Operator.asin"));
+           put("acos()"        , trans.get("Operator.acos"));
+           put("atan()"        , trans.get("Operator.atan"));
+           put("sinh()"        , trans.get("Operator.hsin"));
+           put("cosh()"        , trans.get("Operator.hcos"));
+           put("tanh()"        , trans.get("Operator.htan"));
+           put("log10()"       , trans.get("Operator.log10"));
+           put("round()"       , trans.get("Operator.round"));
+           put("random()"      , trans.get("Operator.random"));
+           put("expm1()"       , trans.get("Operator.expm1"));
+           put("mean([:])"     , trans.get("Operator.mean"));
+           put("min([:])"      , trans.get("Operator.min"));
+           put("max([:])"      , trans.get("Operator.max"));
+           put("var([:])"      , trans.get("Operator.var"));
+           put("rms([:])"      , trans.get("Operator.rms"));
+           put("stdev([:])", trans.get("Operator.stdev"));
+           put("lclip(,)"  , trans.get("Operator.lclip"));
+           put("uclip(,)"  , trans.get("Operator.uclip"));
+           put("binf([:],,)"   , trans.get("Operator.binf"));
+           put("trapz([:])"    , trans.get("Operator.trapz"));
+           put("tnear([:],)"   , trans.get("Operator.tnear"));
+       }}; 
+       
+       
+       protected Functions() throws InvalidCustomFunctionException {
+               
+               CustomFunction meanFn = new CustomFunction("mean") {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                       double[] vals;
+                       try{
+                               vals = vars.get(0).getArrayValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       return new Variable("double MEAN result, ", ArrayUtils.mean(vals));
+                       }       
+               };
+               allFunctions.add(meanFn);
+               
+               CustomFunction minFn = new CustomFunction("min") {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                       double[] vals;
+                       try{
+                               vals = vars.get(0).getArrayValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       return new Variable("double MIN result, ", ArrayUtils.min(vals));
+                       }
+               };
+               allFunctions.add(minFn);
+               
+               CustomFunction maxFn = new CustomFunction("max") {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                       double[] vals;
+                       try{
+                               vals = vars.get(0).getArrayValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       return new Variable("double MAX result, ", ArrayUtils.max(vals));
+                       }
+               };
+               allFunctions.add(maxFn);
+       
+               CustomFunction varFn = new CustomFunction("var") {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                       double[] vals;
+                       try{
+                               vals = vars.get(0).getArrayValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       return new Variable("double VAR result, ", ArrayUtils.variance(vals));
+                       }
+               };
+               allFunctions.add(varFn);
+               
+               CustomFunction stdevFn = new CustomFunction("stdev") {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                       double[] vals;
+                       try{
+                               vals = vars.get(0).getArrayValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       return new Variable("double STDEV result, ", ArrayUtils.stdev(vals));
+                       }
+               };
+               allFunctions.add(stdevFn);
+               
+               CustomFunction rmsFn = new CustomFunction("rms") {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                       double[] vals;
+                       try{
+                               vals = vars.get(0).getArrayValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       return new Variable("double RMS result, ", ArrayUtils.rms(vals));
+                       }
+               };
+               allFunctions.add(rmsFn);
+               
+               CustomFunction lclipFn = new CustomFunction("lclip",2) {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                       double val, clip;
+                       try{
+                               val = vars.get(0).getDoubleValue();
+                               clip = vars.get(1).getDoubleValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       if (val < clip){
+                               val = clip;
+                       }
+                       return new Variable("double LCLIP result, ", val);
+                       }
+               };
+               allFunctions.add(lclipFn);
+               
+               CustomFunction uclipFn = new CustomFunction("uclip",2) {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                               double val, clip;
+                       try{
+                               val = vars.get(0).getDoubleValue();
+                               clip = vars.get(1).getDoubleValue();
+                       } catch (Exception e) {
+                               return new Variable("Invalid");
+                       }
+                       if (val > clip){
+                               val = clip;
+                       }
+                       return new Variable("double UCLIP result, ", val);
+                       }
+               };
+               allFunctions.add(uclipFn);
+               
+               CustomFunction binfFn = new CustomFunction("binf", 3) {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                               double[] range;
+                               double min, max;
+                               try{
+                                       range = vars.get(0).getArrayValue();
+                                       min = vars.get(1).getDoubleValue();
+                                       max = vars.get(2).getDoubleValue();
+                               } catch (Exception e) {
+                                       return new Variable("Invalid");
+                               }
+                               
+                               int ins = 0;
+                               for (double x: range){
+                                       if (x < max && x > min){
+                                               ins++;
+                                       }
+                               }
+                               return new Variable("double BINF result", (double) ins/ (double) range.length);
+                       }
+               };
+               allFunctions.add(binfFn);
+               
+               CustomFunction rombintFn = new CustomFunction("trapz") {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                               double[] range;
+                               double dt = 0;
+                               try{
+                                       range = vars.get(0).getArrayValue();
+                                       dt = vars.get(0).getStep();
+                               } catch (Exception e) {
+                                       return new Variable("Invalid");
+                               }
+                               
+                               return new Variable("double TRAPZ result", ArrayUtils.trapz(range, dt) );
+                       }
+               };
+               allFunctions.add(rombintFn);
+               
+               CustomFunction tnearFn = new CustomFunction("tnear", 2) {
+                       @Override
+                       public Variable applyFunction(List<Variable> vars) {
+                               double[] range;
+                               double dt = 0;
+                               double start = 0;
+                               double near = 0;
+                               try{
+                                       range = vars.get(0).getArrayValue();
+                                       dt = vars.get(0).getStep();
+                                       start = vars.get(0).getStart();
+                                       near = vars.get(1).getDoubleValue();
+                               } catch (Exception e) {
+                                       return new Variable("Invalid");
+                               }
+                               
+                               return new Variable("double TNEAR result", ArrayUtils.tnear(range, near, start, dt) );
+                       } 
+               };
+               allFunctions.add(tnearFn);
+       }
+}
diff --git a/core/src/net/sf/openrocket/simulation/customexpression/IndexExpression.java b/core/src/net/sf/openrocket/simulation/customexpression/IndexExpression.java
new file mode 100644 (file)
index 0000000..6fb084d
--- /dev/null
@@ -0,0 +1,56 @@
+package net.sf.openrocket.simulation.customexpression;
+
+import java.util.List;
+
+import de.congrace.exp4j.Calculable;
+import de.congrace.exp4j.Variable;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.LinearInterpolator;
+
+public class IndexExpression extends CustomExpression {
+
+       FlightDataType type;
+       private static final LogHelper log = Application.getLogger();
+       
+       public IndexExpression(OpenRocketDocument doc, String indexText, String typeText){
+               super(doc);
+               
+               setExpression(indexText);
+               this.setName("");
+               this.setSymbol(typeText);
+       }
+       
+       @Override
+       public Variable evaluate(SimulationStatus status){
+               
+               Calculable calc = buildExpression();
+               if (calc == null){
+                       return new Variable("Unknown");
+               }
+               
+               // From the given datatype, get the time and function values and make an interpolator
+
+               //Note: must get in a way that flight data system will figure out units. Otherwise there will be a type conflict when we get the new data.
+               FlightDataType type = FlightDataType.getType(null, getSymbol(), null);  
+                               
+               List<Double> data = status.getFlightData().get(type);
+               List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
+               LinearInterpolator interp = new LinearInterpolator(time, data); 
+               
+               // Evaluate this expression to get the t value
+               try{
+                       double tvalue = calc.calculate().getDoubleValue();
+                       return new Variable(hash(), interp.getValue( tvalue ) );
+               }
+               catch (java.util.EmptyStackException e){
+                       log.user("Unable to calculate time index for indexed expression "+getExpressionString()+" due to empty stack exception");
+                       return new Variable("Unknown");
+               }
+               
+       }
+}
diff --git a/core/src/net/sf/openrocket/simulation/customexpression/RangeExpression.java b/core/src/net/sf/openrocket/simulation/customexpression/RangeExpression.java
new file mode 100644 (file)
index 0000000..1667b61
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * A range expression contains two indexExpressions for the beginning and end time index of a range
+ */
+
+package net.sf.openrocket.simulation.customexpression;
+
+import java.util.List;
+
+import de.congrace.exp4j.Calculable;
+import de.congrace.exp4j.ExpressionBuilder;
+import de.congrace.exp4j.Variable;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.simulation.customexpression.CustomExpression;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.startup.Application;
+import net.sf.openrocket.util.ArrayUtils;
+import net.sf.openrocket.util.LinearInterpolator;
+import net.sf.openrocket.util.MathUtil;
+
+public class RangeExpression extends CustomExpression {
+       private static final LogHelper log = Application.getLogger();
+
+       private ExpressionBuilder startBuilder, endBuilder;
+       
+       public RangeExpression(OpenRocketDocument doc, String startTime, String endTime, String variableType) {
+               super(doc);
+               
+               if ("".equals(startTime.trim())){
+                       startTime = "0";
+               }
+               if ("".equals(endTime.trim())){
+                       endTime = "t";
+               }
+               
+               this.setName("");
+               this.setSymbol(variableType);
+               this.setExpressions(startTime, endTime);
+               this.expression = variableType+startTime+endTime; // this is used just for generating the hash
+               
+               log.info("New range expression, "+startTime + " to "+endTime);
+       }
+       
+       /*
+        * Sets the actual expression string for this expression
+        */
+       private void setExpressions(String start, String end){
+               
+               startBuilder = new ExpressionBuilder(start);
+               endBuilder = new ExpressionBuilder(end);
+               for (String n : getAllSymbols()){
+                       startBuilder.withVariable(new Variable(n));
+                       endBuilder.withVariable(new Variable(n));
+               }
+       }
+       
+       @Override
+       public Variable evaluate(SimulationStatus status){
+               
+               Calculable startCalc = buildExpression(startBuilder);
+               Calculable endCalc = buildExpression(endBuilder);
+               if (startCalc == null || endCalc == null){
+                       return new Variable("Unknown");
+               }
+               
+               // Set the variables in the start and end calculators
+               for (FlightDataType type : status.getFlightData().getTypes()){
+                       double value = status.getFlightData().getLast(type); 
+                       startCalc.setVariable( new Variable(type.getSymbol(), value ) );
+                       endCalc.setVariable( new Variable(type.getSymbol(), value ) );
+               }               
+               
+               // From the given datatype, get the time and function values and make an interpolator
+
+               //Note: must get in a way that flight data system will figure out units. Otherwise there will be a type conflict when we get the new data.
+               FlightDataType type = FlightDataType.getType(null, getSymbol(), null);
+               
+               List<Double> data = status.getFlightData().get(type);
+               List<Double> time = status.getFlightData().get(FlightDataType.TYPE_TIME);
+               LinearInterpolator interp = new LinearInterpolator(time, data); 
+               
+               // Evaluate the expression to get the start and end of the range
+               double startTime, endTime;
+               try{
+                       startTime = startCalc.calculate().getDoubleValue();
+                       startTime = MathUtil.clamp(startTime, 0, Double.MAX_VALUE);
+                       
+                       endTime = endCalc.calculate().getDoubleValue();
+                       endTime = MathUtil.clamp(endTime, 0, time.get(time.size()-1));
+               }
+               catch (java.util.EmptyStackException e){
+                       log.user("Unable to calculate time index for range expression "+getSymbol()+" due to empty stack exception");
+                       return new Variable("Unknown");
+               }
+               
+               // generate an array representing the range
+               double step = status.getSimulationConditions().getSimulation().getOptions().getTimeStep();
+               double[] t = ArrayUtils.range(startTime, endTime,  step);
+               double[] y = new double[t.length]; 
+               int i = 0;
+               for (double tval : t){
+                       y[i] = interp.getValue( tval );
+                       i++;
+               }
+                               
+               Variable result;
+               if (y.length == 0){
+                       result = new Variable("Unknown");
+               }
+               else {
+                       result = new Variable(hash(), y, startTime, step);
+               }
+               
+               return result;
+       }
+}
index ebb2ad94c3ec8cedab38e43596e955da5afce56c..3f156f38ee392c9e9dcf793ed624fc517affa4a3 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.simulation.listeners;
 
+import java.util.List;
+
 import net.sf.openrocket.aerodynamics.AerodynamicForces;
 import net.sf.openrocket.aerodynamics.FlightConditions;
 import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
@@ -8,6 +10,7 @@ import net.sf.openrocket.motor.MotorInstance;
 import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.RecoveryDevice;
 import net.sf.openrocket.simulation.AccelerationData;
+import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.MassData;
 import net.sf.openrocket.simulation.SimulationStatus;
@@ -27,6 +30,16 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
        
        ////  SimulationListener  ////
        
+       @Override
+       public String getName() {
+               return this.getClass().getSimpleName();
+       }
+       
+       @Override
+       public String[] getMenuPosition() {
+               return new String[0];
+       }
+       
        @Override
        public void startSimulation(SimulationStatus status) throws SimulationException {
                // No-op
@@ -57,9 +70,15 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
                return false;
        }
        
+       /**
+        * Return an array of any flight data types this listener creates.
+        */
+       @Override
+       public FlightDataType[] getFlightDataTypes(){
+               return new FlightDataType[] {};
+       }
+       
        
-
-
        ////  SimulationEventListener  ////
        
        @Override
@@ -83,7 +102,7 @@ public class AbstractSimulationListener implements SimulationListener, Simulatio
        }
        
        
-
+       
        ////  SimulationComputationListener  ////
        
        @Override
index be46c50f8e747fcb33823f618103e648401919d9..3089d053938707430b2adc58c9ea16751cf99b2e 100644 (file)
@@ -1,9 +1,12 @@
 package net.sf.openrocket.simulation.listeners;
 
+import java.util.List;
+
 import net.sf.openrocket.aerodynamics.AerodynamicForces;
 import net.sf.openrocket.aerodynamics.FlightConditions;
 import net.sf.openrocket.models.atmosphere.AtmosphericConditions;
 import net.sf.openrocket.simulation.AccelerationData;
+import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.MassData;
 import net.sf.openrocket.simulation.SimulationStatus;
 import net.sf.openrocket.simulation.exception.SimulationException;
@@ -64,4 +67,5 @@ public interface SimulationComputationListener extends SimulationListener {
        
        public double postSimpleThrustCalculation(SimulationStatus status, double thrust) throws SimulationException;
 
+       public FlightDataType[] getFlightDataTypes();
 }
index 6cbb87f3ba23d91cfca35965fe06dd77678ef4cf..8ac0e11a73877a0b0b67ae9af61b67a5e2ce8665 100644 (file)
@@ -1,9 +1,12 @@
 package net.sf.openrocket.simulation.listeners;
 
+import java.util.List;
+
 import net.sf.openrocket.motor.MotorId;
 import net.sf.openrocket.motor.MotorInstance;
 import net.sf.openrocket.rocketcomponent.MotorMount;
 import net.sf.openrocket.rocketcomponent.RecoveryDevice;
+import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.FlightEvent;
 import net.sf.openrocket.simulation.SimulationStatus;
 import net.sf.openrocket.simulation.exception.SimulationException;
@@ -56,6 +59,10 @@ public interface SimulationEventListener {
         */
        public boolean recoveryDeviceDeployment(SimulationStatus status, RecoveryDevice recoveryDevice)
                        throws SimulationException;
+
+
+
+       public FlightDataType[] getFlightDataTypes();
        
 
 }
index 98b28aada2846690c6daf67f6171d6b5ba05347c..322db8e714d96a60ab83bfd65ab8e5c6bf1b0486 100644 (file)
@@ -1,5 +1,8 @@
 package net.sf.openrocket.simulation.listeners;
 
+import java.util.List;
+
+import net.sf.openrocket.simulation.FlightDataType;
 import net.sf.openrocket.simulation.SimulationStatus;
 import net.sf.openrocket.simulation.exception.SimulationException;
 
@@ -7,6 +10,25 @@ import net.sf.openrocket.simulation.exception.SimulationException;
 
 public interface SimulationListener {
        
+       /**
+        * Get the name of this simulation listener.  Ideally this should be localized, as
+        * it can be displayed in the UI.
+        * 
+        * @return      the name of this simulation listener.
+        */
+       public String getName();
+       
+       
+       /**
+        * Get the menu position of this simulation listener.  This should be an array
+        * of localized submenu names in descending order, or an empty array for positioning
+        * in the base menu.
+        * 
+        * @return      the menu position of this simulation listener.
+        */
+       public String[] getMenuPosition();
+       
+       
        /**
         * Called when starting a simulation.
         * 
@@ -57,4 +79,11 @@ public interface SimulationListener {
         */
        public boolean isSystemListener();
        
+       
+       /**
+        * Return a list of any flight data types this listener creates.
+        */
+       public FlightDataType[] getFlightDataTypes();
+       
+       
 }
diff --git a/core/src/net/sf/openrocket/simulation/listeners/example/DampingMoment.java b/core/src/net/sf/openrocket/simulation/listeners/example/DampingMoment.java
new file mode 100644 (file)
index 0000000..b9d2e46
--- /dev/null
@@ -0,0 +1,129 @@
+package net.sf.openrocket.simulation.listeners.example;
+
+import java.util.List;
+import java.util.Map;
+
+import net.sf.openrocket.aerodynamics.AerodynamicCalculator;
+import net.sf.openrocket.aerodynamics.AerodynamicForces;
+import net.sf.openrocket.aerodynamics.FlightConditions;
+import net.sf.openrocket.motor.MotorId;
+import net.sf.openrocket.motor.MotorInstance;
+import net.sf.openrocket.motor.MotorInstanceConfiguration;
+import net.sf.openrocket.rocketcomponent.MotorMount;
+import net.sf.openrocket.rocketcomponent.RocketComponent;
+import net.sf.openrocket.simulation.FlightDataBranch;
+import net.sf.openrocket.simulation.FlightDataType;
+import net.sf.openrocket.simulation.SimulationStatus;
+import net.sf.openrocket.simulation.exception.SimulationException;
+import net.sf.openrocket.simulation.listeners.AbstractSimulationListener;
+import net.sf.openrocket.unit.UnitGroup;
+import net.sf.openrocket.util.ArrayList;
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.PolyInterpolator;
+
+public class DampingMoment extends AbstractSimulationListener {
+       
+       private static final FlightDataType type = FlightDataType.getType("Damping moment coefficient", "Cdm", UnitGroup.UNITS_COEFFICIENT);
+       private static final FlightDataType[] typeList = {type};
+       
+       public String getName(){
+               return "Damping moment listener";
+       }
+       
+       /**
+        * Return a list of any flight data types this listener creates.
+        */
+       public FlightDataType[] getFlightDataTypes(){
+               return typeList;
+       }
+       
+       @Override
+       public FlightConditions postFlightConditions(SimulationStatus status, FlightConditions flightConditions) throws SimulationException {
+               
+               // Save it as a flightdatatype
+               
+               //status.getFlightData().setValue(type, aerodynamicPart + propulsivePart);
+               status.getFlightData().setValue(type, calculate(status, flightConditions));
+
+               return flightConditions;
+       }
+       
+       private double calculate(SimulationStatus status, FlightConditions flightConditions){
+               
+               // Work out the propulsive/jet damping part of the moment.
+               
+               // dm/dt = (thrust - ma)/v
+               FlightDataBranch data = status.getFlightData();
+               
+               List<Double> mpAll = data.get(FlightDataType.TYPE_PROPELLANT_MASS);
+               List<Double> time = data.get(FlightDataType.TYPE_TIME);
+               if (mpAll == null || time == null){
+                       return Double.NaN;
+               }
+               
+               int len = mpAll.size();
+               
+               // This isn't as accurate as I would like
+               double mdot=Double.NaN;
+               if (len > 2){
+                       // Using polynomial interpolator for derivative. Doesn't help much
+                       //double[] x = { time.get(len-5), time.get(len-4), time.get(len-3), time.get(len-2), time.get(len-1) };
+                       //double[] y = { mpAll.get(len-5), mpAll.get(len-4), mpAll.get(len-3), mpAll.get(len-2), mpAll.get(len-1) };
+                       //PolyInterpolator interp = new PolyInterpolator(x);
+                       //double[] coeff = interp.interpolator(y);
+                       //double dt = .01;
+                       //mdot = (interp.eval(x[4], coeff) - interp.eval(x[4]-dt, coeff))/dt; 
+                                               
+                       mdot = (mpAll.get(len-1) - mpAll.get(len-2)) / (time.get(len-1) - time.get(len-2));
+               }
+               
+               double cg = data.getLast(FlightDataType.TYPE_CG_LOCATION);
+               
+               // find the maximum distance from nose to nozzle. 
+               double nozzleDistance = 0;
+               for (MotorId id: status.getMotorConfiguration().getMotorIDs()){
+                       MotorInstanceConfiguration config = status.getMotorConfiguration();
+                       Coordinate position = config.getMotorPosition(id);
+                       
+                       double x = position.x + config.getMotorInstance(id).getParentMotor().getLength();
+                       if (x > nozzleDistance){
+                               nozzleDistance = x;
+                       }                       
+               }
+               
+               // now can get the propulsive part
+               double propulsivePart = mdot * Math.pow(nozzleDistance - cg, 2);
+               
+               // Work out the aerodynamic part of the moment.
+               double aerodynamicPart = 0;
+               
+               AerodynamicCalculator aerocalc = status.getSimulationConditions().getAerodynamicCalculator();
+               
+               // Must go through each component ...
+               Map<RocketComponent, AerodynamicForces> forces = aerocalc.getForceAnalysis(status.getConfiguration(), flightConditions, null);
+               for (Map.Entry<RocketComponent, AerodynamicForces> entry : forces.entrySet()){
+                       
+                       RocketComponent comp = entry.getKey();
+                       
+                       if (!comp.isAerodynamic()) continue;
+                       
+                       //System.out.println(comp.toString());
+                       
+                       double CNa = entry.getValue().getCNa(); //?
+                       double Cp = entry.getValue().getCP().length();
+                       double z = comp.getPositionValue(); //?
+                       
+                       aerodynamicPart += CNa*Math.pow(z-Cp, 2);
+               }
+               
+               double v = flightConditions.getVelocity();
+               double rho = flightConditions.getAtmosphericConditions().getDensity();
+               double ar = flightConditions.getRefArea();
+               
+               aerodynamicPart = aerodynamicPart * .5 * rho * v * ar;
+               
+               return aerodynamicPart + propulsivePart;
+       
+       }
+       
+}
index 80993218c9a32f4c3ef9851d060f18db84bc2ca6..68063cb40ac46cb341440e41ae7889758f889ed8 100644 (file)
@@ -22,8 +22,7 @@ public class RollControlListener extends AbstractSimulationListener {
        private static final String CONTROL_FIN_NAME = "CONTROL";
        
        // Define custom flight data type
-       private static final FlightDataType FIN_CANT_TYPE = FlightDataType.getType("Control fin cant",
-                       UnitGroup.UNITS_ANGLE);
+       private static final FlightDataType FIN_CANT_TYPE = FlightDataType.getType("Control fin cant", "\u03B1fc", UnitGroup.UNITS_ANGLE);
        
        // Simulation time at which PID controller is activated
        private static final double START_TIME = 0.5;
index 7718b67ec0f94504c844b6c50cb2ee31d43277c1..18d1af776e4855fb212a9716300c67fccbbd45b4 100644 (file)
@@ -1,5 +1,6 @@
 package net.sf.openrocket.startup;
 
+import net.sf.openrocket.database.ComponentPresetDao;
 import net.sf.openrocket.database.MotorDatabase;
 import net.sf.openrocket.l10n.ClassBasedTranslator;
 import net.sf.openrocket.l10n.DebugTranslator;
@@ -23,6 +24,8 @@ public final class Application {
        private static Translator baseTranslator = new DebugTranslator(null);
        
        private static MotorDatabase motorSetDatabase;
+       
+       private static ComponentPresetDao componentPresetDao;
 
        private static Preferences preferences;
        
@@ -159,6 +162,15 @@ public final class Application {
        public static void setMotorSetDatabase(MotorDatabase motorSetDatabase) {
                Application.motorSetDatabase = motorSetDatabase;
        }
+
+       public static ComponentPresetDao getComponentPresetDao() {
+               return componentPresetDao;
+               
+       }
+
+       public static void setComponentPresetDao(ComponentPresetDao componentPresetDao) {
+               Application.componentPresetDao = componentPresetDao;
+       }
        
 
 }
diff --git a/core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java b/core/src/net/sf/openrocket/startup/ConcurrentComponentPresetDatabaseLoader.java
new file mode 100644 (file)
index 0000000..79838ec
--- /dev/null
@@ -0,0 +1,140 @@
+package net.sf.openrocket.startup;
+
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import net.sf.openrocket.database.ComponentPresetDatabase;
+import net.sf.openrocket.file.iterator.DirectoryIterator;
+import net.sf.openrocket.file.iterator.FileIterator;
+import net.sf.openrocket.gui.util.SimpleFileFilter;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.xml.OpenRocketComponentLoader;
+import net.sf.openrocket.util.Pair;
+
+public class ConcurrentComponentPresetDatabaseLoader {
+
+       private static final LogHelper log = Application.getLogger();
+       private static final String SYSTEM_PRESET_DIR = "datafiles/presets";
+
+       private final CountDownLatch latch = new CountDownLatch(1);
+
+       private final ComponentPresetDatabase componentPresetDao;
+
+       private final ExecutorService writerPool;
+
+       private final ExecutorService loaderPool;
+
+       private final Thread workGenerator;
+
+       private FileIterator iterator;
+
+       private long startTime;
+       private long fileCount = 0;
+       private long presetCount = 0;
+
+       ConcurrentComponentPresetDatabaseLoader( ComponentPresetDatabase componentPresetDao ) {
+               this.componentPresetDao = componentPresetDao;
+
+               writerPool = Executors.newSingleThreadExecutor(new ThreadFactory() {
+                       @Override
+                       public Thread newThread(Runnable r) {
+                               Thread t = new Thread(r,"PresetWriterThread");
+                               return t;
+                       }
+               });
+
+               loaderPool = Executors.newFixedThreadPool(3, new ThreadFactory() {
+                       int threadCount = 0;
+                       @Override
+                       public Thread newThread(Runnable r) {
+                               Thread t = new Thread(r,"PresetLoaderPool-" + threadCount++);
+                               t.setPriority(Thread.MIN_PRIORITY);
+                               return t;
+                       }
+
+               });
+
+               workGenerator = new Thread( new WorkGenerator(),"PresetGeneratorThread");
+       }
+
+       public void load() {
+               startTime = System.currentTimeMillis();
+               workGenerator.start();
+       }
+
+       public void await() throws InterruptedException {
+               latch.await();
+               loaderPool.shutdown();
+               loaderPool.awaitTermination(90, TimeUnit.SECONDS);
+               writerPool.shutdown();
+               writerPool.awaitTermination(90, TimeUnit.SECONDS);
+               if ( iterator != null ) {
+                       iterator.close();
+               }
+               long end = System.currentTimeMillis();
+               log.debug("Time to load presets: " + (end-startTime) + "ms " + presetCount + " loaded from " + fileCount + " files");
+       }
+
+
+       private class WorkGenerator implements Runnable {
+               @Override
+               public void run() {
+                       // Start loading
+                       log.info("Loading component presets from " + SYSTEM_PRESET_DIR);
+
+                       iterator = DirectoryIterator.findDirectory(SYSTEM_PRESET_DIR,
+                                       new SimpleFileFilter("", false, "orc"));
+
+                       if (iterator != null) {
+                               while( iterator.hasNext() ) {
+                                       Pair<String,InputStream> f = iterator.next();
+                                       FileLoader loader = new FileLoader( f.getV(), f.getU() );
+                                       loaderPool.execute(loader);
+                                       fileCount ++;
+                               }
+                       }
+                       latch.countDown();
+               }
+       }
+
+       private class FileLoader implements Runnable {
+               private final InputStream is;
+               private final String fileName;
+
+               public FileLoader(InputStream is, String fileName) {
+                       super();
+                       this.is = is;
+                       this.fileName = fileName;
+               }
+
+               @Override
+               public void run() {
+                       OpenRocketComponentLoader loader = new OpenRocketComponentLoader();
+                       Collection<ComponentPreset> presets = loader.load(is, fileName);
+                       PresetWriter writer = new PresetWriter(presets);
+                       writerPool.execute(writer);
+               }               
+       }
+
+       private class PresetWriter implements Runnable {
+               private final Collection<ComponentPreset> presets;
+
+               public PresetWriter(Collection<ComponentPreset> presets) {
+                       super();
+                       this.presets = presets;
+               }
+
+               @Override
+               public void run() {
+                       presetCount += presets.size();
+                       componentPresetDao.addAll(presets);
+               }
+
+       }
+}
diff --git a/core/src/net/sf/openrocket/startup/ConcurrentLoadingThrustCurveMotorSetDatabase.java b/core/src/net/sf/openrocket/startup/ConcurrentLoadingThrustCurveMotorSetDatabase.java
new file mode 100644 (file)
index 0000000..2eba9b4
--- /dev/null
@@ -0,0 +1,302 @@
+package net.sf.openrocket.startup;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import net.sf.openrocket.database.ThrustCurveMotorSet;
+import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
+import net.sf.openrocket.file.iterator.DirectoryIterator;
+import net.sf.openrocket.file.iterator.FileIterator;
+import net.sf.openrocket.file.motor.MotorLoaderHelper;
+import net.sf.openrocket.gui.util.SimpleFileFilter;
+import net.sf.openrocket.gui.util.SwingPreferences;
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.motor.Motor;
+import net.sf.openrocket.motor.ThrustCurveMotor;
+import net.sf.openrocket.util.BugException;
+import net.sf.openrocket.util.Pair;
+
+/**
+ * Load motors in parallel using a three stage pipeline.
+ * 
+ * Stage 1: single thread managed by the ThrustCurveMotorSetDatabase.  This thread generates
+ *          one object for each thrust curve motor file and puts it in the second stage.
+ *          
+ * Stage 2: multiple threads which process individual files.  Each process takes
+ *          a single motor file and parses out the list of motors it contains.
+ *          The list of motors is queued up for the third stage to process.
+ *          
+ * Stage 3: single thread which processes the list of motors generated in stage 2.
+ *          This thread puts all the motors from the list in the motor set database.
+ *          
+ * It is important that stage 3 be done with a single thread because ThrustCurveMotorSetDatabase
+ * is not thread safe.  Even if synchronization were to be done, it is unlikely that parallelizing
+ * this process would improve anything.
+ * 
+ *
+ */
+public class ConcurrentLoadingThrustCurveMotorSetDatabase extends ThrustCurveMotorSetDatabase {
+
+       private static final LogHelper log = Application.getLogger();
+       private final String thrustCurveDirectory;
+
+       /** Block motor loading for this many milliseconds */
+       // Block motor loading for 1.5 seconds to allow window painting to be faster
+       private static AtomicInteger blockLoading = new AtomicInteger(1500);
+
+       public ConcurrentLoadingThrustCurveMotorSetDatabase(String thrustCurveDirectory) {
+               // configure ThrustCurveMotorSetDatabase as true so we get our own thread in
+               // loadMotors.
+               super(true);
+               this.thrustCurveDirectory = thrustCurveDirectory;
+       }
+
+       @Override
+       protected void loadMotors() {
+
+               // Block loading until timeout occurs or database is taken into use
+               log.info("Blocking motor loading while starting up");
+               /*
+               while (!inUse && blockLoading.addAndGet(-100) > 0) {
+                       try {
+                               Thread.sleep(100);
+                       } catch (InterruptedException e) {
+                       }
+               }
+               */
+               log.info("Blocking ended, inUse=" + inUse + " blockLoading=" + blockLoading.get());
+
+               BookKeeping keeper = new BookKeeping();
+               keeper.start();
+
+               try {
+                       keeper.waitForFinish();
+               }
+               catch ( InterruptedException iex ) {
+                       throw new BugException(iex);
+               }
+
+               keeper = null;
+
+       }
+
+       private void addAll( List<Motor> motors ) {
+               for (Motor m : motors) {
+                       addMotor( (ThrustCurveMotor) m);
+               }
+       }
+
+       /**
+        * A class which holds all the threading data.
+        * Implemented as an inner class so we can easily jettison the references when
+        * the processing is terminated.
+        *
+        */
+       private class BookKeeping {
+
+               /*
+                * Executor for Stage 3.
+                */
+               private final ExecutorService writerThread;
+
+               /*
+                * Executor for Stage 2.
+                */
+               private final ExecutorService loaderPool;
+
+               /*
+                * Runnable used for Stage 1.
+                */
+               private final WorkGenerator workGenerator;
+
+               private long startTime;
+
+               /*
+                * Number of thrust curves loaded
+                */
+               private int thrustCurveCount = 0;
+
+               /*
+                * Number of files processed.
+                */
+               private int fileCount = 0;
+
+               /*
+                * We have to hold on to the zip file iterator which is used to load
+                * the system motor files until all processing is done.  This is because
+                * closing the iterator prematurely causes all the InputStreams opened
+                * with it to close. 
+                */
+               private FileIterator iterator;
+
+               private BookKeeping() {
+
+                       writerThread = new ThreadPoolExecutor(1,1,200, TimeUnit.SECONDS,
+                                       new LinkedBlockingQueue<Runnable>(),
+                                       new ThreadFactory() {
+                               @Override
+                               public Thread newThread(Runnable r) {
+                                       Thread t = new Thread(r,"MotorWriterThread");
+                                       return t;
+                               }
+                       });
+
+                       loaderPool = new ThreadPoolExecutor(10,10, 2, TimeUnit.SECONDS,
+                                       new LinkedBlockingQueue<Runnable>(),
+                                       new ThreadFactory() {
+                               int threadCount = 0;
+                               @Override
+                               public Thread newThread(Runnable r) {
+                                       Thread t = new Thread(r,"MotorLoaderPool-" + threadCount++);
+                                       return t;
+                               }
+                       });
+
+                       workGenerator = new WorkGenerator();
+
+               }
+
+               private void start() {
+
+                       startTime = System.currentTimeMillis();
+
+                       log.info("Starting motor loading from " + thrustCurveDirectory + " in background thread.");
+
+                       // Run the work generator - in this thread.
+                       workGenerator.run();
+
+               }
+
+               private void waitForFinish() throws InterruptedException {
+                       try {
+                               loaderPool.shutdown();
+                               loaderPool.awaitTermination(90, TimeUnit.SECONDS);
+                               writerThread.shutdown();
+                               writerThread.awaitTermination(90, TimeUnit.SECONDS);
+                       }
+                       finally {
+                               iterator.close();
+                       }
+
+                       long endTime = System.currentTimeMillis();
+
+                       int distinctMotorCount = 0;
+                       int distinctThrustCurveCount = 0;
+                       distinctMotorCount = motorSets.size();
+                       for (ThrustCurveMotorSet set : motorSets) {
+                               distinctThrustCurveCount += set.getMotorCount();
+                       }
+
+                       log.info("Motor loading done, took " + (endTime - startTime) + " ms to load " 
+                                       + fileCount + " files/directories containing " 
+                                       + thrustCurveCount + " thrust curves which contained "
+                                       + distinctMotorCount + " distinct motors with "
+                                       + distinctThrustCurveCount + " distinct thrust curves.");
+
+               }
+
+
+               private class WorkGenerator implements Runnable {
+
+                       @Override
+                       public void run() {
+                               // Start loading
+                               log.info("Loading motors from " + thrustCurveDirectory);
+
+                               iterator = DirectoryIterator.findDirectory(thrustCurveDirectory,
+                                               new SimpleFileFilter("", false, "eng", "rse"));
+
+                               // Load the packaged thrust curves
+                               if (iterator == null) {
+                                       throw new IllegalStateException("Thrust curve directory " + thrustCurveDirectory +
+                                                       "not found, distribution built wrong");
+                               }
+
+                               while( iterator.hasNext() ) {
+                                       Pair<String,InputStream> f = iterator.next();
+                                       MotorLoader loader = new MotorLoader( f.getV(), f.getU() );
+                                       loaderPool.execute(loader);
+                                       fileCount ++;
+                               }
+
+                               // Load the user-defined thrust curves
+                               for (File file : ((SwingPreferences) Application.getPreferences()).getUserThrustCurveFiles()) {
+                                       log.info("Loading motors from " + file);
+                                       MotorLoader loader = new MotorLoader( file );
+                                       loaderPool.execute(loader);
+                                       fileCount++;
+                               }
+                       }
+               }
+
+               private class MotorLoader implements Runnable {
+
+                       private final InputStream is;
+                       private final String fileName;
+
+                       private final File file;
+
+                       public MotorLoader( File file ) {
+                               super();
+                               this.file = file;
+                               this.is = null;
+                               this.fileName = null;
+                       }
+
+                       public MotorLoader(InputStream is, String fileName) {
+                               super();
+                               this.file = null;
+                               this.is = is;
+                               this.fileName = fileName;
+                       }
+
+                       @Override
+                       public void run() {
+                               log.debug("Loading motor from " + fileName);
+
+                               try {
+                                       List<Motor> motors;
+                                       if ( file == null ) {
+                                               motors = MotorLoaderHelper.load(is, fileName);
+                                       } else {
+                                               motors = MotorLoaderHelper.load(file);
+                                       }
+                                       writerThread.submit( new MotorInserter(motors));
+                               }
+                               finally {
+                                       if ( is != null ) {
+                                               try {
+                                                       is.close();
+                                               } catch ( IOException iex ) {
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               private class MotorInserter implements Runnable {
+
+                       private final List<Motor> motors;
+
+                       MotorInserter( List<Motor> motors ) {
+                               this.motors = motors;
+                       }
+
+                       @Override
+                       public void run() {
+                               thrustCurveCount += motors.size();
+                               ConcurrentLoadingThrustCurveMotorSetDatabase.this.addAll(motors);
+                       }
+
+               }
+       }
+
+}
diff --git a/core/src/net/sf/openrocket/startup/OSXStartup.java b/core/src/net/sf/openrocket/startup/OSXStartup.java
new file mode 100644 (file)
index 0000000..ad14186
--- /dev/null
@@ -0,0 +1,115 @@
+package net.sf.openrocket.startup;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+
+import net.sf.openrocket.arch.SystemInfo;
+import net.sf.openrocket.arch.SystemInfo.Platform;
+import net.sf.openrocket.gui.dialogs.AboutDialog;
+import net.sf.openrocket.gui.dialogs.preferences.PreferencesDialog;
+import net.sf.openrocket.gui.main.BasicFrame;
+import net.sf.openrocket.logging.LogHelper;
+
+import com.apple.eawt.AboutHandler;
+import com.apple.eawt.PreferencesHandler;
+import com.apple.eawt.QuitHandler;
+import com.apple.eawt.QuitResponse;
+import com.apple.eawt.AppEvent.AboutEvent;
+import com.apple.eawt.AppEvent.PreferencesEvent;
+import com.apple.eawt.AppEvent.QuitEvent;
+
+/**
+ * Static code for initialization of OSX UI Elements: Menu, Icon, Name and
+ * Application menu handlers.
+ * 
+ * @author Bill Kuker <bkuker@billkuker.com>
+ * 
+ */
+final class OSXStartup {
+       private static final LogHelper log = Application.getLogger();
+
+       // The name in the app menu
+       private static final String APP_NAME = "OpenRocket";
+       
+       // The image resource to use for the Dock Icon
+       private static final String ICON_RSRC = "/pix/icon/icon-256.png";
+       
+       /**
+        * The handler for the Quit item in the OSX app menu
+        */
+       private static final QuitHandler qh = new QuitHandler() {
+               @Override
+               public void handleQuitRequestWith(final QuitEvent e, final QuitResponse r) {
+                       BasicFrame.quitAction();
+                       // if we get here the user canceled
+                       r.cancelQuit();
+               }
+       };
+
+       /**
+        * The handler for the About item in the OSX app menu
+        */
+       private static final AboutHandler ah = new AboutHandler() {
+               @Override
+               public void handleAbout(final AboutEvent a) {
+                       new AboutDialog(null).setVisible(true);
+               }
+       };
+
+       /**
+        * The handler for the Preferences item in the OSX app menu
+        */
+       private static final PreferencesHandler ph = new PreferencesHandler() {
+               @Override
+               public void handlePreferences(final PreferencesEvent p) {
+                       PreferencesDialog.showPreferences(null);
+               }
+       };
+
+       /**
+        * Sets up the Application's Icon, Name, Menu and some menu item handlers
+        * for Apple OSX. This method needs to be called before other AWT or Swing
+        * things happen, or parts will fail to work.
+        * 
+        * This function should fail gracefully if the OS is wrong.
+        */
+       static void setupOSX() {
+               if (SystemInfo.getPlatform() != Platform.MAC_OS) {
+                       log.warn("Attempting to set up OSX UI on non-MAC_OS");
+               }
+               log.debug("Setting up OSX UI Elements");
+               try {
+                       // Put the menu bar at the top of the screen
+                       System.setProperty("apple.laf.useScreenMenuBar", "true");
+                       // Set the name in the menu
+                       System.setProperty("com.apple.mrj.application.apple.menu.about.name", APP_NAME);
+
+                       // This line must come AFTER the above properties are set, otherwise
+                       // the name will not appear
+                       final com.apple.eawt.Application osxApp = com.apple.eawt.Application.getApplication();
+
+                       if (osxApp == null) {
+                               // Application is null: Something is wrong, give up on OSX
+                               // setup.
+                               throw new NullPointerException("com.apple.eawt.Application.getApplication() returned NULL. "
+                                               + "Aborting OSX UI Setup.");
+                       }
+                       
+                       // Set handlers
+                       osxApp.setQuitHandler(qh);
+                       osxApp.setAboutHandler(ah);
+                       osxApp.setPreferencesHandler(ph);
+
+                       // Set the dock icon to the largest icon
+                       final Image dockIcon = Toolkit.getDefaultToolkit().getImage(
+                                       Startup2.class.getResource(ICON_RSRC));
+                       osxApp.setDockIconImage(dockIcon);
+
+               } catch (final Throwable t) {
+                       // None of the preceding is critical to the app,
+                       // so at worst case log an error and continue
+                       log.warn("Error setting up OSX UI:", t);
+               }
+       }
+
+}
index 0a5e62b94e0441a75d7124e6976d7ab281a1f87c..73a29cc2f0e25a352f07113be07fb22e16b7c00e 100644 (file)
@@ -5,8 +5,8 @@ import java.util.Map;
 import java.util.Set;\r
 \r
 import net.sf.openrocket.database.Databases;\r
-import net.sf.openrocket.l10n.Translator;\r
 import net.sf.openrocket.material.Material;\r
+import net.sf.openrocket.preset.ComponentPreset;\r
 import net.sf.openrocket.rocketcomponent.BodyComponent;\r
 import net.sf.openrocket.rocketcomponent.FinSet;\r
 import net.sf.openrocket.rocketcomponent.InternalComponent;\r
@@ -22,7 +22,7 @@ import net.sf.openrocket.util.MathUtil;
 import net.sf.openrocket.util.UniqueID;\r
 \r
 public abstract class Preferences {\r
-\r
+       \r
        /*\r
         * Well known string keys to preferences.\r
         * There are other strings out there in the source as well.\r
@@ -45,26 +45,30 @@ public abstract class Preferences {
        \r
        public static final String MOTOR_DIAMETER_FILTER = "MotorDiameterMatch";\r
        public static final String MOTOR_HIDE_SIMILAR = "MotorHideSimilar";\r
-\r
+       \r
        // Node names\r
        public static final String PREFERRED_THRUST_CURVE_MOTOR_NODE = "preferredThrustCurveMotors";\r
-\r
+       \r
        /*\r
         * ******************************************************************************************\r
         * \r
         * Abstract methods which must be implemented by any derived class.\r
         */\r
-       public abstract boolean getBoolean( String key, boolean defaultValue );\r
-       public abstract void putBoolean( String key, boolean value );\r
-\r
-       public abstract int getInt( String key, int defaultValue);\r
-       public abstract void putInt( String key, int value );\r
-\r
-       public abstract double getDouble( String key, double defaultValue );\r
-       public abstract void putDouble( String key, double value );\r
-\r
-       public abstract String getString( String key, String defaultValue );\r
-       public abstract void putString( String key, String value );\r
+       public abstract boolean getBoolean(String key, boolean defaultValue);\r
+       \r
+       public abstract void putBoolean(String key, boolean value);\r
+       \r
+       public abstract int getInt(String key, int defaultValue);\r
+       \r
+       public abstract void putInt(String key, int value);\r
+       \r
+       public abstract double getDouble(String key, double defaultValue);\r
+       \r
+       public abstract void putDouble(String key, double value);\r
+       \r
+       public abstract String getString(String key, String defaultValue);\r
+       \r
+       public abstract void putString(String key, String value);\r
        \r
        /**\r
         * Directory represents a way to collect multiple keys together.  Implementors may\r
@@ -74,10 +78,10 @@ public abstract class Preferences {
         * @param defaultValue\r
         * @return\r
         */\r
-       public abstract String getString( String directory, String key, String defaultValue);\r
-\r
-       public abstract void putString( String directory, String key, String value );\r
-\r
+       public abstract String getString(String directory, String key, String defaultValue);\r
+       \r
+       public abstract void putString(String directory, String key, String value);\r
+       \r
        /*\r
         * ******************************************************************************************\r
         */\r
@@ -173,7 +177,7 @@ public abstract class Preferences {
                        putString(key, value.name());\r
                }\r
        }\r
-\r
+       \r
        public Color getDefaultColor(Class<? extends RocketComponent> c) {\r
                String color = get("componentColors", c, DEFAULT_COLORS);\r
                if (color == null)\r
@@ -192,8 +196,8 @@ public abstract class Preferences {
                        return;\r
                putString("componentColors", c.getSimpleName(), stringifyColor(color));\r
        }\r
-\r
-\r
+       \r
+       \r
        /**\r
         * Retrieve a Line style for the given component.\r
         * @param c\r
@@ -262,16 +266,16 @@ public abstract class Preferences {
                putString("componentMaterials", componentClass.getSimpleName(),\r
                                material == null ? null : material.toStorableString());\r
        }\r
-\r
+       \r
        /**\r
         * get a net.sf.openrocket.util.Color object for the given key.\r
         * @param key\r
         * @param defaultValue\r
         * @return\r
         */\r
-       public final Color getColor( String key, Color defaultValue ) {\r
-               Color c = parseColor( getString(key,null) );\r
-               if ( c == null ) {\r
+       public final Color getColor(String key, Color defaultValue) {\r
+               Color c = parseColor(getString(key, null));\r
+               if (c == null) {\r
                        return defaultValue;\r
                }\r
                return c;\r
@@ -282,10 +286,10 @@ public abstract class Preferences {
         * @param key\r
         * @param value\r
         */\r
-       public final void putColor( String key, Color value ) {\r
-               putString( key, stringifyColor(value) );\r
+       public final void putColor(String key, Color value) {\r
+               putString(key, stringifyColor(value));\r
        }\r
-\r
+       \r
        /**\r
         * Helper function to convert a string representation into a net.sf.openrocket.util.Color object.\r
         * @param color\r
@@ -319,7 +323,7 @@ public abstract class Preferences {
                String string = color.getRed() + "," + color.getGreen() + "," + color.getBlue();\r
                return string;\r
        }\r
-\r
+       \r
        /**\r
         * Special helper function which allows for a map of default values.\r
         * \r
@@ -358,11 +362,17 @@ public abstract class Preferences {
                \r
                return null;\r
        }\r
-\r
+       \r
        public abstract void addUserMaterial(Material m);\r
+       \r
        public abstract Set<Material> getUserMaterials();\r
+       \r
        public abstract void removeUserMaterial(Material m);\r
-\r
+       \r
+       public abstract void setComponentFavorite(ComponentPreset preset, ComponentPreset.Type type, boolean favorite);\r
+       \r
+       public abstract Set<String> getComponentFavorites(ComponentPreset.Type type);\r
+       \r
        /*\r
         * Map of default line styles\r
         */\r
@@ -377,18 +387,9 @@ public abstract class Preferences {
         * Within a holder class so they will load only when needed.\r
         */\r
        private static class DefaultMaterialHolder {\r
-               private static final Translator trans = Application.getTranslator();\r
-               \r
-               //// Elastic cord (round 2mm, 1/16 in)\r
-               private static final Material DEFAULT_LINE_MATERIAL =\r
-                               Databases.findMaterial(Material.Type.LINE, trans.get("Databases.materials.Elasticcordround2mm"),\r
-                                               0.0018, false);\r
-               //// Ripstop nylon\r
-               private static final Material DEFAULT_SURFACE_MATERIAL =\r
-                               Databases.findMaterial(Material.Type.SURFACE, trans.get("Databases.materials.Ripstopnylon"), 0.067, false);\r
-               //// Cardboard\r
-               private static final Material DEFAULT_BULK_MATERIAL =\r
-                               Databases.findMaterial(Material.Type.BULK, trans.get("Databases.materials.Cardboard"), 680, false);\r
+               private static final Material DEFAULT_LINE_MATERIAL = Databases.findMaterial(Material.Type.LINE, "Elastic cord (round 2 mm, 1/16 in)");\r
+               private static final Material DEFAULT_SURFACE_MATERIAL = Databases.findMaterial(Material.Type.SURFACE, "Ripstop nylon");\r
+               private static final Material DEFAULT_BULK_MATERIAL = Databases.findMaterial(Material.Type.BULK, "Cardboard");\r
        }\r
        \r
        private static final HashMap<Class<?>, String> DEFAULT_COLORS =\r
@@ -402,6 +403,6 @@ public abstract class Preferences {
                DEFAULT_COLORS.put(RecoveryDevice.class, "255,0,0");\r
        }\r
        \r
-\r
-\r
+       \r
+       \r
 }\r
index d288ea76f660a8bd3f7a84e0ba34bc305bbe92a9..31f83184ad18c4026973e4f2d3919ce2fc0f0bfb 100644 (file)
@@ -38,7 +38,6 @@ public class Startup {
        
        private static final int LOG_BUFFER_LENGTH = 50;
        
-       
        /**
         * OpenRocket startup main method.
         */
@@ -54,13 +53,12 @@ public class Startup {
                
                // Setup the translations
                initializeL10n();
-               
+
                // Continue startup in Startup2 class (where Application is already set up)
                Startup2.runMain(args);
                
        }
        
-       
 
        /**
         * Set proper system properties if openrocket.debug is defined.
@@ -86,7 +84,7 @@ public class Startup {
        /**
         * Initializes the loggins system.
         */
-       private static void initializeLogging() {
+       public static void initializeLogging() {
                DelegatorLogger delegator = new DelegatorLogger();
                
                // Log buffer
index 11ceb19049f523e7a7741d09c61c664309d205f1..6b7b49cdfc962aa351b6321b77f44831a8006788 100644 (file)
@@ -4,31 +4,24 @@ import java.awt.GraphicsEnvironment;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.io.File;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.swing.SwingUtilities;
 import javax.swing.Timer;
 import javax.swing.ToolTipManager;
 
+import net.sf.openrocket.arch.SystemInfo;
+import net.sf.openrocket.arch.SystemInfo.Platform;
 import net.sf.openrocket.communication.UpdateInfo;
 import net.sf.openrocket.communication.UpdateInfoRetriever;
+import net.sf.openrocket.database.ComponentPresetDatabase;
 import net.sf.openrocket.database.Databases;
-import net.sf.openrocket.database.ThrustCurveMotorSet;
-import net.sf.openrocket.database.ThrustCurveMotorSetDatabase;
-import net.sf.openrocket.file.iterator.DirectoryIterator;
-import net.sf.openrocket.file.iterator.FileIterator;
-import net.sf.openrocket.file.motor.MotorLoaderHelper;
 import net.sf.openrocket.gui.dialogs.UpdateInfoDialog;
 import net.sf.openrocket.gui.main.BasicFrame;
 import net.sf.openrocket.gui.main.Splash;
 import net.sf.openrocket.gui.main.SwingExceptionHandler;
 import net.sf.openrocket.gui.util.GUIUtil;
-import net.sf.openrocket.gui.util.SimpleFileFilter;
 import net.sf.openrocket.gui.util.SwingPreferences;
 import net.sf.openrocket.logging.LogHelper;
-import net.sf.openrocket.motor.Motor;
-import net.sf.openrocket.motor.ThrustCurveMotor;
 import net.sf.openrocket.util.BuildProperties;
 
 /**
@@ -43,11 +36,6 @@ public class Startup2 {
 
        private static final String THRUSTCURVE_DIRECTORY = "datafiles/thrustcurves/";
        
-       /** Block motor loading for this many milliseconds */
-       private static AtomicInteger blockLoading = new AtomicInteger(Integer.MAX_VALUE);
-       
-       
-
        /**
         * Run when starting up OpenRocket after Application has been set up.
         * 
@@ -66,6 +54,11 @@ public class Startup2 {
                VersionHelper.checkVersion();
                VersionHelper.checkOpenJDK();
                
+               // If running on a MAC set up OSX UI Elements.
+               if ( SystemInfo.getPlatform() == Platform.MAC_OS ){
+                       OSXStartup.setupOSX();
+               }
+               
                // Run the actual startup method in the EDT since it can use progress dialogs etc.
                log.info("Moving startup to EDT");
                SwingUtilities.invokeAndWait(new Runnable() {
@@ -90,6 +83,25 @@ public class Startup2 {
                log.info("Initializing the splash screen");
                Splash.init();
                
+               // Must be done after localization is initialized
+               ComponentPresetDatabase componentPresetDao = new ComponentPresetDatabase(true) {
+
+                       @Override
+                       protected void load() {
+                               ConcurrentComponentPresetDatabaseLoader presetLoader = new ConcurrentComponentPresetDatabaseLoader( this );
+                               presetLoader.load();
+                               try {
+                                       presetLoader.await();
+                               } catch ( InterruptedException iex) {
+                                       
+                               }
+                       }
+                       
+               };
+               Application.setComponentPresetDao( componentPresetDao );
+
+               componentPresetDao.startLoading();
+               
                // Setup the uncaught exception handler
                log.info("Registering exception handler");
                SwingExceptionHandler exceptionHandler = new SwingExceptionHandler();
@@ -119,9 +131,12 @@ public class Startup2 {
                
                // Load motors etc.
                log.info("Loading databases");
+               
                loadMotor();
+               
                Databases.fakeMethod();
                
+
                // Starting action (load files or open new document)
                log.info("Opening main application window");
                if (!handleCommandLine(args)) {
@@ -132,10 +147,16 @@ public class Startup2 {
                log.info("Checking update status");
                checkUpdateStatus(updateInfo);
                
-               // Block motor loading for 1.5 seconds to allow window painting to be faster
-               blockLoading.set(1500);
        }
        
+       /**
+        * this method is useful for the python bindings.
+        */
+       public static void loadMotor() {
+               ConcurrentLoadingThrustCurveMotorSetDatabase motorLoader = new ConcurrentLoadingThrustCurveMotorSetDatabase(THRUSTCURVE_DIRECTORY);
+               motorLoader.startLoading();
+               Application.setMotorSetDatabase(motorLoader);
+       }
        
        /**
         * Check that the JRE is not running headless.
@@ -154,78 +175,6 @@ public class Startup2 {
        }
        
        
-       private static void loadMotor() {
-               
-               log.info("Starting motor loading from " + THRUSTCURVE_DIRECTORY + " in background thread.");
-               ThrustCurveMotorSetDatabase db = new ThrustCurveMotorSetDatabase(true) {
-                       
-                       @Override
-                       protected void loadMotors() {
-                               
-                               // Block loading until timeout occurs or database is taken into use
-                               log.info("Blocking motor loading while starting up");
-                               while (!inUse && blockLoading.addAndGet(-100) > 0) {
-                                       try {
-                                               Thread.sleep(100);
-                                       } catch (InterruptedException e) {
-                                       }
-                               }
-                               log.info("Blocking ended, inUse=" + inUse + " blockLoading=" + blockLoading.get());
-                               
-                               // Start loading
-                               log.info("Loading motors from " + THRUSTCURVE_DIRECTORY);
-                               long t0 = System.currentTimeMillis();
-                               int fileCount;
-                               int thrustCurveCount;
-                               
-                               // Load the packaged thrust curves
-                               List<Motor> list;
-                               FileIterator iterator = DirectoryIterator.findDirectory(THRUSTCURVE_DIRECTORY,
-                                                               new SimpleFileFilter("", false, "eng", "rse"));
-                               if (iterator == null) {
-                                       throw new IllegalStateException("Thrust curve directory " + THRUSTCURVE_DIRECTORY +
-                                                       "not found, distribution built wrong");
-                               }
-                               list = MotorLoaderHelper.load(iterator);
-                               for (Motor m : list) {
-                                       this.addMotor((ThrustCurveMotor) m);
-                               }
-                               fileCount = iterator.getFileCount();
-                               
-                               thrustCurveCount = list.size();
-                               
-                               // Load the user-defined thrust curves
-                               for (File file : ((SwingPreferences) Application.getPreferences()).getUserThrustCurveFiles()) {
-                                       log.info("Loading motors from " + file);
-                                       list = MotorLoaderHelper.load(file);
-                                       for (Motor m : list) {
-                                               this.addMotor((ThrustCurveMotor) m);
-                                       }
-                                       fileCount++;
-                                       thrustCurveCount += list.size();
-                               }
-                               
-                               long t1 = System.currentTimeMillis();
-                               
-                               // Count statistics
-                               int distinctMotorCount = 0;
-                               int distinctThrustCurveCount = 0;
-                               distinctMotorCount = motorSets.size();
-                               for (ThrustCurveMotorSet set : motorSets) {
-                                       distinctThrustCurveCount += set.getMotorCount();
-                               }
-                               log.info("Motor loading done, took " + (t1 - t0) + " ms to load "
-                                               + fileCount + " files/directories containing "
-                                               + thrustCurveCount + " thrust curves which contained "
-                                               + distinctMotorCount + " distinct motors with "
-                                               + distinctThrustCurveCount + " distinct thrust curves.");
-                       }
-                       
-               };
-               db.startLoading();
-               Application.setMotorSetDatabase(db);
-       }
-       
        private static void checkUpdateStatus(final UpdateInfoRetriever updateInfo) {
                if (updateInfo == null)
                        return;
index 097f1dc43c2d64ce6f16ced5dff95e04ce89cb25..0b3d91829e309d0ce9719a7646b1d15c39bf3750 100644 (file)
@@ -1,6 +1,7 @@
 package net.sf.openrocket.startup;
 
 import java.awt.GraphicsEnvironment;
+import java.util.Locale;
 
 import javax.swing.JOptionPane;
 
@@ -59,8 +60,8 @@ public class VersionHelper {
         */
        static void checkOpenJDK() {
                
-               if (System.getProperty("java.runtime.name", "").toLowerCase().indexOf("icedtea") >= 0 ||
-                               System.getProperty("java.vm.name", "").toLowerCase().indexOf("openjdk") >= 0) {
+               if (System.getProperty("java.runtime.name", "").toLowerCase(Locale.ENGLISH).indexOf("icedtea") >= 0 ||
+                               System.getProperty("java.vm.name", "").toLowerCase(Locale.ENGLISH).indexOf("openjdk") >= 0) {
                        
                        String jreName = System.getProperty("java.vm.name", "(unknown)");
                        String jreVersion = System.getProperty("java.runtime.version", "(unknown)");
@@ -79,7 +80,7 @@ public class VersionHelper {
        }
        
        
-
+       
        ///////////  Helper methods  //////////
        
        /**
@@ -97,7 +98,7 @@ public class VersionHelper {
                }
                System.err.println();
                
-
+               
                if (!GraphicsEnvironment.isHeadless()) {
                        
                        JOptionPane.showMessageDialog(null, message, "Error starting OpenRocket",
diff --git a/core/src/net/sf/openrocket/unit/FixedUnitGroup.java b/core/src/net/sf/openrocket/unit/FixedUnitGroup.java
new file mode 100644 (file)
index 0000000..8cb6fde
--- /dev/null
@@ -0,0 +1,35 @@
+package net.sf.openrocket.unit;
+
+/*
+ * This class provides a 'dumb' version of UnitGroup
+ * It allows any arbitrary unit to be created. It doesn't store any value and can't be converted into anything else.
+ * This is useful for custom expression units.
+ * 
+ * @author Richard Graham
+ */
+
+public class FixedUnitGroup extends UnitGroup {
+       
+       String unitString;
+       
+       public FixedUnitGroup( String unitString ){
+               this.unitString = unitString; 
+       }
+       
+       public int getUnitCount(){
+               return 1;
+       }
+       
+       public Unit getDefaultUnit(){
+               return new GeneralUnit(1, unitString);
+       }
+       
+       public Unit getSIUnit(){
+               return new GeneralUnit(1, unitString);
+       }
+       
+       public boolean contains(Unit u){
+               return true;
+       }
+       
+}
diff --git a/core/src/net/sf/openrocket/unit/FractionalUnit.java b/core/src/net/sf/openrocket/unit/FractionalUnit.java
new file mode 100644 (file)
index 0000000..740e477
--- /dev/null
@@ -0,0 +1,245 @@
+package net.sf.openrocket.unit;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+
+import net.sf.openrocket.util.Chars;
+
+public class FractionalUnit extends Unit {
+       
+       private final static char FRACTION = Chars.FRACTION;
+       
+       private final static String[] NUMERATOR = {
+                       "\u2070", // 0
+                       "\u00B9", // 1
+                       "\u00B2", // 2
+                       "\u00B3", // 3
+                       "\u2074", // 4
+                       "\u2075", // 5
+                       "\u2076", // 6
+                       "\u2077", // 7
+                       "\u2078", // 8
+                       "\u2079" // 9
+       };
+       
+       private final static String[] DENOMINATOR = {
+                       "\u2080", // 0
+                       "\u2081", // 1
+                       "\u2082", // 2
+                       "\u2083", // 3
+                       "\u2084", // 4
+                       "\u2085", // 5
+                       "\u2086", // 6
+                       "\u2087", // 7
+                       "\u2088", // 8
+                       "\u2089" // 9
+       };
+       
+       // This is the base of the fractions.  ie, 16d for 1/16ths.
+       private final int fractionBase;
+       // This is 1d/fractionBase;
+       private final double fractionValue;
+       
+       // This is the value used when incrementing/decrementing.
+       private final double incrementValue;
+       
+       // If the actual value differs from the decimal representation by more than this,
+       // we display as decimals.
+       private final double epsilon;
+       
+       private final String unitLabel;
+       
+       public FractionalUnit(double multiplier, String unit, String unitLabel, int fractionBase, double incrementValue) {
+               this(multiplier, unit, unitLabel, fractionBase, incrementValue, 0.1d / fractionBase);
+       }
+       
+       public FractionalUnit(double multiplier, String unit, String unitLabel, int fractionBase, double incrementValue, double epsilon) {
+               super(multiplier, unit);
+               this.unitLabel = unitLabel;
+               this.fractionBase = fractionBase;
+               this.fractionValue = 1.0d / fractionBase;
+               this.incrementValue = incrementValue;
+               this.epsilon = epsilon;
+       }
+       
+       @Override
+       public double round(double value) {
+               return roundTo(value, fractionValue);
+       }
+       
+       private double roundTo(double value, double fraction) {
+               double remainder = Math.IEEEremainder(value, fraction);
+               return value - remainder;
+       }
+       
+       @Override
+       public double getNextValue(double value) {
+               double rounded = roundTo(value, incrementValue);
+               if (rounded <= value + epsilon) {
+                       rounded += incrementValue;
+               }
+               return rounded;
+       }
+       
+       @Override
+       public double getPreviousValue(double value) {
+               double rounded = roundTo(value, incrementValue);
+               if (rounded >= value - epsilon) {
+                       rounded -= incrementValue;
+               }
+               return rounded;
+       }
+       
+       @Override
+       public Tick[] getTicks(double start, double end, double minor, double major) {
+               // Convert values
+               start = toUnit(start);
+               end = toUnit(end);
+               minor = toUnit(minor);
+               major = toUnit(major);
+               
+               if (minor <= 0 || major <= 0 || major < minor) {
+                       throw new IllegalArgumentException("getTicks called with minor=" + minor + " major=" + major);
+               }
+               
+               ArrayList<Tick> ticks = new ArrayList<Tick>();
+               
+               int mod2, mod3, mod4; // Moduli for minor-notable, major-nonnotable, major-notable
+               double minstep;
+               
+               // Find the smallest possible step size
+               double one = 1;
+               while (one > minor)
+                       one /= 2;
+               while (one < minor)
+                       one *= 2;
+               minstep = one;
+               mod2 = 16;
+               
+               // Find step size for major ticks
+               one = 1;
+               while (one > major)
+                       one /= 10;
+               while (one < major)
+                       one *= 10;
+               if (one / 2 >= major) {
+                       // major step is round-five, major-notable is next round-ten
+                       double majorstep = one / 2;
+                       mod3 = (int) Math.round(majorstep / minstep);
+                       mod4 = mod3 * 2;
+               } else {
+                       // major step is round-ten, major-notable is next round-ten
+                       mod3 = (int) Math.round(one / minstep);
+                       mod4 = mod3 * 10;
+               }
+               // Check for clashes between minor-notable and major-nonnotable
+               if (mod3 == mod2) {
+                       if (mod2 == 2)
+                               mod2 = 1; // Every minor tick is notable
+                       else
+                               mod2 = 5; // Every fifth minor tick is notable
+               }
+               
+               
+               // Calculate starting position
+               int pos = (int) Math.ceil(start / minstep);
+               //              System.out.println("mod2="+mod2+" mod3="+mod3+" mod4="+mod4);
+               while (pos * minstep <= end) {
+                       double unitValue = pos * minstep;
+                       double value = fromUnit(unitValue);
+                       
+                       if (pos % mod4 == 0)
+                               ticks.add(new Tick(value, unitValue, true, true));
+                       else if (pos % mod3 == 0)
+                               ticks.add(new Tick(value, unitValue, true, false));
+                       else if (pos % mod2 == 0)
+                               ticks.add(new Tick(value, unitValue, false, true));
+                       else
+                               ticks.add(new Tick(value, unitValue, false, false));
+                       
+                       pos++;
+               }
+               
+               return ticks.toArray(new Tick[0]);
+       }
+       
+       
+       @Override
+       public String toString(double value) {
+               
+               double correctVal = toUnit(value);
+               double val = round(correctVal);
+               
+               
+               if (Math.abs(val - correctVal) > epsilon) {
+                       NumberFormat decFormat = new DecimalFormat("#.###");
+                       return decFormat.format(correctVal);
+               }
+               
+               NumberFormat intFormat = new DecimalFormat("#");
+               double sign = Math.signum(val);
+               
+               double posValue = sign * val;
+               
+               double intPart = Math.floor(posValue);
+               
+               double frac = Math.rint((posValue - intPart) / fractionValue);
+               double fracBase = fractionBase;
+               
+               // Reduce fraction.
+               while (frac > 0 && fracBase > 2 && frac % 2 == 0) {
+                       frac /= 2.0;
+                       fracBase /= 2.0;
+               }
+               
+               posValue *= sign;
+               
+               if (frac == 0.0) {
+                       return intFormat.format(posValue);
+               } else if (intPart == 0.0) {
+                       return (sign < 0 ? "-" : "") + numeratorString(Double.valueOf(frac).intValue())
+                                       + FRACTION + denominatorString(Double.valueOf(fracBase).intValue());
+               } else {
+                       return intFormat.format(sign * intPart) + " " + numeratorString(Double.valueOf(frac).intValue())
+                                       + FRACTION + denominatorString(Double.valueOf(fracBase).intValue());
+               }
+               
+       }
+       
+       private String numeratorString(int value) {
+               
+               String rep = "";
+               if (value == 0) {
+                       return "0";
+               }
+               while (value > 0) {
+                       rep = NUMERATOR[value % 10] + rep;
+                       value = value / 10;
+               }
+               return rep;
+       }
+       
+       private String denominatorString(int value) {
+               String rep = "";
+               if (value == 0) {
+                       return "0";
+               }
+               while (value > 0) {
+                       rep = DENOMINATOR[value % 10] + rep;
+                       value = value / 10;
+               }
+               return rep;
+       }
+       
+       @Override
+       public String toStringUnit(double value) {
+               if (Double.isNaN(value))
+                       return "N/A";
+               
+               String s = toString(value);
+               s += " " + unitLabel;
+               return s;
+       }
+       
+}
index 4703b31b4481f3ac31c8334085138a5253e960a4..dda76944372419fd17d42d203c854e0ffbea4ca6 100644 (file)
@@ -70,42 +70,6 @@ public abstract class Unit {
                return true;
        }
        
-       
-       // Testcases for toString(double)
-       public static void main(String arg[]) {
-               System.out.println(NOUNIT2.toString(0.0049));
-               System.out.println(NOUNIT2.toString(0.0050));
-               System.out.println(NOUNIT2.toString(0.0051));
-               System.out.println(NOUNIT2.toString(0.00123));
-               System.out.println(NOUNIT2.toString(0.0123));
-               System.out.println(NOUNIT2.toString(0.1234));
-               System.out.println(NOUNIT2.toString(1.2345));
-               System.out.println(NOUNIT2.toString(12.345));
-               System.out.println(NOUNIT2.toString(123.456));
-               System.out.println(NOUNIT2.toString(1234.5678));
-               System.out.println(NOUNIT2.toString(12345.6789));
-               System.out.println(NOUNIT2.toString(123456.789));
-               System.out.println(NOUNIT2.toString(1234567.89));
-               System.out.println(NOUNIT2.toString(12345678.9));
-               
-               System.out.println(NOUNIT2.toString(-0.0049));
-               System.out.println(NOUNIT2.toString(-0.0050));
-               System.out.println(NOUNIT2.toString(-0.0051));
-               System.out.println(NOUNIT2.toString(-0.00123));
-               System.out.println(NOUNIT2.toString(-0.0123));
-               System.out.println(NOUNIT2.toString(-0.1234));
-               System.out.println(NOUNIT2.toString(-1.2345));
-               System.out.println(NOUNIT2.toString(-12.345));
-               System.out.println(NOUNIT2.toString(-123.456));
-               System.out.println(NOUNIT2.toString(-1234.5678));
-               System.out.println(NOUNIT2.toString(-12345.6789));
-               System.out.println(NOUNIT2.toString(-123456.789));
-               System.out.println(NOUNIT2.toString(-1234567.89));
-               System.out.println(NOUNIT2.toString(-12345678.9));
-               
-       }
-       
-       
        @Override
        public String toString() {
                return unit;
@@ -115,6 +79,7 @@ public abstract class Unit {
        
        private static final DecimalFormat intFormat = new DecimalFormat("#");
        private static final DecimalFormat decFormat = new DecimalFormat("0.##");
+       private static final DecimalFormat smallFormat = new DecimalFormat("0.###");
        private static final DecimalFormat expFormat = new DecimalFormat("0.00E0");
        
        /**
@@ -134,9 +99,12 @@ public abstract class Unit {
                if (Math.abs(val) >= 100) {
                        return intFormat.format(val);
                }
-               if (Math.abs(val) <= 0.005) {
+               if (Math.abs(val) <= 0.0005) {
                        return "0";
                }
+               if ( Math.abs(val) < 0.095) {
+                       return smallFormat.format(val);
+               }
                
                double sign = Math.signum(val);
                val = Math.abs(val);
@@ -146,7 +114,6 @@ public abstract class Unit {
                        val *= 10;
                }
                val = Math.rint(val) / mul * sign;
-               
                return decFormat.format(val);
        }
        
index f72f22a970bc6435757882ad6b74778b45ad6ffa..48ae67a9ebe273f46d0280686c642db2ec78a117 100644 (file)
@@ -27,6 +27,7 @@ public class UnitGroup {
        
        public static final UnitGroup UNITS_MOTOR_DIMENSIONS;
        public static final UnitGroup UNITS_LENGTH;
+       public static final UnitGroup UNITS_ALL_LENGTHS;
        public static final UnitGroup UNITS_DISTANCE;
        
        public static final UnitGroup UNITS_AREA;
@@ -37,6 +38,7 @@ public class UnitGroup {
         */
        public static final UnitGroup UNITS_STABILITY_CALIBERS;
        public static final UnitGroup UNITS_VELOCITY;
+       public static final UnitGroup UNITS_WINDSPEED;
        public static final UnitGroup UNITS_ACCELERATION;
        public static final UnitGroup UNITS_MASS;
        public static final UnitGroup UNITS_INERTIA;
@@ -62,11 +64,17 @@ public class UnitGroup {
        public static final UnitGroup UNITS_ROUGHNESS;
        
        public static final UnitGroup UNITS_COEFFICIENT;
+       public static final UnitGroup UNITS_FREQUENCY;
        
-       //      public static final UnitGroup UNITS_FREQUENCY;
+       public static final UnitGroup UNITS_ENERGY;
+       public static final UnitGroup UNITS_POWER;
+       public static final UnitGroup UNITS_MOMENTUM;
+       public static final UnitGroup UNITS_VOLTAGE;
+       public static final UnitGroup UNITS_CURRENT;
        
        
-       public static final Map<String, UnitGroup> UNITS;
+       public static final Map<String, UnitGroup> UNITS; // keys such as "LENGTH", "VELOCITY"
+       public static final Map<String, UnitGroup> SIUNITS; // keys such a "m", "m/s"
        
        
        /*
@@ -79,15 +87,47 @@ public class UnitGroup {
                UNITS_NONE = new UnitGroup();
                UNITS_NONE.addUnit(Unit.NOUNIT2);
                
+               UNITS_ENERGY = new UnitGroup();
+               UNITS_ENERGY.addUnit(new GeneralUnit(1, "J"));
+               UNITS_ENERGY.addUnit(new GeneralUnit(1e-7, "erg"));
+               UNITS_ENERGY.addUnit(new GeneralUnit(1.055, "BTU"));
+               UNITS_ENERGY.addUnit(new GeneralUnit(4.184, "cal"));
+               UNITS_ENERGY.addUnit(new GeneralUnit(1.3558179483314, "ft"+DOT+"lbf"));
+               UNITS_ENERGY.setDefaultUnit(0);
+               
+               UNITS_POWER = new UnitGroup();
+               UNITS_POWER.addUnit(new GeneralUnit(1e-3, "mW"));
+               UNITS_POWER.addUnit(new GeneralUnit(1, "W"));
+               UNITS_POWER.addUnit(new GeneralUnit(1e3, "kW"));
+               UNITS_POWER.addUnit(new GeneralUnit(1e-7, "ergs"));
+               UNITS_POWER.addUnit(new GeneralUnit(745.699872, "hp"));
+               UNITS_POWER.setDefaultUnit(1);
+               
+               UNITS_MOMENTUM = new UnitGroup();
+               UNITS_MOMENTUM.addUnit(new GeneralUnit(1, "kg"+DOT+"m/s"));
+               UNITS_MOMENTUM.setDefaultUnit(0);
+               
+               UNITS_VOLTAGE = new UnitGroup();
+               UNITS_VOLTAGE.addUnit(new GeneralUnit(1e-3, "mV"));
+               UNITS_VOLTAGE.addUnit(new GeneralUnit(1, "V"));
+               UNITS_VOLTAGE.setDefaultUnit(1);
+               
+               UNITS_CURRENT = new UnitGroup();
+               UNITS_CURRENT.addUnit(new GeneralUnit(1e-3, "mA"));
+               UNITS_CURRENT.addUnit(new GeneralUnit(1, "A"));
+               UNITS_CURRENT.setDefaultUnit(1);
+               
                UNITS_LENGTH = new UnitGroup();
                UNITS_LENGTH.addUnit(new GeneralUnit(0.001, "mm"));
                UNITS_LENGTH.addUnit(new GeneralUnit(0.01, "cm"));
                UNITS_LENGTH.addUnit(new GeneralUnit(1, "m"));
                UNITS_LENGTH.addUnit(new GeneralUnit(0.0254, "in"));
+               UNITS_LENGTH.addUnit(new FractionalUnit(0.0254, "in/64", "in", 64, 1d / 16d, 0.5d / 64d));
                UNITS_LENGTH.addUnit(new GeneralUnit(0.3048, "ft"));
                UNITS_LENGTH.setDefaultUnit(1);
                
                UNITS_MOTOR_DIMENSIONS = new UnitGroup();
+               UNITS_MOTOR_DIMENSIONS.addUnit(new GeneralUnit(1, "m")); // just added
                UNITS_MOTOR_DIMENSIONS.addUnit(new GeneralUnit(0.001, "mm"));
                UNITS_MOTOR_DIMENSIONS.addUnit(new GeneralUnit(0.01, "cm"));
                UNITS_MOTOR_DIMENSIONS.addUnit(new GeneralUnit(0.0254, "in"));
@@ -101,6 +141,19 @@ public class UnitGroup {
                UNITS_DISTANCE.addUnit(new GeneralUnit(1609.344, "mi"));
                UNITS_DISTANCE.addUnit(new GeneralUnit(1852, "nmi"));
                
+               UNITS_ALL_LENGTHS = new UnitGroup();
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(0.001, "mm"));
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(0.01, "cm"));
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(1, "m"));
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(1000, "km"));
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(0.0254, "in"));
+               UNITS_ALL_LENGTHS.addUnit(new FractionalUnit(0.0254, "in/64", "in", 64, 1d / 16d, 0.5d / 64d));
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(0.3048, "ft"));
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(0.9144, "yd"));
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(1609.344, "mi"));
+               UNITS_ALL_LENGTHS.addUnit(new GeneralUnit(1852, "nmi"));
+               UNITS_ALL_LENGTHS.setDefaultUnit(2);
+               
                UNITS_AREA = new UnitGroup();
                UNITS_AREA.addUnit(new GeneralUnit(pow2(0.001), "mm" + SQUARED));
                UNITS_AREA.addUnit(new GeneralUnit(pow2(0.01), "cm" + SQUARED));
@@ -111,6 +164,7 @@ public class UnitGroup {
                
                
                UNITS_STABILITY = new UnitGroup();
+               UNITS_STABILITY.addUnit(new GeneralUnit(1, "m"));
                UNITS_STABILITY.addUnit(new GeneralUnit(0.001, "mm"));
                UNITS_STABILITY.addUnit(new GeneralUnit(0.01, "cm"));
                UNITS_STABILITY.addUnit(new GeneralUnit(0.0254, "in"));
@@ -127,6 +181,12 @@ public class UnitGroup {
                UNITS_VELOCITY.addUnit(new GeneralUnit(0.3048, "ft/s"));
                UNITS_VELOCITY.addUnit(new GeneralUnit(0.44704, "mph"));
                
+               UNITS_WINDSPEED = new UnitGroup();
+               UNITS_WINDSPEED.addUnit(new GeneralUnit(1, "m/s"));
+               UNITS_WINDSPEED.addUnit(new GeneralUnit(1 / 3.6, "km/h"));
+               UNITS_WINDSPEED.addUnit(new GeneralUnit(0.3048, "ft/s"));
+               UNITS_WINDSPEED.addUnit(new GeneralUnit(0.44704, "mph"));
+               
                UNITS_ACCELERATION = new UnitGroup();
                UNITS_ACCELERATION.addUnit(new GeneralUnit(1, "m/s" + SQUARED));
                UNITS_ACCELERATION.addUnit(new GeneralUnit(0.3048, "ft/s" + SQUARED));
@@ -154,6 +214,7 @@ public class UnitGroup {
                
                UNITS_DENSITY_BULK = new UnitGroup();
                UNITS_DENSITY_BULK.addUnit(new GeneralUnit(1000, "g/cm" + CUBED));
+               UNITS_DENSITY_BULK.addUnit(new GeneralUnit(1000, "kg/dm" + CUBED));
                UNITS_DENSITY_BULK.addUnit(new GeneralUnit(1, "kg/m" + CUBED));
                UNITS_DENSITY_BULK.addUnit(new GeneralUnit(1729.99404, "oz/in" + CUBED));
                UNITS_DENSITY_BULK.addUnit(new GeneralUnit(16.0184634, "lb/ft" + CUBED));
@@ -225,6 +286,7 @@ public class UnitGroup {
                
                
                UNITS_ROUGHNESS = new UnitGroup();
+               UNITS_ROUGHNESS.addUnit(new GeneralUnit(1, "m")); // just added
                UNITS_ROUGHNESS.addUnit(new GeneralUnit(0.000001, MICRO + "m"));
                UNITS_ROUGHNESS.addUnit(new GeneralUnit(0.0000254, "mil"));
                
@@ -234,18 +296,20 @@ public class UnitGroup {
                
                
                // This is not used by OpenRocket, and not extensively tested:
-               //              UNITS_FREQUENCY = new UnitGroup();
+               UNITS_FREQUENCY = new UnitGroup();
                //              UNITS_FREQUENCY.addUnit(new GeneralUnit(1, "s"));
                //              UNITS_FREQUENCY.addUnit(new GeneralUnit(0.001, "ms"));
                //              UNITS_FREQUENCY.addUnit(new GeneralUnit(0.000001, MICRO + "s"));
-               //              UNITS_FREQUENCY.addUnit(new FrequencyUnit(1, "Hz"));
-               //              UNITS_FREQUENCY.addUnit(new FrequencyUnit(1000, "kHz"));
-               //              UNITS_FREQUENCY.setDefaultUnit(3);
+               UNITS_FREQUENCY.addUnit(new FrequencyUnit(.001, "mHz"));
+               UNITS_FREQUENCY.addUnit(new FrequencyUnit(1, "Hz"));
+               UNITS_FREQUENCY.addUnit(new FrequencyUnit(1000, "kHz"));
+               UNITS_FREQUENCY.setDefaultUnit(1);
                
                
                HashMap<String, UnitGroup> map = new HashMap<String, UnitGroup>();
                map.put("NONE", UNITS_NONE);
                map.put("LENGTH", UNITS_LENGTH);
+               map.put("ALL_LENGTHS", UNITS_ALL_LENGTHS);
                map.put("MOTOR_DIMENSIONS", UNITS_MOTOR_DIMENSIONS);
                map.put("DISTANCE", UNITS_DISTANCE);
                map.put("VELOCITY", UNITS_VELOCITY);
@@ -269,8 +333,36 @@ public class UnitGroup {
                map.put("RELATIVE", UNITS_RELATIVE);
                map.put("ROUGHNESS", UNITS_ROUGHNESS);
                map.put("COEFFICIENT", UNITS_COEFFICIENT);
+               map.put("VOLTAGE", UNITS_VOLTAGE);
+               map.put("CURRENT", UNITS_CURRENT);
+               map.put("ENERGY", UNITS_ENERGY);
+               map.put("POWER", UNITS_POWER);
+               map.put("MOMENTUM", UNITS_MOMENTUM);
+               map.put("FREQUENCY", UNITS_FREQUENCY);
                
                UNITS = Collections.unmodifiableMap(map);
+               
+               HashMap<String, UnitGroup> simap = new HashMap<String, UnitGroup>();
+               simap.put("m", UNITS_ALL_LENGTHS);
+               simap.put("m^2", UNITS_AREA);
+               simap.put("m/s", UNITS_VELOCITY);
+               simap.put("m/s^2", UNITS_ACCELERATION); 
+               simap.put("kg", UNITS_MASS);
+               simap.put("kg m^2", UNITS_INERTIA);
+               simap.put("kg/m^3", UNITS_DENSITY_BULK);
+               simap.put("N", UNITS_FORCE);
+               simap.put("Ns", UNITS_IMPULSE);
+               simap.put("s", UNITS_FLIGHT_TIME);
+               simap.put("Pa", UNITS_PRESSURE);
+               simap.put("V", UNITS_VOLTAGE);
+               simap.put("A", UNITS_CURRENT);
+               simap.put("J", UNITS_ENERGY);
+               simap.put("W", UNITS_POWER);
+               simap.put("kg m/s", UNITS_MOMENTUM);
+               simap.put("Hz", UNITS_FREQUENCY);
+               simap.put("K", UNITS_TEMPERATURE);
+               
+               SIUNITS = Collections.unmodifiableMap(simap);
        }
        
        public static void setDefaultMetricUnits() {
@@ -293,6 +385,7 @@ public class UnitGroup {
                UNITS_FLIGHT_TIME.setDefaultUnit("s");
                UNITS_ROLL.setDefaultUnit("r/s");
                UNITS_TEMPERATURE.setDefaultUnit(DEGREE + "C");
+               UNITS_WINDSPEED.setDefaultUnit("m/s");
                UNITS_PRESSURE.setDefaultUnit("mbar");
                UNITS_RELATIVE.setDefaultUnit("%");
                UNITS_ROUGHNESS.setDefaultUnit(MICRO + "m");
@@ -318,6 +411,7 @@ public class UnitGroup {
                UNITS_FLIGHT_TIME.setDefaultUnit("s");
                UNITS_ROLL.setDefaultUnit("r/s");
                UNITS_TEMPERATURE.setDefaultUnit(DEGREE + "F");
+               UNITS_WINDSPEED.setDefaultUnit("mph");
                UNITS_PRESSURE.setDefaultUnit("mbar");
                UNITS_RELATIVE.setDefaultUnit("%");
                UNITS_ROUGHNESS.setDefaultUnit("mil");
@@ -382,7 +476,14 @@ public class UnitGroup {
                defaultUnit = n;
        }
        
-       
+       public Unit getSIUnit(){
+               for (Unit u : units){
+                       if (u.multiplier == 1){
+                               return u;
+                       }
+               }
+               return UNITS_NONE.getDefaultUnit();
+       }
        
        /**
         * Find a unit by approximate unit name.  Only letters and (ordinary) numbers are
@@ -419,6 +520,14 @@ public class UnitGroup {
                throw new IllegalArgumentException("name=" + name);
        }
        
+       public Unit getUnit(String name) throws IllegalArgumentException {
+               for (int i = 0; i < units.size(); i++) {
+                       if (units.get(i).getUnit().equals(name)) {
+                               return units.get(i);
+                       }
+               }
+               throw new IllegalArgumentException("name=" + name);
+       }
        
        public Unit getUnit(int n) {
                return units.get(n);
@@ -440,6 +549,17 @@ public class UnitGroup {
                return units.toArray(new Unit[0]);
        }
        
+       /**
+        * Return the value in SI units from the default unit of this group.
+        * It is the same as calling <code>getDefaultUnit().fromUnit(value)</code>
+        * 
+        * @param value the default unit value to convert
+        * @return the value in SI units.
+        * @see Unit#fromUnit(double)
+        */
+       public double fromUnit( double value ) {
+               return this.getDefaultUnit().fromUnit(value);
+       }
        
        /**
         * Return the value formatted by the default unit of this group.
@@ -480,7 +600,28 @@ public class UnitGroup {
                return this.getDefaultUnit().toValue(value);
        }
        
+       @Override
+       public String toString(){
+               return this.getClass().getSimpleName()+":"+this.getSIUnit().toString();
+       }
        
+       @Override
+       public boolean equals(Object o){
+               UnitGroup u = (UnitGroup) o;
+               int size = units.size();
+               if (size != u.units.size()){
+                       return false;
+               }
+               
+               for (int i=0; i<size; i++){
+                       if ( !units.get(i).equals(u.units.get(i)) ){
+                               return false;
+                       }
+               }
+               
+               return true;
+                       
+       }
        
        
        private static final Pattern STRING_PATTERN = Pattern.compile("^\\s*([0-9.,-]+)(.*?)$");
@@ -531,6 +672,15 @@ public class UnitGroup {
        ///////////////////////////
        
        
+       @Override
+       public int hashCode() {
+               int code = 0;
+               for (Unit u : units){
+                       code = code + u.hashCode();
+               }
+               return code;
+       }
+
        /**
         * A private class that switches the CaliberUnit to a rocket-specific CaliberUnit.
         * All other methods are passed through to UNITS_STABILITY.
diff --git a/core/src/net/sf/openrocket/util/AlphanumComparator.java b/core/src/net/sf/openrocket/util/AlphanumComparator.java
new file mode 100644 (file)
index 0000000..c7a7b48
--- /dev/null
@@ -0,0 +1,139 @@
+/*\r
+ * The Alphanum Algorithm is an improved sorting algorithm for strings\r
+ * containing numbers.  Instead of sorting numbers in ASCII order like\r
+ * a standard sort, this algorithm sorts numbers in numeric order.\r
+ *\r
+ * The Alphanum Algorithm is discussed at http://www.DaveKoelle.com\r
+ *\r
+ *\r
+ * This library is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU Lesser General Public\r
+ * License as published by the Free Software Foundation; either\r
+ * version 2.1 of the License, or any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
+ * Lesser General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public\r
+ * License along with this library; if not, write to the Free Software\r
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA\r
+ *\r
+ */\r
+\r
+/*\r
+ * Subsequently this code had been hacked up to make it genericized and support\r
+ * folding upper/lower case.\r
+ */\r
+package net.sf.openrocket.util;\r
+\r
+import java.text.Collator;\r
+import java.util.Comparator;\r
+\r
+/**\r
+ * This is an updated version with enhancements made by Daniel Migowski,\r
+ * Andre Bogus, and David Koelle\r
+ *\r
+ * To convert to use Templates (Java 1.5+):\r
+ *   - Change "implements Comparator" to "implements Comparator<String>"\r
+ *   - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)"\r
+ *   - Remove the type checking and casting in compare().\r
+ *\r
+ * To use this class:\r
+ *   Use the static "sort" method from the java.util.Collections class:\r
+ *   Collections.sort(your list, new AlphanumComparator());\r
+ */\r
+public class AlphanumComparator implements Comparator<String>\r
+{\r
+\r
+       private static final Collator sorter = Collator.getInstance();\r
+       static {\r
+               sorter.setStrength(Collator.TERTIARY);\r
+               sorter.setDecomposition(Collator.CANONICAL_DECOMPOSITION);\r
+       }\r
+\r
+       private final boolean isDigit(char ch)\r
+       {\r
+               return ch >= 48 && ch <= 57;\r
+       }\r
+\r
+       /** Length of string is passed in for improved efficiency (only need to calculate it once) **/\r
+       private final String getChunk(String s, int slength, int marker)\r
+       {\r
+               StringBuilder chunk = new StringBuilder();\r
+               char c = s.charAt(marker);\r
+               chunk.append(c);\r
+               marker++;\r
+               if (isDigit(c))\r
+               {\r
+                       while (marker < slength)\r
+                       {\r
+                               c = s.charAt(marker);\r
+                               if (!isDigit(c))\r
+                                       break;\r
+                               chunk.append(c);\r
+                               marker++;\r
+                       }\r
+               } else\r
+               {\r
+                       while (marker < slength)\r
+                       {\r
+                               c = s.charAt(marker);\r
+                               if (isDigit(c))\r
+                                       break;\r
+                               chunk.append(c);\r
+                               marker++;\r
+                       }\r
+               }\r
+               return chunk.toString();\r
+       }\r
+\r
+       @Override\r
+       public int compare(String s1, String s2)\r
+       {\r
+\r
+               int thisMarker = 0;\r
+               int thatMarker = 0;\r
+               int s1Length = s1.length();\r
+               int s2Length = s2.length();\r
+\r
+               while (thisMarker < s1Length && thatMarker < s2Length)\r
+               {\r
+                       String thisChunk = getChunk(s1, s1Length, thisMarker);\r
+                       thisMarker += thisChunk.length();\r
+\r
+                       String thatChunk = getChunk(s2, s2Length, thatMarker);\r
+                       thatMarker += thatChunk.length();\r
+\r
+                       // If both chunks contain numeric characters, sort them numerically\r
+                       int result = 0;\r
+                       if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0)))\r
+                       {\r
+                               // Simple chunk comparison by length.\r
+                               int thisChunkLength = thisChunk.length();\r
+                               result = thisChunkLength - thatChunk.length();\r
+                               // If equal, the first different number counts\r
+                               if (result == 0)\r
+                               {\r
+                                       for (int i = 0; i < thisChunkLength; i++)\r
+                                       {\r
+                                               result = thisChunk.charAt(i) - thatChunk.charAt(i);\r
+                                               if (result != 0)\r
+                                               {\r
+                                                       return result;\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } else\r
+                       {\r
+                               result = sorter.compare(thisChunk, thatChunk);\r
+                       }\r
+\r
+                       if (result != 0)\r
+                               return result;\r
+               }\r
+\r
+               return s1Length - s2Length;\r
+       }\r
+}\r
diff --git a/core/src/net/sf/openrocket/util/ArrayUtils.java b/core/src/net/sf/openrocket/util/ArrayUtils.java
new file mode 100644 (file)
index 0000000..d029394
--- /dev/null
@@ -0,0 +1,250 @@
+package net.sf.openrocket.util;
+
+import java.lang.reflect.Array;
+
+public class ArrayUtils {
+
+       /**
+        * Returns a double array with values from start to end with given step.
+        * Starts exactly at start and stops at the multiple of step <= stop. 
+        */
+       public static double[] range(double start, double stop, double step){
+               
+               int size = (int) Math.floor(((stop - start) / step)) + 1;
+               
+               //System.out.println("Range from "+start+" to "+stop+" step "+step+" has length "+size);
+               
+               double[] output = new double[size];
+               int i = 0;
+               double x = start;
+               while (i<size){
+                       output[i] = x;
+                       x = x+step;
+                       i++;
+               }
+               
+               return output;
+       }
+
+       /**
+        * Return the mean of an array
+        */
+       public static double mean(double[] vals){
+               double subtotal = 0;
+               for (int i = 0; i < vals.length; i++ ){
+                       if (!Double.isNaN(vals[i])){
+                               subtotal += vals[i];
+                       }
+               }
+               subtotal = subtotal / vals.length;
+               return subtotal;
+       }
+
+       /**
+        * Returns the maximum value in the array.
+        */
+
+       public static double max(double[] vals) {
+               double m = vals[0];
+               for (int i = 1; i < vals.length; i++)
+                       m = Math.max(m, vals[i]);
+               return m;
+       }
+
+       /**
+        * Returns the minimum value in the array.
+        */
+
+       public static double min(double[] vals) {
+               double m = vals[0];
+               for (int i = 1; i < vals.length; i++)
+                       m = Math.min(m, vals[i]);
+               return m;
+       }
+
+       /**
+        * Returns the variance of the array of doubles
+        */
+       public static double variance(double[] vals) {
+               double mu = mean(vals);
+               double sumsq = 0.0;
+               double temp = 0;
+               for (int i = 0; i < vals.length; i++){
+                       if (!Double.isNaN(vals[i])){
+                               temp = (mu - vals[i]);
+                               sumsq += temp*temp;
+                       }
+               }
+               return sumsq / (vals.length);
+       }
+
+       /**
+        * Returns the standard deviation of an array of doubles
+        */
+       public static double stdev(double[] vals) {
+               return Math.sqrt(variance(vals));
+       }
+       
+       /**
+        * Returns the RMS value of an array of doubles 
+        */
+       public static double rms(double[] vals) {
+               double m = mean(vals);
+               double s = stdev(vals);
+               return Math.sqrt( m*m + s*s );
+       }
+       
+       /**
+        * Returns the integral of a given array calculated by the trapezoidal rule
+        * dt is the time step between each array value. Any NaN values are treated as zero
+        */
+       public static double trapz(double[] y, double dt){
+               double stop = (y.length -1) * dt;
+               
+               if (y.length <= 1 || dt <= 0) return 0;
+               
+               double[] x = range(0, stop, dt);
+           
+           double sum = 0.0;
+           for (int i = 1; i < x.length; i++) {
+               double temp = (x[i] - x[i-1]) * (y[i] + y[i-1]);
+               if (!Double.isNaN(temp)){
+                       sum += temp;
+               }
+           }
+           return sum * 0.5;
+       }
+       
+       /**
+        * Returns the nearest value in an array to a given value
+        * Search starts from the lowest array index
+        */
+       public static double tnear(double[] range, double near, double start, double step){
+               double min = Double.POSITIVE_INFINITY;
+               int mini = 0;
+               
+               //System.out.println("Nearest to "+near+" in range length "+range.length);
+               for (int i=0; i < range.length; i++){
+                       double x = Math.abs(range[i] - near);
+                       if (x < min){
+                               min = x;
+                               mini = i;
+                       }
+               }
+               
+               //System.out.println("Found nearest at i="+mini);               
+               return start + (mini*step);
+       }
+       
+       
+       public static <T> T[] copyOf( T[] original, int length ) {
+               return copyOfRange(original,0,length);
+       }
+       
+       /**
+        * Implementation of java.util.Arrays.copyOfRange
+        * 
+        * Since Froyo does not include this function it must be implemented here.
+        * 
+        * @param original
+        * @param start
+        * @param end
+        * @return
+        */
+       public static <T> T[] copyOfRange( T[] original, int start, int end ) {
+               
+               if ( original == null ) {
+                       throw new NullPointerException();
+               }
+               
+               if ( start < 0 || start > original.length ) {
+                       throw new ArrayIndexOutOfBoundsException();
+               }
+               
+               if ( start > end ) {
+                       throw new IllegalArgumentException();
+               }
+               
+               T[] result = (T[]) Array.newInstance( original.getClass().getComponentType(), end-start );
+               
+               int index = 0;
+               int stop = original.length < end ? original.length : end;
+               for ( int i = start; i < stop; i ++ ) {
+                       if ( i < original.length ) {
+                               result[index] = original[i];
+                       }
+                       index++;
+               }
+               
+               return result;
+               
+       }
+
+       public static double[] copyOf( double[] original, int length ) {
+               return copyOfRange(original,0,length);
+       }
+       
+       public static double[] copyOfRange( double[] original, int start, int end ) {
+               
+               if ( original == null ) {
+                       throw new NullPointerException();
+               }
+               
+               if ( start < 0 || start > original.length ) {
+                       throw new ArrayIndexOutOfBoundsException();
+               }
+               
+               if ( start > end ) {
+                       throw new IllegalArgumentException();
+               }
+               
+               double[] result = new double[(end-start)];
+               
+               int index = 0;
+               int stop = original.length < end ? original.length : end;
+               for ( int i = start; i < stop; i ++ ) {
+                       if ( i < original.length ) {
+                               result[index] = original[i];
+                       }
+                       index++;
+               }
+               
+               return result;
+               
+       }
+
+       public static byte[] copyOf( byte[] original, int length ) {
+               return copyOfRange(original,0,length);
+       }
+       
+       public static byte[] copyOfRange( byte[] original, int start, int end ) {
+               
+               if ( original == null ) {
+                       throw new NullPointerException();
+               }
+               
+               if ( start < 0 || start > original.length ) {
+                       throw new ArrayIndexOutOfBoundsException();
+               }
+               
+               if ( start > end ) {
+                       throw new IllegalArgumentException();
+               }
+               
+               byte[] result = new byte[(end-start)];
+               
+               int index = 0;
+               int stop = original.length < end ? original.length : end;
+               for ( int i = start; i < stop; i ++ ) {
+                       if ( i < original.length ) {
+                               result[index] = original[i];
+                       }
+                       index++;
+               }
+               
+               return result;
+               
+       }
+
+}
+
index 042d36715d41840522a586db27f4011055a18873..aeed54a1dd0f30c5bef6c6d3dace98651aedeb31 100644 (file)
@@ -3,7 +3,6 @@ package net.sf.openrocket.util;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Random;
 
 public class Base64 {
 
@@ -81,7 +80,7 @@ public class Base64 {
                        if (p==0)
                                break;
                        if (p!=4) {
-                               throw new IllegalArgumentException("Data ended when decoding Base64, p="+p);
+                               throw new IllegalArgumentException("Data ended when decoding Base64, data=" + data + ", p="+p);
                        }
                        
                        int l = decodeGroup(block, array, length);
@@ -166,67 +165,4 @@ public class Base64 {
                return 3;
        }
        
-       
-       
-       public static void main(String[] arg) {
-               Random rnd = new Random();
-               
-               for (int round=0; round < 1000; round++) {
-                       int n = rnd.nextInt(1000);
-                       n = 100000;
-                       
-                       byte[] array = new byte[n];
-                       rnd.nextBytes(array);
-
-                       String encoded = encode(array);
-                       
-                       System.out.println(encoded);
-                       System.exit(0);
-//                     for (int i=0; i<1000; i++) {
-//                             int pos = rnd.nextInt(encoded.length());
-//                             String s1 = encoded.substring(0, pos);
-//                             String s2 = encoded.substring(pos);
-//                             switch (rnd.nextInt(15)) {
-//                             case 0:
-//                                     encoded = s1 + " " + s2;
-//                                     break;
-//                             case 1:
-//                                     encoded = s1 + "\u0009" + s2;
-//                                     break;
-//                             case 2:
-//                                     encoded = s1 + "\n" + s2;
-//                                     break;
-//                             case 3:
-//                                     encoded = s1 + "\u000B" + s2;
-//                                     break;
-//                             case 4:
-//                                     encoded = s1 + "\r" + s2;
-//                                     break;
-//                             case 5:
-//                                     encoded = s1 + "\u000C" + s2;
-//                                     break;
-//                             case 6:
-//                                     encoded = s1 + "\u001C" + s2;
-//                                     break;
-//                             }
-//                     }
-                       
-                       byte[] decoded = null;
-                       try {
-                               decoded = decode(encoded);
-                       } catch (IllegalArgumentException e) {
-                               e.printStackTrace();
-                               System.err.println("Bad data:\n"+encoded);
-                               System.exit(1);
-                       }
-                       
-                       if (!Arrays.equals(array, decoded)) {
-                               System.err.println("Data differs!  n="+n);
-                               System.exit(1);
-                       }
-                       System.out.println("n="+n+" ok!");
-               }
-       }
-       
-       
 }
index 46bc3c20b09bd617f99cb5b4947688f039000921..9e88e93ea4f7866067ed290e6bae6b46658cd9fc 100644 (file)
@@ -32,7 +32,7 @@ public class BuildProperties {
        \r
        static {\r
                try {\r
-                       InputStream is = ClassLoader.getSystemResourceAsStream("build.properties");\r
+                       InputStream is = BuildProperties.class.getClassLoader().getResourceAsStream("build.properties");\r
                        if (is == null) {\r
                                throw new MissingResourceException(\r
                                                "build.properties not found, distribution built wrong" +\r
index eeba22bcaf2ae7daff79ce9d8d4e4387ba942992..1b2857a2b7cd1d1ed2a29d42467ffb245eb512df 100644 (file)
@@ -13,6 +13,8 @@ public class Chars {
        public static final char FRAC14 = '\u00BC';
        /** The fraction 3/4 */
        public static final char FRAC34 = '\u00BE';
+       /** Fraction slash */
+       public static final char FRACTION = '\u2044';
        
        /** Degree sign */
        public static final char DEGREE = '\u00B0';
index 3bc981aaa8d1a618b2bf0067fa320fd5ea236f0f..0f65ffa4935a498f1c9c898b7934c7be024948b2 100644 (file)
@@ -12,8 +12,11 @@ import net.sf.openrocket.startup.Application;
  * 
  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
  */
-public final class Coordinate implements Serializable {
+public final class Coordinate implements Cloneable, Serializable {
        private static final LogHelper log = Application.getLogger();
+
+       // Defined for backwards compatibility after adding clone().
+       static final long serialVersionUID = 585574649794259293L;
        
        ////////  Debug section
        /*
@@ -68,8 +71,6 @@ public final class Coordinate implements Serializable {
        private double length = -1; /* Cached when calculated */
        
        
-
-
        public Coordinate() {
                this(0, 0, 0, 0);
        }
@@ -315,6 +316,10 @@ public final class Coordinate implements Serializable {
                else
                        return String.format("(%.3f,%.3f,%.3f)", x, y, z);
        }
-       
+
+       @Override
+       public Coordinate clone() {
+               return new Coordinate(  this.x, this.y, this.z, this.weight );
+       }
 
 }
diff --git a/core/src/net/sf/openrocket/util/ExpressionParser.java b/core/src/net/sf/openrocket/util/ExpressionParser.java
new file mode 100644 (file)
index 0000000..d3a3fa6
--- /dev/null
@@ -0,0 +1,67 @@
+package net.sf.openrocket.util;
+
+import java.text.DecimalFormatSymbols;
+
+import net.sf.openrocket.logging.LogHelper;
+import net.sf.openrocket.startup.Application;
+import de.congrace.exp4j.Calculable;
+import de.congrace.exp4j.ExpressionBuilder;
+
+public class ExpressionParser {
+       private static final LogHelper log = Application.getLogger();
+       
+       private static final char DECIMAL_SEPARATOR;
+       private static final char MINUS_SIGN;
+       static {
+               DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance();
+               DECIMAL_SEPARATOR = symbols.getDecimalSeparator();
+               MINUS_SIGN = symbols.getMinusSign();
+       }
+       
+       public double parse(String expression) throws InvalidExpressionException {
+               
+               String modified = null;
+               try {
+                       modified = modify(expression);
+                       ExpressionBuilder builder = new ExpressionBuilder(modified);
+                       Calculable calc = builder.build();
+                       double n = calc.calculate().getDoubleValue();
+                       log.debug("Evaluated expression '" + expression + "' (modified='" + modified + "') to " + n);
+                       return n;
+               } catch (Exception e) {
+                       log.warn("Unable to parse expression '" + expression + "' (modified='" + modified + "')", e);
+                       throw new InvalidExpressionException("Invalid expression: " + expression, e);
+               }
+       }
+       
+       private String modify(String exp) throws InvalidExpressionException {
+               
+               // Normalize digit equivalents, fraction sign, decimal separators and minus sign
+               char[] chars = exp.toCharArray();
+               for (int i = 0; i < chars.length; i++) {
+                       int value = Character.getNumericValue(chars[i]);
+                       if (value >= 0 && value < 10) {
+                               chars[i] = Character.toChars(48 + value)[0];
+                       }
+                       if (chars[i] == Chars.FRACTION) {
+                               chars[i] = '/';
+                       }
+                       if (chars[i] == DECIMAL_SEPARATOR || chars[i] == ',') {
+                               chars[i] = '.';
+                       }
+                       if (chars[i] == MINUS_SIGN) {
+                               chars[i] = '-';
+                       }
+               }
+               exp = String.copyValueOf(chars);
+               
+               // Replace fraction equivalents "1 3/4" with "(1+3/4)"
+               exp = exp.replaceAll("(?<![\\d.])(\\d+)\\s+(\\d+)\\s*/\\s*(\\d+)(?![\\d.])", "($1+$2/$3)");
+               
+               // Disallow spaces between numbers - default is to remove spaces!
+               if (exp.matches(".*[0-9.]\\s+[0-9.].*")) {
+                       throw new InvalidExpressionException("Expression contains excess space: " + exp);
+               }
+               return exp;
+       }
+}
index f8a37a09dd5bc848966eb2bd98f71acf889b10f6..0721e893d1ef08048925fd18b1ad3d8695328138 100644 (file)
@@ -1,5 +1,7 @@
 package net.sf.openrocket.util;
 
+import java.util.Locale;
+
 import net.sf.openrocket.l10n.Translator;
 import net.sf.openrocket.startup.Application;
 
@@ -13,7 +15,7 @@ import net.sf.openrocket.startup.Application;
  */
 public enum GeodeticComputationStrategy {
        
-
+       
        /**
         * Perform computations using a flat Earth approximation.  addCoordinate computes the
         * location using a direct meters-per-degree scaling and getCoriolisAcceleration always
@@ -131,7 +133,7 @@ public enum GeodeticComputationStrategy {
                }
        };
        
-
+       
        private static final Translator trans = Application.getTranslator();
        
        private static final double PRECISION_LIMIT = 0.5e-13;
@@ -141,14 +143,14 @@ public enum GeodeticComputationStrategy {
         * Return the name of this geodetic computation method.
         */
        public String getName() {
-               return trans.get(name().toLowerCase() + ".name");
+               return trans.get(name().toLowerCase(Locale.ENGLISH) + ".name");
        }
        
        /**
         * Return a description of the geodetic computation methods.
         */
        public String getDescription() {
-               return trans.get(name().toLowerCase() + ".desc");
+               return trans.get(name().toLowerCase(Locale.ENGLISH) + ".desc");
        }
        
        @Override
@@ -169,9 +171,9 @@ public enum GeodeticComputationStrategy {
        public abstract Coordinate getCoriolisAcceleration(WorldCoordinate location, Coordinate velocity);
        
        
-
-
-
+       
+       
+       
        private static Coordinate computeCoriolisAcceleration(WorldCoordinate latlon, Coordinate velocity) {
                
                double sinlat = Math.sin(latlon.getLatitudeRad());
@@ -189,14 +191,14 @@ public enum GeodeticComputationStrategy {
                // able to be set independently and in terms of bearing with north == +ve y.
                
                Coordinate coriolis = new Coordinate(2.0 * WorldCoordinate.EROT * (v_n * sinlat - v_u * coslat),
-                                                                                               2.0 * WorldCoordinate.EROT * (-1.0 * v_e * sinlat),
-                                                                                               2.0 * WorldCoordinate.EROT * (v_e * coslat)
-                                                                                       );
+                               2.0 * WorldCoordinate.EROT * (-1.0 * v_e * sinlat),
+                               2.0 * WorldCoordinate.EROT * (v_e * coslat)
+                               );
                return coriolis;
        }
        
        
-
+       
        // ******************************************************************** //
        // The Vincenty Direct Solution.
        // Code from GeoConstants.java, Ian Cameron Smith, GPL
@@ -226,8 +228,8 @@ public enum GeodeticComputationStrategy {
         *                                              point, in radians clockwise from north.
         */
        private static double[] dirct1(double glat1, double glon1,
-                                                                       double azimuth, double dist,
-                                                                       double axis, double flat) {
+                       double azimuth, double dist,
+                       double axis, double flat) {
                double r = 1.0 - flat;
                
                double tu = r * Math.sin(glat1) / Math.cos(glat1);
@@ -264,7 +266,7 @@ public enum GeodeticComputationStrategy {
                        x = e * cy;
                        y = e + e - 1.0;
                        y = (((sy * sy * 4.0 - 3.0) * y * cz * d / 6.0 + x) *
-                                                                       d / 4.0 - cz) * sy * d + tu;
+                                       d / 4.0 - cz) * sy * d + tu;
                } while (Math.abs(y - c) > PRECISION_LIMIT);
                
                baz = cu * cy * cf - su * sy;
@@ -285,5 +287,5 @@ public enum GeodeticComputationStrategy {
                return ret;
        }
        
-
+       
 }
diff --git a/core/src/net/sf/openrocket/util/InvalidExpressionException.java b/core/src/net/sf/openrocket/util/InvalidExpressionException.java
new file mode 100644 (file)
index 0000000..118cefe
--- /dev/null
@@ -0,0 +1,22 @@
+package net.sf.openrocket.util;
+
+/**
+ * Exception indicating an invalid expression.
+ * 
+ * @author Sampo Niskanen <sampo.niskanen@iki.fi>
+ */
+public class InvalidExpressionException extends Exception {
+       
+       public InvalidExpressionException(String message) {
+               super(message);
+       }
+       
+       public InvalidExpressionException(Throwable cause) {
+               super(cause);
+       }
+       
+       public InvalidExpressionException(String message, Throwable cause) {
+               super(message, cause);
+       }
+       
+}
index b73438ed10bf8714dc80808de2206338ad4ba9c2..545cfa581d9e4f8e09c53b11d937a6f2de41c15a 100644 (file)
@@ -18,8 +18,15 @@ public class JarUtil {
         */
        public static File getCurrentJarFile() {
                // Find the jar file this class is contained in
+               
                URL jarUrl = null;
-               CodeSource codeSource = Database.class.getProtectionDomain().getCodeSource();
+               CodeSource codeSource;
+               try {
+                       codeSource = new URL("rsrc:.").openConnection().getClass().getProtectionDomain().getCodeSource();
+               } catch (Throwable e) {
+                       codeSource = Database.class.getProtectionDomain().getCodeSource();
+               }
+               
                if (codeSource != null)
                        jarUrl = codeSource.getLocation();
                
index e94a39766e6237306e42f241549a6ccfc0394718..e16726bb52e136ca273c59fa6d7dab788e762d67 100644 (file)
@@ -1,7 +1,8 @@
 package net.sf.openrocket.util;
 
 import java.util.Iterator;
-import java.util.Map;
+import java.util.List;
+import java.util.SortedMap;
 import java.util.TreeMap;
 
 public class LinearInterpolator implements Cloneable {
@@ -14,7 +15,7 @@ public class LinearInterpolator implements Cloneable {
         */
        public LinearInterpolator() {
        }
-       
+
        /**
         * Construct a <code>LinearInterpolator</code> with the given points.
         * 
@@ -27,8 +28,11 @@ public class LinearInterpolator implements Cloneable {
        public LinearInterpolator(double[] x, double[] y) {
                addPoints(x,y);
        }
-       
-       
+
+       public LinearInterpolator(List<Double> x, List<Double> y) {
+               addPoints(x,y);
+       }
+
        /**
         * Add the point to the linear interpolation.
         * 
@@ -38,7 +42,7 @@ public class LinearInterpolator implements Cloneable {
        public void addPoint(double x, double y) {
                sortMap.put(x, y);
        }
-       
+
        /**
         * Add the points to the linear interpolation.
         * 
@@ -56,41 +60,75 @@ public class LinearInterpolator implements Cloneable {
                        sortMap.put(x[i],y[i]);
                }
        }
-       
-       
-       
+
+       public void addPoints(List<Double> x, List<Double> y){
+               if (x.size() != y.size()) {
+                       throw new IllegalArgumentException("Array lengths do not match, x="+x.size() +
+                                       " y="+y.size());
+               }
+               for (int i=0; i < x.size(); i++) {
+                       sortMap.put( (Double) x.toArray()[i], (Double) y.toArray()[i]);
+               }
+       }
+
+
        public double getValue(double x) {
-               Map.Entry<Double,Double> e1, e2;
                double x1, x2;
-               double y1, y2;
+               Double y1, y2;
+               // Froyo does not support floorEntry, firstEntry or higherEntry.  We instead have to
+               // resort to using other more awkward methods.
+
+               y1 = sortMap.get(x);
+
+               if ( y1 != null ) {
+                       // Wow, x was a key in the map.  Such luck.
+                       return y1.doubleValue();
+               }
+
+               // we now know that x is not in the map, so we need to find the lower and higher keys.
                
-               e1 = sortMap.floorEntry(x);
+               // let's just make certain that our map is not empty.
+               if ( sortMap.isEmpty() ) {
+                       throw new IllegalStateException("No points added yet to the interpolator.");
+               }
                
-               if (e1 == null) {
-                       // x smaller than any value in the set
-                       e1 = sortMap.firstEntry();
-                       if (e1 == null) {
-                               throw new IllegalStateException("No points added yet to the interpolator.");
-                       }
-                       return e1.getValue();
+               // firstKey in the map - cannot be null since the map is not empty.
+               Double firstKey = sortMap.firstKey();
+
+               // x is smaller than the first entry in the map.
+               if ( x < firstKey.doubleValue() ) {
+                       y1 = sortMap.get(firstKey);
+                       return y1.doubleValue();
                }
                
-               x1 = e1.getKey();
-               e2 = sortMap.higherEntry(x1);
+               // floor key is the largest key smaller than x - since we have at least one key,
+               // and x>=firstKey, we know that floorKey != null.
+               Double floorKey = sortMap.subMap(firstKey, x).lastKey();
+
+               x1 = floorKey.doubleValue();
+               y1 = sortMap.get(floorKey);
 
-               if (e2 == null) {
-                       // x larger than any value in the set
-                       return e1.getValue();
+               // Now we need to find the key that is greater or equal to x
+               SortedMap<Double,Double> tailMap = sortMap.tailMap(x);
+
+               // Check if x is bigger than all the entries.
+               if ( tailMap.isEmpty() ) {
+                       return y1.doubleValue();
                }
+               Double ceilKey = tailMap.firstKey();
                
-               x2 = e2.getKey();
-               y1 = e1.getValue();
-               y2 = e2.getValue();
+               // Check if x is bigger than all the entries.
+               if ( ceilKey == null ) {
+                       return y1.doubleValue();
+               }
                
+               x2 = ceilKey.doubleValue();
+               y2 = sortMap.get(ceilKey);
+
                return (x - x1)/(x2-x1) * (y2-y1) + y1;
        }
-       
-       
+
+
        public double[] getXPoints() {
                double[] x = new double[sortMap.size()];
                Iterator<Double> iter = sortMap.keySet().iterator();
@@ -99,8 +137,8 @@ public class LinearInterpolator implements Cloneable {
                }
                return x;
        }
-       
-       
+
+
        @SuppressWarnings("unchecked")
        @Override
        public LinearInterpolator clone() {
@@ -113,16 +151,4 @@ public class LinearInterpolator implements Cloneable {
                }
        }
 
-       
-       public static void main(String[] args) {
-               LinearInterpolator interpolator = new LinearInterpolator(
-                               new double[] {1, 1.5, 2, 4, 5},
-                               new double[] {0, 1,   0, 2, 2}
-               );
-               
-               for (double x=0; x < 6; x+=0.1) {
-                       System.out.printf("%.1f:  %.2f\n", x, interpolator.getValue(x));
-               }
-       }
-       
 }
index c88e85853562bc5907f64bfb4654d329b2140128..09a316899cec68ce70ef6140d3aaafb6e93ae130 100644 (file)
@@ -310,7 +310,7 @@ public class MathUtil {
                        return sorted.get(n / 2).doubleValue();
                }
        }
-
+       
        /**
         * Use interpolation to determine the value of the function at point t.
         * Current implementation uses simple linear interpolation.   The domain
index f97d45c43a91612ed4d3db9598edf901531e4660..134f71783cf8d9492cd857f571549ea318bb2a7c 100644 (file)
@@ -228,35 +228,4 @@ public class PolyInterpolator {
                }
        }
 
-
-
-
-       public static void main(String[] arg) {
-
-               PolyInterpolator p0 = new PolyInterpolator(
-                               new double[] {0.6, 1.1},
-                               new double[] {0.6, 1.1}
-               );
-               double[] r0 = p0.interpolator(1.5, 1.6, 2, -3);
-               
-               PolyInterpolator p1 = new PolyInterpolator(
-                               new double[] {0.6, 1.1},
-                               new double[] {0.6, 1.1},
-                               new double[] {0.6}
-               );
-               double[] r1 = p1.interpolator(1.5, 1.6, 2, -3, 0);
-               
-               PolyInterpolator p2 = new PolyInterpolator(
-                               new double[] {0.6, 1.1},
-                               new double[] {0.6, 1.1},
-                               new double[] {0.6, 1.1}
-               );
-               double[] r2 = p2.interpolator(1.5, 1.6, 2, -3, 0, 0);
-               
-
-               for (double x=0.6; x <= 1.11; x += 0.01) {
-                       System.out.println(x + " " + eval(x,r0) + " " + eval(x,r1) + " " + eval(x,r2));
-               }
-               
-       }
 }
index 5f2776626c26fcd0764be7a33a8e8fee717f72cd..e82eb9d22e31a9aca5904d6174cc16a08d7971fe 100644 (file)
@@ -318,39 +318,4 @@ public class Quaternion {
                return String.format("Quaternion[%f,%f,%f,%f,norm=%f]", w, x, y, z, this.norm());
        }
        
-       public static void main(String[] arg) {
-               
-               Quaternion q = new Quaternion(Math.random() - 0.5, Math.random() - 0.5,
-                               Math.random() - 0.5, Math.random() - 0.5);
-               q.normalize();
-               
-               q = new Quaternion(-0.998717, 0.000000, 0.050649, -0.000000);
-               
-               Coordinate coord = new Coordinate(10 * (Math.random() - 0.5),
-                               10 * (Math.random() - 0.5), 10 * (Math.random() - 0.5));
-               
-               System.out.println("Quaternion: " + q);
-               System.out.println("Coordinate: " + coord);
-               coord = q.invRotate(coord);
-               System.out.println("Rotated: " + coord);
-               coord = q.rotate(coord);
-               System.out.println("Back:       " + coord);
-               
-
-               q = new Quaternion(0.237188, 0.570190, -0.514542, 0.594872);
-               q.normalize();
-               Coordinate c = new Coordinate(148578428.914, 8126778.954, -607.741);
-               
-               System.out.println("Rotated: " + q.rotate(c));
-               
-               //              Coordinate c = new Coordinate(0,1,0);
-               //              Coordinate rot = new Coordinate(Math.PI/4,0,0);
-               //              
-               //              System.out.println("Before: "+c);
-               //              c = rotation(rot).invRotate(c);
-               //              System.out.println("After: "+c);
-               
-
-       }
-       
 }
diff --git a/core/src/net/sf/openrocket/util/SimpleStack.java b/core/src/net/sf/openrocket/util/SimpleStack.java
new file mode 100644 (file)
index 0000000..6bdd967
--- /dev/null
@@ -0,0 +1,29 @@
+package net.sf.openrocket.util;
+
+import java.util.NoSuchElementException;
+/**
+ * SimpleStack implementation backed by an ArrayList.
+ * 
+ */
+public class SimpleStack<T> extends ArrayList<T> {
+
+       public void push( T value ) {
+               this.add(value);
+       }
+       
+       public T peek() {
+               if ( size() <= 0 ) {
+                       return null;
+               }
+               return this.get( size() -1 );
+       }
+       
+       public T pop() {
+               if ( size() <= 0 ) {
+                       throw new NoSuchElementException();
+               }
+               T value = this.remove( size() -1 );
+               return value;
+       }
+       
+}
index 0dfc56291ded7ae1f940ab9a243f35e1d537115f..7a670e166a2360d31afc9a199fb57c199fabb9cb 100644 (file)
@@ -2,6 +2,7 @@ package net.sf.openrocket.util;
 
 import java.util.Random;
 
+import net.sf.openrocket.database.Databases;
 import net.sf.openrocket.material.Material;
 import net.sf.openrocket.material.Material.Type;
 import net.sf.openrocket.motor.Motor;
@@ -81,12 +82,12 @@ public class TestRockets {
                rocket.setRevision("Rocket revision " + key);
                rocket.setName(key);
                
-
+               
                Stage stage = new Stage();
                setBasics(stage);
                rocket.addChild(stage);
                
-
+               
                NoseCone nose = new NoseCone();
                setBasics(stage);
                nose.setAftRadius(rnd(0.03));
@@ -104,7 +105,7 @@ public class TestRockets {
                nose.setType((Shape) randomEnum(Shape.class));
                stage.addChild(nose);
                
-
+               
                Transition shoulder = new Transition();
                setBasics(shoulder);
                shoulder.setAftRadius(rnd(0.06));
@@ -128,7 +129,7 @@ public class TestRockets {
                shoulder.setType((Shape) randomEnum(Shape.class));
                stage.addChild(shoulder);
                
-
+               
                BodyTube body = new BodyTube();
                setBasics(body);
                body.setThickness(rnd(0.002));
@@ -142,7 +143,7 @@ public class TestRockets {
                body.setOuterRadiusAutomatic(rnd.nextBoolean());
                stage.addChild(body);
                
-
+               
                Transition boattail = new Transition();
                setBasics(boattail);
                boattail.setAftRadius(rnd(0.03));
@@ -166,7 +167,7 @@ public class TestRockets {
                boattail.setType((Shape) randomEnum(Shape.class));
                stage.addChild(boattail);
                
-
+               
                MassComponent mass = new MassComponent();
                setBasics(mass);
                mass.setComponentMass(rnd(0.05));
@@ -176,9 +177,9 @@ public class TestRockets {
                mass.setRadius(rnd(0.05));
                nose.addChild(mass);
                
-
-
-
+               
+               
+               
                return rocket;
        }
        
@@ -203,7 +204,7 @@ public class TestRockets {
                        ExternalComponent e = (ExternalComponent) c;
                        e.setFinish((Finish) randomEnum(Finish.class));
                        double d = rnd(100);
-                       e.setMaterial(Material.newMaterial(Type.BULK, "Testmat " + d, d, rnd.nextBoolean()));
+                       e.setMaterial(Databases.findMaterial(Type.BULK, "Testmat " + d, d));
                }
                
                if (c instanceof InternalComponent) {
@@ -214,7 +215,7 @@ public class TestRockets {
        }
        
        
-
+       
        private double rnd(double scale) {
                return (rnd.nextDouble() * 0.2 + 0.9) * scale;
        }
@@ -232,9 +233,9 @@ public class TestRockets {
        }
        
        
-
-
-
+       
+       
+       
        public Rocket makeSmallFlyable() {
                double noseconeLength = 0.10, noseconeRadius = 0.01;
                double bodytubeLength = 0.20, bodytubeRadius = 0.01, bodytubeThickness = 0.001;
@@ -242,7 +243,7 @@ public class TestRockets {
                int finCount = 3;
                double finRootChord = 0.04, finTipChord = 0.05, finSweep = 0.01, finThickness = 0.003, finHeight = 0.03;
                
-
+               
                Rocket rocket;
                Stage stage;
                NoseCone nosecone;
@@ -258,11 +259,11 @@ public class TestRockets {
                
                finset = new TrapezoidFinSet(finCount, finRootChord, finTipChord, finSweep, finHeight);
                
-
+               
                // Stage construction
                rocket.addChild(stage);
                
-
+               
                // Component construction
                stage.addChild(nosecone);
                stage.addChild(bodytube);
@@ -284,7 +285,7 @@ public class TestRockets {
                
                rocket.getDefaultConfiguration().setAllStages();
                
-
+               
                return rocket;
        }
        
@@ -331,7 +332,7 @@ public class TestRockets {
                rocket.addChild(stage);
                rocket.setPerfectFinish(false);
                
-
+               
                // Component construction
                stage.addChild(nosecone);
                stage.addChild(bodytube);
@@ -355,12 +356,12 @@ public class TestRockets {
                
                rocket.getDefaultConfiguration().setAllStages();
                
-
+               
                return rocket;
        }
        
        
-
+       
        public static Rocket makeIsoHaisu() {
                Rocket rocket;
                Stage stage;
@@ -397,7 +398,7 @@ public class TestRockets {
                tube3.setOverrideMass(0.730);
                stage.addChild(tube3);
                
-
+               
                LaunchLug lug = new LaunchLug();
                tube1.addChild(lug);
                
@@ -411,7 +412,7 @@ public class TestRockets {
                coupler.setPositionValue(-0.14);
                tube1.addChild(coupler);
                
-
+               
                // Parachute
                MassComponent mass = new MassComponent(0.05, 0.05, 0.280);
                mass.setRelativePosition(Position.TOP);
@@ -430,7 +431,7 @@ public class TestRockets {
                mass.setPositionValue(0.25);
                tube1.addChild(mass);
                
-
+               
                auxfinset = new TrapezoidFinSet();
                auxfinset.setName("CONTROL");
                auxfinset.setFinCount(2);
@@ -445,9 +446,9 @@ public class TestRockets {
                auxfinset.setBaseRotation(Math.PI / 2);
                tube1.addChild(auxfinset);
                
-
-
-
+               
+               
+               
                coupler = new TubeCoupler();
                coupler.setOuterRadiusAutomatic(true);
                coupler.setLength(0.28);
@@ -457,8 +458,8 @@ public class TestRockets {
                coupler.setOverrideMass(0.360);
                tube2.addChild(coupler);
                
-
-
+               
+               
                // Parachute
                mass = new MassComponent(0.1, 0.05, 0.028);
                mass.setRelativePosition(Position.TOP);
@@ -479,8 +480,8 @@ public class TestRockets {
                mass.setPositionValue(0.19);
                tube2.addChild(mass);
                
-
-
+               
+               
                InnerTube inner = new InnerTube();
                inner.setOuterRadius(0.08 / 2);
                inner.setInnerRadius(0.0762 / 2);
@@ -489,7 +490,7 @@ public class TestRockets {
                inner.setOverrideMass(0.388);
                tube3.addChild(inner);
                
-
+               
                CenteringRing center = new CenteringRing();
                center.setInnerRadiusAutomatic(true);
                center.setOuterRadiusAutomatic(true);
@@ -500,7 +501,7 @@ public class TestRockets {
                center.setPositionValue(0);
                tube3.addChild(center);
                
-
+               
                center = new CenteringRing();
                center.setInnerRadiusAutomatic(true);
                center.setOuterRadiusAutomatic(true);
@@ -511,7 +512,7 @@ public class TestRockets {
                center.setPositionValue(0.28);
                tube3.addChild(center);
                
-
+               
                center = new CenteringRing();
                center.setInnerRadiusAutomatic(true);
                center.setOuterRadiusAutomatic(true);
@@ -522,10 +523,10 @@ public class TestRockets {
                center.setPositionValue(0.83);
                tube3.addChild(center);
                
-
-
-
-
+               
+               
+               
+               
                finset = new TrapezoidFinSet();
                finset.setRootChord(0.495);
                finset.setTipChord(0.1);
@@ -537,17 +538,17 @@ public class TestRockets {
                finset.setBaseRotation(Math.PI / 2);
                tube3.addChild(finset);
                
-
+               
                finset.setCantAngle(0 * Math.PI / 180);
                System.err.println("Fin cant angle: " + (finset.getCantAngle() * 180 / Math.PI));
                
-
+               
                // Stage construction
                rocket.addChild(stage);
                rocket.setPerfectFinish(false);
                
-
-
+               
+               
                String id = rocket.newMotorConfigurationID();
                tube3.setMotorMount(true);
                
@@ -560,10 +561,10 @@ public class TestRockets {
                
                rocket.getDefaultConfiguration().setAllStages();
                
-
+               
                return rocket;
        }
        
-
-
+       
+       
 }
index 32dffd849a4eb0c13cc92d8c1eb613df76e5b327..0b86876de9055e3047b5ea3649b9c19e50325a31 100644 (file)
@@ -1,12 +1,32 @@
 package net.sf.openrocket.util;
 
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
 
 public class TextUtil {
+
+       
        private static final char[] HEX = {
                        '0', '1', '2', '3', '4', '5', '6', '7',
                        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
        };
-       
+
+       /**
+        * Return the byte array for the string in the given charset.
+        * 
+        * This function is implemented because Froyo (Android API 8) does not support
+        * String.getBytes(Charset)
+        * 
+        * @param string
+        * @param charSet
+        * @return
+        */
+       public static byte[] convertStringToBytes( String string, Charset charSet ) {
+               ByteBuffer encoded = charSet.encode(string);
+               return encoded.array();
+       }
+
        
        /**
         * Return the bytes formatted as a hexadecimal string.  The length of the
@@ -164,4 +184,17 @@ public class TextUtil {
                s = s.replace(">", "&gt;");
                return s;
        }
+       
+       /*
+        * Returns a word-wrapped version of given input string using HTML syntax, wrapped to len characters.
+        */
+       public static String wrap(String in,int len) {
+               in=in.trim();
+               if(in.length()<len) return in;
+               if(in.substring(0, len).contains("\n"))
+                       return in.substring(0, in.indexOf("\n")).trim() + "\n\n" + wrap(in.substring(in.indexOf("\n") + 1), len);
+               int place=Math.max(Math.max(in.lastIndexOf(" ",len),in.lastIndexOf("\t",len)),in.lastIndexOf("-",len));
+               return "<html>"+in.substring(0,place).trim()+"<br>"+wrap(in.substring(place),len);
+       }
+
 }
index 2c54697409da1b9ab6cd8baba4a13ce7c0722238..8656a4f25762e7cd857cb61e31cb722f2cd22137 100644 (file)
@@ -257,23 +257,4 @@ public class Transformation implements java.io.Serializable {
                return this.translate.equals(o.translate);
        }
        
-       public static void main(String[] arg) {
-               Transformation t;
-               
-               t = new Transformation();
-               t.print("Empty");
-               t = new Transformation(1,2,3);
-               t.print("1,2,3");
-               t = new Transformation(new Coordinate(2,3,4));
-               t.print("coord 2,3 4");
-               
-               t = Transformation.rotate_y(0.01);
-               t.print("rotate_y 0.01");
-               
-               t = new Transformation(-1,0,0);
-               t = t.applyTransformation(Transformation.rotate_y(0.01));
-               t = t.applyTransformation(new Transformation(1,0,0));
-               t.print("shift-rotate-shift");
-       }
-       
 }
diff --git a/core/src/net/sf/openrocket/util/enums/EnumConversion.java b/core/src/net/sf/openrocket/util/enums/EnumConversion.java
new file mode 100644 (file)
index 0000000..4b8624f
--- /dev/null
@@ -0,0 +1,7 @@
+package net.sf.openrocket.util.enums;
+
+public interface EnumConversion {
+       
+       public String convert(Enum<?> e);
+       
+}
diff --git a/core/src/net/sf/openrocket/util/enums/EnumName.java b/core/src/net/sf/openrocket/util/enums/EnumName.java
new file mode 100644 (file)
index 0000000..7821061
--- /dev/null
@@ -0,0 +1,63 @@
+package net.sf.openrocket.util.enums;
+
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.openrocket.util.BugException;
+
+public class EnumName<E extends Enum<E>> {
+       
+       public static final EnumConversion NAME = new EnumConversion() {
+               @Override
+               public String convert(Enum<?> e) {
+                       return e.name();
+               }
+       };
+       
+       
+       private final Class<E> type;
+       private final Map<E, String> map;
+       private final Map<String, E> reverse;
+       
+       public EnumName(Class<E> type) {
+               this(type, NAME);
+       }
+       
+       public EnumName(Class<E> type, EnumConversion conversion) {
+               this.type = type;
+               map = new EnumMap<E, String>(type);
+               reverse = new HashMap<String, E>();
+               
+               E[] keys = type.getEnumConstants();
+               if (keys == null) {
+                       throw new IllegalArgumentException("Type " + type + " is not of enum type");
+               }
+               for (E key : keys) {
+                       String value = conversion.convert(key);
+                       if (reverse.containsKey(value)) {
+                               throw new BugException("Two enum constants were converted to have the name value: " + reverse.get(value)
+                                               + " and " + key + " both convert to '" + value + "'");
+                       }
+                       map.put(key, value);
+                       reverse.put(value, key);
+                       
+               }
+       }
+       
+       
+       
+       public String getName(E key) {
+               String name = map.get(key);
+               if (name == null) {
+                       throw new IllegalArgumentException("No name found for enum " + key + " from map of type " + type);
+               }
+               return name;
+       }
+       
+       public E getEnum(String name) {
+               return reverse.get(name);
+       }
+       
+       
+}
diff --git a/core/src/net/sf/openrocket/utils/L10NGenerator.java b/core/src/net/sf/openrocket/utils/L10NGenerator.java
new file mode 100644 (file)
index 0000000..de64a10
--- /dev/null
@@ -0,0 +1,56 @@
+package net.sf.openrocket.utils;
+
+import java.text.Normalizer;
+
+import net.sf.openrocket.util.Chars;
+
+/**
+ * This class is used to generate the map used in L10N class
+ * due to the fact that Android does not support java.text.Normalizer.
+ */
+public class L10NGenerator {
+       
+       public static void main(String[] args) throws Exception {
+               
+               // Latin chars
+               for (char ch = 128; ch < 0x250; ch++) {
+                       output(ch);
+               }
+               // Superscript numbers
+               for (char ch = 0x2070; ch <= 0x2079; ch++) {
+                       output(ch);
+               }
+               // Subscript numbers
+               for (char ch = 0x2080; ch <= 0x2089; ch++) {
+                       output(ch);
+               }
+               output(Chars.FRACTION);
+               print(Chars.ZWSP, " ");
+               print(Chars.NBSP, " ");
+       }
+       
+       private static void output(char ch) {
+               String text = "" + ch;
+               StringBuilder sb = new StringBuilder(text.length());
+               //                      s = normalize(s);
+               text = Normalizer.normalize(text, Normalizer.Form.NFKD);
+               
+               for (char c : text.toCharArray()) {
+                       if (c < 128) {
+                               sb.append(c);
+                       } else if (c == Chars.FRACTION) {
+                               sb.append('/');
+                       }
+               }
+               
+               text = sb.toString().trim();
+               
+               if (text.length() > 0) {
+                       print(ch, text);
+               }
+       }
+       
+       private static void print(char ch, String text) {
+               System.out.printf("m.put('\\u%04x', \"%s\");\n", (int) ch, text);
+       }
+}
index ab5c48ab7becc5d1c9f4b28cbc7b4134fb2f9a00..57f5d5203f444fe365ef6948703221aa6f10ac14 100644 (file)
@@ -14,12 +14,13 @@ import java.net.URL;
 import java.security.Permission;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import net.sf.openrocket.util.BugException;
 
 public class HttpURLConnectionMock extends HttpURLConnection {
-
+       
        private static final URL MOCK_URL;
        static {
                try {
@@ -88,7 +89,7 @@ public class HttpURLConnectionMock extends HttpURLConnection {
        }
        
        
-
+       
        @Override
        public void connect() {
                if (!connected) {
@@ -99,17 +100,17 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                        connected = true;
                }
        }
-
+       
        @Override
        public void disconnect() {
                
        }
-
+       
        @Override
        public boolean usingProxy() {
                return false;
        }
-
+       
        
        
        
@@ -117,69 +118,69 @@ public class HttpURLConnectionMock extends HttpURLConnection {
        public boolean getInstanceFollowRedirects() {
                return this.instanceFollowRedirects;
        }
-
+       
        @Override
        public void setInstanceFollowRedirects(boolean followRedirects) {
                assertFalse(connected);
                this.instanceFollowRedirects = followRedirects;
        }
-
+       
        @Override
        public String getRequestMethod() {
-               return this.requestMethod; 
+               return this.requestMethod;
        }
-
+       
        @Override
        public void setRequestMethod(String method) throws ProtocolException {
                assertFalse(connected);
                this.requestMethod = method;
        }
-
+       
        @Override
        public int getResponseCode() throws IOException {
                connect();
                return this.responseCode;
        }
-
+       
        public void setResponseCode(int code) {
                this.responseCode = code;
        }
        
-
+       
        @Override
        public void addRequestProperty(String key, String value) {
                assertFalse(connected);
-               assertFalse(this.requestProperties.containsKey(key.toLowerCase()));
-               this.requestProperties.put(key.toLowerCase(), value);
+               assertFalse(this.requestProperties.containsKey(key.toLowerCase(Locale.ENGLISH)));
+               this.requestProperties.put(key.toLowerCase(Locale.ENGLISH), value);
        }
-
-
+       
+       
        @Override
        public void setRequestProperty(String key, String value) {
                assertFalse(connected);
-               this.requestProperties.put(key.toLowerCase(), value);
+               this.requestProperties.put(key.toLowerCase(Locale.ENGLISH), value);
        }
-
-
+       
+       
        @Override
        public String getRequestProperty(String key) {
-               return this.requestProperties.get(key.toLowerCase());
+               return this.requestProperties.get(key.toLowerCase(Locale.ENGLISH));
        }
-
-
+       
+       
        @Override
        public int getConnectTimeout() {
                return this.connectTimeout;
        }
-
+       
        @Override
        public void setConnectTimeout(int timeout) {
                assertFalse(connected);
                this.connectTimeout = timeout;
        }
-
-
-
+       
+       
+       
        @Override
        public String getContentEncoding() {
                connect();
@@ -189,9 +190,9 @@ public class HttpURLConnectionMock extends HttpURLConnection {
        public void setContentEncoding(String encoding) {
                this.contentEncoding = encoding;
        }
-
-
-
+       
+       
+       
        @Override
        public int getContentLength() {
                connect();
@@ -199,7 +200,7 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                        return 0;
                return content.length;
        }
-
+       
        public void setContent(byte[] content) {
                this.content = content;
        }
@@ -211,8 +212,8 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                        fail("UTF-8");
                }
        }
-
-
+       
+       
        @Override
        public String getContentType() {
                connect();
@@ -222,35 +223,35 @@ public class HttpURLConnectionMock extends HttpURLConnection {
        public void setContentType(String type) {
                this.contentType = type;
        }
-
-
-
+       
+       
+       
        @Override
        public boolean getDoInput() {
                return this.doInput;
        }
-
-
+       
+       
        @Override
        public void setDoInput(boolean doinput) {
                assertFalse(connected);
                this.doInput = doinput;
        }
-
-
+       
+       
        @Override
        public boolean getDoOutput() {
                return this.doOutput;
        }
-
-
+       
+       
        @Override
        public void setDoOutput(boolean dooutput) {
                assertFalse(connected);
                this.doOutput = dooutput;
        }
-
-
+       
+       
        @Override
        public InputStream getInputStream() throws IOException {
                assertTrue(doInput);
@@ -261,8 +262,8 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                inputStream = new ByteArrayInputStream(content);
                return inputStream;
        }
-
-
+       
+       
        @Override
        public OutputStream getOutputStream() throws IOException {
                assertTrue(doOutput);
@@ -283,29 +284,26 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                        return null;
                }
        }
-
-
-
+       
+       
+       
        @Override
        public void setUseCaches(boolean usecaches) {
                assertFalse(connected);
                this.useCaches = usecaches;
        }
-
-
-
+       
+       
+       
        @Override
        public boolean getUseCaches() {
                return this.useCaches;
        }
-
-
-
-
-
-
-
-
+       
+       
+       
+       
+       
        private void assertNull(Object o) {
                try {
                        org.junit.Assert.assertNull(o);
@@ -314,7 +312,7 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                        throw e;
                }
        }
-
+       
        private void assertNotNull(Object o) {
                try {
                        org.junit.Assert.assertNotNull(o);
@@ -323,7 +321,7 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                        throw e;
                }
        }
-
+       
        private void assertTrue(boolean o) {
                try {
                        org.junit.Assert.assertTrue(o);
@@ -332,7 +330,7 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                        throw e;
                }
        }
-
+       
        private void assertFalse(boolean o) {
                try {
                        org.junit.Assert.assertFalse(o);
@@ -341,209 +339,196 @@ public class HttpURLConnectionMock extends HttpURLConnection {
                        throw e;
                }
        }
-
+       
        private void fail(String msg) {
                failed = true;
                org.junit.Assert.fail(msg);
        }
-
-
-
-       
-
-
-
-
-
        
        
        
        
-
-       
        
-
-
        @Override
        public InputStream getErrorStream() {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public String getHeaderField(int n) {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public long getHeaderFieldDate(String name, long Default) {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public String getHeaderFieldKey(int n) {
                throw new UnsupportedOperationException();
        }
-
-
+       
+       
        @Override
        public Permission getPermission() throws IOException {
                throw new UnsupportedOperationException();
        }
-
-
+       
+       
        @Override
        public String getResponseMessage() throws IOException {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public void setChunkedStreamingMode(int chunklen) {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public void setFixedLengthStreamingMode(int contentLength) {
                throw new UnsupportedOperationException();
        }
-
-
-
-
-
+       
+       
+       
+       
+       
        @Override
        public boolean getAllowUserInteraction() {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public Object getContent() throws IOException {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @SuppressWarnings("unchecked")
        @Override
        public Object getContent(Class[] classes) throws IOException {
                throw new UnsupportedOperationException();
        }
-
-
+       
+       
        @Override
        public long getDate() {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public boolean getDefaultUseCaches() {
                throw new UnsupportedOperationException();
        }
-
-
+       
+       
        @Override
        public long getExpiration() {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public String getHeaderField(String name) {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public int getHeaderFieldInt(String name, int Default) {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public Map<String, List<String>> getHeaderFields() {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public long getIfModifiedSince() {
                throw new UnsupportedOperationException();
        }
-
-
+       
+       
        @Override
        public long getLastModified() {
                throw new UnsupportedOperationException();
        }
-
+       
        @Override
        public int getReadTimeout() {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public Map<String, List<String>> getRequestProperties() {
                throw new UnsupportedOperationException();
        }
-
-
+       
+       
        @Override
        public URL getURL() {
                throw new UnsupportedOperationException();
        }
-
-
-
+       
+       
+       
        @Override
        public void setAllowUserInteraction(boolean allowuserinteraction) {
                throw new UnsupportedOperationException();
        }
-
+       
        @Override
        public void setDefaultUseCaches(boolean defaultusecaches) {
                throw new UnsupportedOperationException();
        }
-
-
+       
+       
        @Override
        public void setIfModifiedSince(long ifmodifiedsince) {
                throw new UnsupportedOperationException();
        }
-
-
+       
+       
        @Override
        public void setReadTimeout(int timeout) {
                throw new UnsupportedOperationException();
        }
-
-
-
-
-
+       
+       
+       
+       
+       
        @Override
        public String toString() {
                throw new UnsupportedOperationException();
        }
-
+       
        
        
        
diff --git a/core/test/net/sf/openrocket/gui/print/PrintUnitTest.java b/core/test/net/sf/openrocket/gui/print/PrintUnitTest.java
new file mode 100644 (file)
index 0000000..f92d18b
--- /dev/null
@@ -0,0 +1,49 @@
+package net.sf.openrocket.gui.print;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+* PrintUnit Tester.
+*
+*/
+public class PrintUnitTest {
+
+    /**
+     *
+     * Method: toMillis(double length)
+     *
+     */
+    @Test
+    public void testToMillis() throws Exception {
+        Assert.assertEquals(25.400000, PrintUnit.INCHES.toMillis(1), 0.00001);
+        Assert.assertEquals(1, PrintUnit.MILLIMETERS.toInches(PrintUnit.INCHES.toMillis(1)), 0.000001);
+    }
+
+    /**
+     *
+     * Method: toCentis(double length)
+     *
+     */
+    @Test
+    public void testToCentis() throws Exception {
+        Assert.assertEquals(4, PrintUnit.CENTIMETERS.toMeters(PrintUnit.METERS.toCentis(4)), 0.000001);
+        Assert.assertEquals(4, PrintUnit.CENTIMETERS.toPoints(PrintUnit.POINTS.toCentis(4)), 0.000001);
+    }
+
+    /**
+     *
+     * Method: toPoints(double length)
+     *
+     */
+    @Test
+    public void testToPoints() throws Exception {
+        Assert.assertEquals(1, PrintUnit.POINTS.toInches(72), 0.00001);
+        Assert.assertEquals(25.4, PrintUnit.POINTS.toMillis(72), 0.00001);
+        Assert.assertEquals(1, PrintUnit.MILLIMETERS.toPoints(PrintUnit.POINTS.toMillis(1)), 0.000001);
+
+        Assert.assertEquals(28.3464567, PrintUnit.CENTIMETERS.toPoints(1), 0.000001d);
+    }
+
+
+}
diff --git a/core/test/net/sf/openrocket/l10n/TestDebugTranslator.java b/core/test/net/sf/openrocket/l10n/TestDebugTranslator.java
new file mode 100644 (file)
index 0000000..698094f
--- /dev/null
@@ -0,0 +1,24 @@
+package net.sf.openrocket.l10n;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class TestDebugTranslator {
+       
+       @Test
+       public void testGetEnglish() {
+               DebugTranslator trans = new DebugTranslator(null);
+               assertEquals("[material:Paper (office)]", trans.get("material", "Paper (office)"));
+       }
+       
+       
+       @Test
+       public void testGetBase() {
+               DebugTranslator trans = new DebugTranslator(null);
+               assertEquals("Paper (office)", trans.getBaseText("material", "[material:Paper (office)]"));
+               assertEquals("Papier (toilet)", trans.getBaseText("material", "Papier (toilet)"));
+       }
+       
+       
+}
diff --git a/core/test/net/sf/openrocket/l10n/TestL10N.java b/core/test/net/sf/openrocket/l10n/TestL10N.java
new file mode 100644 (file)
index 0000000..6194931
--- /dev/null
@@ -0,0 +1,29 @@
+package net.sf.openrocket.l10n;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.util.Chars;
+
+import org.junit.Test;
+
+public class TestL10N {
+       
+       @Test
+       public void testNormalize() {
+               assertEquals("hello", L10N.normalize("hello"));
+               assertEquals("hello", L10N.normalize("Hello"));
+               assertEquals("hello", L10N.normalize(" \t Hello \n "));
+               assertEquals("hello", L10N.normalize("H\u00eall\u00d6"));
+               assertEquals("hello_world", L10N.normalize("Hello World!"));
+               assertEquals("hello_world", L10N.normalize("?  Hello\nWorld  !"));
+               assertEquals("hello_123", L10N.normalize("Hello  123!"));
+               assertEquals("hello_123", L10N.normalize("Hello/123?"));
+               
+               assertEquals("plywood_birch", L10N.normalize("Plywood (birch)"));
+               assertEquals("styrofoam_blue_foam_xps", L10N.normalize("Styrofoam \"Blue foam\" (XPS)"));
+               assertEquals("tubular_nylon_11_mm_7_16_in", L10N.normalize("Tubular nylon (11 mm, 7/16 in)"));
+               
+               assertEquals("m2", L10N.normalize("m" + Chars.SQUARED));
+               assertEquals("a_b", L10N.normalize("a" + Chars.NBSP + "b"));
+               assertEquals("1_2a", L10N.normalize(Chars.FRAC12 + "A"));
+       }
+}
index db7dbfc79bde1eab057ec5992866f85e21e05d7e..992bcc2cea54eff9de69a90e7816b8ede16f8f03 100644 (file)
@@ -5,18 +5,35 @@ import static org.junit.Assert.*;
 import java.util.Locale;
 import java.util.MissingResourceException;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
 
 public class TestResourceBundleTranslator {
        
+       private Locale originalDefaultLocale;
+       
+       @Before
+       public void setup() {
+               // Default locale affects resource bundles, so set something non-English
+               this.originalDefaultLocale = Locale.getDefault();
+               Locale.setDefault(Locale.GERMAN);
+       }
+       
+       @After
+       public void teardown() {
+               Locale.setDefault(originalDefaultLocale);
+       }
+       
+       
        @Test
-       public void testSuccessfulUS() {
-               ResourceBundleTranslator trans = new ResourceBundleTranslator("l10n.messages", Locale.US);
-               assertEquals("messages.properties", trans.get("debug.currentFile"));
+       public void testSuccessfulDefault() {
+               ResourceBundleTranslator trans = new ResourceBundleTranslator("l10n.messages");
+               assertEquals("messages_de.properties", trans.get("debug.currentFile"));
        }
        
        @Test
-       public void testSuccessfulFR() {
+       public void testSuccessfulNonDefault() {
                ResourceBundleTranslator trans = new ResourceBundleTranslator("l10n.messages", Locale.FRENCH);
                assertEquals("messages_fr.properties", trans.get("debug.currentFile"));
        }
@@ -31,4 +48,20 @@ public class TestResourceBundleTranslator {
                }
        }
        
+       @Test
+       public void testGetEnglish() {
+               ResourceBundleTranslator trans = new ResourceBundleTranslator("l10n.messages", Locale.FRENCH);
+               assertEquals("Papier (bureau)", trans.get("material", "Paper (office)"));
+               assertEquals("Paper (toilet)", trans.get("material", "Paper (toilet)"));
+       }
+       
+       
+       @Test
+       public void testGetBase() {
+               ResourceBundleTranslator trans = new ResourceBundleTranslator("l10n.messages", Locale.FRENCH);
+               assertEquals("Paper (office)", trans.getBaseText("material", "Papier (bureau)"));
+               assertEquals("Papier (toilet)", trans.getBaseText("material", "Papier (toilet)"));
+       }
+       
+       
 }
index 6870c5f2c2429adcc6ef03b3a221ced57b57975c..cd0ce25efb94a67caf72297627a224aad925980f 100644 (file)
@@ -24,6 +24,18 @@ public class ManufacturerTest {
                
        }
        
+       public void testContrail() {
+               Manufacturer c1, c2;
+               
+               c1 = Manufacturer.getManufacturer("Contrail" );
+               
+               // Used in rsp files.
+               c2 = Manufacturer.getManufacturer("Contrail_Rockets");
+               
+               assertNotNull(c1);
+               assertEquals(c1,c2);
+       }
+       
        @Test
        public void testNew() {
                
diff --git a/core/test/net/sf/openrocket/preset/BodyTubeComponentTests.java b/core/test/net/sf/openrocket/preset/BodyTubeComponentTests.java
new file mode 100644 (file)
index 0000000..891d9ed
--- /dev/null
@@ -0,0 +1,142 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.BodyTube;
+import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to BodyTube RocketComponents through
+ * the BodyTube.loadFromPreset mechanism.
+ * 
+ * Test BodyTube is well defined.
+ * 
+ * Test calling setters on BodyTube will clear the ComponentPreset.
+ * 
+ */
+public class BodyTubeComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               BodyTube bt = new BodyTube();
+               
+               assertSame(ComponentPreset.Type.BODY_TUBE, bt.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               BodyTube bt = new BodyTube();
+               
+               bt.loadPreset(preset);
+               
+               assertEquals(2.0, bt.getLength(), 0.0);
+               assertEquals(1.0, bt.getOuterRadius(), 0.0);
+               assertEquals(1.0, bt.getAftRadius(), 0.0);
+               assertEquals(0.5, bt.getInnerRadius(), 0.0);
+               
+               assertFalse(bt.isAftRadiusAutomatic());
+               assertFalse(bt.isFilled());
+               assertFalse(bt.isForeRadiusAutomatic());
+               assertFalse(bt.isOuterRadiusAutomatic());
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), bt.getMaterial());
+               assertEquals(100.0, bt.getMass(), 0.05);
+       }
+       
+       @Test
+       public void changeLengthLeavesPreset() {
+               BodyTube bt = new BodyTube();
+               
+               bt.loadPreset(preset);
+               
+               bt.setLength(1.0);
+               
+               assertSame(preset, bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeODClearsPreset() {
+               BodyTube bt = new BodyTube();
+               
+               bt.loadPreset(preset);
+               
+               bt.setOuterRadius(2.0);
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeIDClearsPreset() {
+               BodyTube bt = new BodyTube();
+               
+               bt.loadPreset(preset);
+               
+               bt.setInnerRadius(0.75);
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeThicknessClearsPreset() {
+               BodyTube bt = new BodyTube();
+               
+               bt.loadPreset(preset);
+               
+               bt.setThickness(0.1);
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               BodyTube bt = new BodyTube();
+               
+               bt.loadPreset(preset);
+               
+               bt.setMaterial(Material.newMaterial(Material.Type.BULK, "new", 1.0, true));
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeFinishLeavesPreset() {
+               BodyTube bt = new BodyTube();
+               
+               bt.loadPreset(preset);
+               
+               bt.setFinish(Finish.POLISHED);
+               
+               assertSame(preset, bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeFillClearsPreset() {
+               BodyTube bt = new BodyTube();
+               
+               bt.loadPreset(preset);
+               
+               bt.setFilled(true);
+               
+               assertNull(bt.getPresetComponent());
+       }
+}
diff --git a/core/test/net/sf/openrocket/preset/BodyTubePresetTests.java b/core/test/net/sf/openrocket/preset/BodyTubePresetTests.java
new file mode 100644 (file)
index 0000000..33d7529
--- /dev/null
@@ -0,0 +1,271 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+
+import org.junit.Test;
+
+/**
+ * Test construction of BODY_TUBE type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class BodyTubePresetTests {
+       
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.MANUFACTURER,
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Manufacturer specified",
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyOuterDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyInnerDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.INNER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyThicknessDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.THICKNESS, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testComputeInnerDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(1.0, preset.get(ComponentPreset.INNER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeOuterDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(2.0, preset.get(ComponentPreset.OUTER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThickness() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThicknessLooses() throws Exception {
+               // If all OUTER_DIAMETER, INNER_DIAMETER and THICKNESS are
+               // specified, THICKNESS is recomputed.
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 15.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeDensityNoMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("TubeCustom", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+       @Test
+       public void testMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(2.0, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+               
+       }
+       
+       @Test
+       public void testComputeDensityWithMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/BulkHeadComponentTests.java b/core/test/net/sf/openrocket/preset/BulkHeadComponentTests.java
new file mode 100644 (file)
index 0000000..6a1c846
--- /dev/null
@@ -0,0 +1,103 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.Bulkhead;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to Bulkhead RocketComponents through
+ * the Bulkhead.loadFromPreset mechanism.
+ * 
+ * Test Bulkhead is well defined.
+ * 
+ * Test calling setters on Bulkhead will clear the ComponentPreset.
+ * 
+ */
+public class BulkHeadComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               Bulkhead bt = new Bulkhead();
+               
+               assertSame(ComponentPreset.Type.BULK_HEAD, bt.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               Bulkhead bt = new Bulkhead();
+               
+               bt.loadPreset(preset);
+               
+               assertEquals(2.0, bt.getLength(), 0.0);
+               assertEquals(1.0, bt.getOuterRadius(), 0.0);
+               
+               assertFalse(bt.isOuterRadiusAutomatic());
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), bt.getMaterial());
+               assertEquals(100.0, bt.getMass(), 0.05);
+       }
+       
+       @Test
+       public void changeLengthLeavesPreset() {
+               Bulkhead bt = new Bulkhead();
+               
+               bt.loadPreset(preset);
+               
+               bt.setLength(1.0);
+               
+               assertSame(preset, bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeODClearsPreset() {
+               Bulkhead bt = new Bulkhead();
+               
+               bt.loadPreset(preset);
+               
+               bt.setOuterRadius(2.0);
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeODAutomaticClearsPreset() {
+               Bulkhead bt = new Bulkhead();
+               
+               bt.loadPreset(preset);
+               
+               bt.setOuterRadiusAutomatic(true);
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               Bulkhead bt = new Bulkhead();
+               
+               bt.loadPreset(preset);
+               
+               bt.setMaterial(Material.newMaterial(Material.Type.BULK, "new", 1.0, true));
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/BulkHeadPresetTests.java b/core/test/net/sf/openrocket/preset/BulkHeadPresetTests.java
new file mode 100644 (file)
index 0000000..2f393ba
--- /dev/null
@@ -0,0 +1,173 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+
+import org.junit.Test;
+
+/**
+ * Test construction of BULK_HEAD type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class BulkHeadPresetTests {
+       
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.MANUFACTURER,
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                                       "No Manufacturer specified",
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "No OuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "No OuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                                       "No Length specified",
+                                                       "No OuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOuterDiameterRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                       "No OuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testComputeDensityNoMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("BulkHeadCustom", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+       @Test
+       public void testMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(2.0, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+               
+       }
+       
+       @Test
+       public void testComputeDensityWithMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BULK_HEAD);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/CenteringRingComponentTests.java b/core/test/net/sf/openrocket/preset/CenteringRingComponentTests.java
new file mode 100644 (file)
index 0000000..dac3f8f
--- /dev/null
@@ -0,0 +1,116 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.CenteringRing;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to CenteringRing RocketComponents through
+ * the CenteringRing.loadFromPreset mechanism.
+ * 
+ * Test CenteringRing is well defined.
+ * 
+ * Test calling setters on CenteringRing will clear the ComponentPreset.
+ * 
+ */
+public class CenteringRingComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               CenteringRing cr = new CenteringRing();
+               
+               assertSame(ComponentPreset.Type.CENTERING_RING, cr.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               CenteringRing cr = new CenteringRing();
+               
+               cr.loadPreset(preset);
+               
+               assertEquals(2.0, cr.getLength(), 0.0);
+               assertEquals(1.0, cr.getOuterRadius(), 0.0);
+               assertEquals(0.5, cr.getInnerRadius(), 0.0);
+               
+               assertFalse(cr.isOuterRadiusAutomatic());
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), cr.getMaterial());
+               assertEquals(100.0, cr.getMass(), 0.05);
+       }
+       
+       @Test
+       public void changeLengthLeavesPreset() {
+               CenteringRing cr = new CenteringRing();
+               
+               cr.loadPreset(preset);
+               
+               cr.setLength(1.0);
+               
+               assertSame(preset, cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeODClearsPreset() {
+               CenteringRing cr = new CenteringRing();
+               
+               cr.loadPreset(preset);
+               
+               cr.setOuterRadius(2.0);
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeIDClearsPreset() {
+               CenteringRing cr = new CenteringRing();
+               
+               cr.loadPreset(preset);
+               
+               cr.setInnerRadius(0.75);
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeThicknessClearsPreset() {
+               CenteringRing cr = new CenteringRing();
+               
+               cr.loadPreset(preset);
+               
+               cr.setThickness(0.1);
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               CenteringRing cr = new CenteringRing();
+               
+               cr.loadPreset(preset);
+               
+               cr.setMaterial(Material.newMaterial(Material.Type.BULK, "new", 1.0, true));
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/CenteringRingPresetTests.java b/core/test/net/sf/openrocket/preset/CenteringRingPresetTests.java
new file mode 100644 (file)
index 0000000..718e4be
--- /dev/null
@@ -0,0 +1,271 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+
+import org.junit.Test;
+
+/**
+ * Test construction of CENTERING_RING type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class CenteringRingPresetTests {
+       
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.MANUFACTURER,
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Manufacturer specified",
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyOuterDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyInnerDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.INNER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyThicknessDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.THICKNESS, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testComputeInnerDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(1.0, preset.get(ComponentPreset.INNER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeOuterDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(2.0, preset.get(ComponentPreset.OUTER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThickness() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThicknessLooses() throws Exception {
+               // If all OUTER_DIAMETER, INNER_DIAMETER and THICKNESS are
+               // specified, THICKNESS is recomputed.
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 15.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeDensityNoMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("CenteringRingCustom", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+       @Test
+       public void testMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(2.0, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+               
+       }
+       
+       @Test
+       public void testComputeDensityWithMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.CENTERING_RING);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/EngineBlockComponentTests.java b/core/test/net/sf/openrocket/preset/EngineBlockComponentTests.java
new file mode 100644 (file)
index 0000000..759a3b7
--- /dev/null
@@ -0,0 +1,116 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.EngineBlock;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to EngineBlock RocketComponents through
+ * the EngineBlock.loadFromPreset mechanism.
+ * 
+ * Test EngineBlock is well defined.
+ * 
+ * Test calling setters on EngineBlock will clear the ComponentPreset.
+ * 
+ */
+public class EngineBlockComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               EngineBlock eb = new EngineBlock();
+               
+               assertSame(ComponentPreset.Type.ENGINE_BLOCK, eb.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               EngineBlock eb = new EngineBlock();
+               
+               eb.loadPreset(preset);
+               
+               assertEquals(2.0, eb.getLength(), 0.0);
+               assertEquals(1.0, eb.getOuterRadius(), 0.0);
+               assertEquals(0.5, eb.getInnerRadius(), 0.0);
+               
+               assertFalse(eb.isOuterRadiusAutomatic());
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), eb.getMaterial());
+               assertEquals(100.0, eb.getMass(), 0.05);
+       }
+       
+       @Test
+       public void changeLengthLeavesPreset() {
+               EngineBlock eb = new EngineBlock();
+               
+               eb.loadPreset(preset);
+               
+               eb.setLength(1.0);
+               
+               assertSame(preset, eb.getPresetComponent());
+       }
+       
+       @Test
+       public void changeODClearsPreset() {
+               EngineBlock eb = new EngineBlock();
+               
+               eb.loadPreset(preset);
+               
+               eb.setOuterRadius(2.0);
+               
+               assertNull(eb.getPresetComponent());
+       }
+       
+       @Test
+       public void changeIDClearsPreset() {
+               EngineBlock eb = new EngineBlock();
+               
+               eb.loadPreset(preset);
+               
+               eb.setInnerRadius(0.75);
+               
+               assertNull(eb.getPresetComponent());
+       }
+       
+       @Test
+       public void changeThicknessClearsPreset() {
+               EngineBlock eb = new EngineBlock();
+               
+               eb.loadPreset(preset);
+               
+               eb.setThickness(0.1);
+               
+               assertNull(eb.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               EngineBlock eb = new EngineBlock();
+               
+               eb.loadPreset(preset);
+               
+               eb.setMaterial(Material.newMaterial(Material.Type.BULK, "new", 1.0, true));
+               
+               assertNull(eb.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/EngineBlockPresetTests.java b/core/test/net/sf/openrocket/preset/EngineBlockPresetTests.java
new file mode 100644 (file)
index 0000000..d032b51
--- /dev/null
@@ -0,0 +1,271 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+
+import org.junit.Test;
+
+/**
+ * Test construction of ENGINE_BLOCK type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class EngineBlockPresetTests {
+       
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.MANUFACTURER,
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Manufacturer specified",
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyOuterDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyInnerDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.INNER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyThicknessDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.THICKNESS, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testComputeInnerDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(1.0, preset.get(ComponentPreset.INNER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeOuterDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(2.0, preset.get(ComponentPreset.OUTER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThickness() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThicknessLooses() throws Exception {
+               // If all OUTER_DIAMETER, INNER_DIAMETER and THICKNESS are
+               // specified, THICKNESS is recomputed.
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 15.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeDensityNoMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("EngineBlockCustom", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+       @Test
+       public void testMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(2.0, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+               
+       }
+       
+       @Test
+       public void testComputeDensityWithMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.ENGINE_BLOCK);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/LaunchLugComponentTests.java b/core/test/net/sf/openrocket/preset/LaunchLugComponentTests.java
new file mode 100644 (file)
index 0000000..e232aa6
--- /dev/null
@@ -0,0 +1,126 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
+import net.sf.openrocket.rocketcomponent.LaunchLug;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to LaunchLug RocketComponents through
+ * the LaunchLug.loadFromPreset mechanism.
+ * 
+ * Test LaunchLug is well defined.
+ * 
+ * Test calling setters on LaunchLug will clear the ComponentPreset.
+ * 
+ */
+public class LaunchLugComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               LaunchLug bt = new LaunchLug();
+               
+               assertSame(ComponentPreset.Type.LAUNCH_LUG, bt.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               LaunchLug bt = new LaunchLug();
+               
+               bt.loadPreset(preset);
+               
+               assertEquals(2.0, bt.getLength(), 0.0);
+               assertEquals(1.0, bt.getOuterRadius(), 0.0);
+               assertEquals(0.5, bt.getInnerRadius(), 0.0);
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), bt.getMaterial());
+               assertEquals(100.0, bt.getMass(), 0.05);
+       }
+       
+       @Test
+       public void changeLengthLeavesPreset() {
+               LaunchLug bt = new LaunchLug();
+               
+               bt.loadPreset(preset);
+               
+               bt.setLength(1.0);
+               
+               assertSame(preset, bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeODClearsPreset() {
+               LaunchLug bt = new LaunchLug();
+               
+               bt.loadPreset(preset);
+               
+               bt.setOuterRadius(2.0);
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeIDClearsPreset() {
+               LaunchLug bt = new LaunchLug();
+               
+               bt.loadPreset(preset);
+               
+               bt.setInnerRadius(0.75);
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeThicknessClearsPreset() {
+               LaunchLug bt = new LaunchLug();
+               
+               bt.loadPreset(preset);
+               
+               bt.setThickness(0.1);
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               LaunchLug bt = new LaunchLug();
+               
+               bt.loadPreset(preset);
+               
+               bt.setMaterial(Material.newMaterial(Material.Type.BULK, "new", 1.0, true));
+               
+               assertNull(bt.getPresetComponent());
+       }
+       
+       @Test
+       public void changeFinishLeavesPreset() {
+               LaunchLug bt = new LaunchLug();
+               
+               bt.loadPreset(preset);
+               
+               bt.setFinish(Finish.POLISHED);
+               
+               assertSame(preset, bt.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/LaunchLugPresetTests.java b/core/test/net/sf/openrocket/preset/LaunchLugPresetTests.java
new file mode 100644 (file)
index 0000000..207931d
--- /dev/null
@@ -0,0 +1,271 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+
+import org.junit.Test;
+
+/**
+ * Test construction of LAUNCH_LUG type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class LaunchLugPresetTests {
+       
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.MANUFACTURER,
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Manufacturer specified",
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyOuterDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyInnerDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.INNER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyThicknessDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.THICKNESS, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testComputeInnerDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(1.0, preset.get(ComponentPreset.INNER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeOuterDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(2.0, preset.get(ComponentPreset.OUTER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThickness() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThicknessLooses() throws Exception {
+               // If all OUTER_DIAMETER, INNER_DIAMETER and THICKNESS are
+               // specified, THICKNESS is recomputed.
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 15.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeDensityNoMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("TubeCustom", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+       @Test
+       public void testMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(2.0, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+               
+       }
+       
+       @Test
+       public void testComputeDensityWithMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.LAUNCH_LUG);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/NoseConeComponentTests.java b/core/test/net/sf/openrocket/preset/NoseConeComponentTests.java
new file mode 100644 (file)
index 0000000..37f7dd4
--- /dev/null
@@ -0,0 +1,174 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
+import net.sf.openrocket.rocketcomponent.NoseCone;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to NoseCone RocketComponents through
+ * the NoseCone.loadFromPreset mechanism.
+ * 
+ * Test NoseCone is well defined.
+ * 
+ * Test calling setters on NoseCone will clear the ComponentPreset.
+ * 
+ */
+public class NoseConeComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+               presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.AFT_SHOULDER_LENGTH, 1.0);
+               presetspec.put(ComponentPreset.AFT_SHOULDER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.FILLED, true);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               NoseCone nc = new NoseCone();
+               
+               assertSame(ComponentPreset.Type.NOSE_CONE, nc.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               assertEquals(2.0, nc.getLength(), 0.0);
+               assertSame(Transition.Shape.CONICAL, nc.getType());
+               assertEquals(1.0, nc.getAftRadius(), 0.0);
+               assertEquals(0.0, nc.getForeShoulderLength(), 0.0);
+               assertEquals(0.0, nc.getForeShoulderRadius(), 0.0);
+               assertEquals(1.0, nc.getAftShoulderLength(), 0.0);
+               assertEquals(0.5, nc.getAftShoulderRadius(), 0.0);
+               assertEquals(0.5, nc.getAftShoulderThickness(), 0.0);
+               
+               assertFalse(nc.isForeRadiusAutomatic());
+               assertFalse(nc.isAftRadiusAutomatic());
+               assertTrue(nc.isFilled());
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), nc.getMaterial());
+               assertEquals(100.0, nc.getMass(), 0.05);
+       }
+       
+       @Test
+       public void changeLengthClearsPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setLength(1.0);
+               
+               assertNull(nc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAftRadiusClearsPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setAftRadius(2.0);
+               
+               assertNull(nc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAftRadiusAutomaticClearsPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setAftRadiusAutomatic(true);
+               
+               assertNull(nc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAftShoulderRadiusClearsPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setAftShoulderRadius(2.0);
+               
+               assertNull(nc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAftSholderLengthLeavesPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setAftShoulderLength(2.0);
+               
+               assertSame(preset, nc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeThicknessClearsPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setThickness(0.1);
+               
+               assertNull(nc.getPresetComponent());
+       }
+       
+       
+       @Test
+       public void changeFilledClearsPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setFilled(false);
+               
+               assertNull(nc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "new", 1.0, true));
+               
+               assertNull(nc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeFinishLeavesPreset() {
+               NoseCone nc = new NoseCone();
+               
+               nc.loadPreset(preset);
+               
+               nc.setFinish(Finish.POLISHED);
+               
+               assertSame(preset, nc.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/NoseConePresetTests.java b/core/test/net/sf/openrocket/preset/NoseConePresetTests.java
new file mode 100644 (file)
index 0000000..56e849c
--- /dev/null
@@ -0,0 +1,208 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Test;
+
+/**
+ * Test construction of NOSE_CONE type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class NoseConePresetTests extends BaseTestCase {
+       
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.MANUFACTURER,
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.AFT_OUTER_DIAMETER,
+                                                       ComponentPreset.SHAPE
+                                       },
+                                       new String[] {
+                                                       "No Manufacturer specified",
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "No AftOuterDiameter specified",
+                                                       "No Shape specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.AFT_OUTER_DIAMETER,
+                                                       ComponentPreset.SHAPE
+                                       },
+                                       new String[] {
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "No AftOuterDiameter specified",
+                                                       "No Shape specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.AFT_OUTER_DIAMETER,
+                                                       ComponentPreset.SHAPE
+                                       },
+                                       new String[] {
+                                                       "No Length specified",
+                                                       "No AftOuterDiameter specified",
+                                                       "No Shape specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testShapeRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.AFT_OUTER_DIAMETER,
+                                                       ComponentPreset.SHAPE
+                                       },
+                                       new String[] {
+                                                       "No AftOuterDiameter specified",
+                                                       "No Shape specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testAftOuterDiameterRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.AFT_OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                       "No AftOuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testComputeDensityNoMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+               presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.FILLED, true);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // constants put into the presetspec above.
+               double volume = /*base area*/Math.PI;
+               volume *= 2.0 /* times height *// 3.0; /* one third */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("NoseConeCustom", preset.get(ComponentPreset.MATERIAL).getName());
+               // note - epsilon is 1% of the simple computation of density
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.01 * density);
+       }
+       
+       @Test
+       public void testMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+               presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(2.0, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+               
+       }
+       
+       @Test
+       public void testComputeDensityWithMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.NOSE_CONE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+               presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.FILLED, true);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // constants put into the presetspec above.
+               double volume = /*base area*/Math.PI;
+               volume *= 2.0 /* times height *// 3.0; /* one third */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               // note - epsilon is 1% of the simple computation of density
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.01 * density);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/ParachutePresetTests.java b/core/test/net/sf/openrocket/preset/ParachutePresetTests.java
new file mode 100644 (file)
index 0000000..e6b3110
--- /dev/null
@@ -0,0 +1,138 @@
+package net.sf.openrocket.preset;
+
+import net.sf.openrocket.motor.Manufacturer;
+
+import org.junit.Test;
+
+/**
+ * Test construction of PARACHUTE type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class ParachutePresetTests {
+
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.PARACHUTE);
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.MANUFACTURER, 
+                                       ComponentPreset.PARTNO, 
+                                       ComponentPreset.DIAMETER,
+                                       ComponentPreset.LINE_COUNT,
+                                       ComponentPreset.LINE_LENGTH
+                       },
+                       new String[] {
+                                       "No Manufacturer specified",
+                                       "No PartNo specified",
+                                       "No Diameter specified",
+                                       "No LineCount specified",
+                                       "No LineLength specified"
+                       }
+                                       );
+               }
+       }
+
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.PARACHUTE);
+                       presetspec.put( ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.PARTNO, 
+                                       ComponentPreset.DIAMETER,
+                                       ComponentPreset.LINE_COUNT,
+                                       ComponentPreset.LINE_LENGTH
+                       },
+                       new String[] {
+                                       "No PartNo specified",
+                                       "No Diameter specified",
+                                       "No LineCount specified",
+                                       "No LineLength specified"
+                       }
+                                       );
+               }
+       }
+
+       @Test
+       public void testDiameterRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.PARACHUTE);
+                       presetspec.put( ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put( ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.DIAMETER,
+                                       ComponentPreset.LINE_COUNT,
+                                       ComponentPreset.LINE_LENGTH
+                       },
+                       new String[] {
+                                       "No Diameter specified",
+                                       "No LineCount specified",
+                                       "No LineLength specified"
+                       }
+                                       );
+               }
+       }
+
+       @Test
+       public void testLineCountRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.PARACHUTE);
+                       presetspec.put( ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put( ComponentPreset.PARTNO, "partno");
+                       presetspec.put( ComponentPreset.DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.LINE_COUNT,
+                                       ComponentPreset.LINE_LENGTH
+                       },
+                       new String[] {
+                                       "No LineCount specified",
+                                       "No LineLength specified"
+                       }
+                                       );
+               }
+       }
+
+       @Test
+       public void testLineLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.PARACHUTE);
+                       presetspec.put( ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put( ComponentPreset.PARTNO, "partno");
+                       presetspec.put( ComponentPreset.DIAMETER, 2.0);
+                       presetspec.put( ComponentPreset.LINE_COUNT, 6);
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.LINE_LENGTH
+                       },
+                       new String[] {
+                                       "No LineLength specified"
+                       }
+                                       );
+               }
+       }
+
+}
diff --git a/core/test/net/sf/openrocket/preset/ParachuterComponentTests.java b/core/test/net/sf/openrocket/preset/ParachuterComponentTests.java
new file mode 100644 (file)
index 0000000..e248996
--- /dev/null
@@ -0,0 +1,128 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.Parachute;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to Parachute RocketComponents through
+ * the Parachute.loadFromPreset mechanism.
+ * 
+ * Test Parachute is well defined.
+ * 
+ * Test calling setters on Parachute will clear the ComponentPreset.
+ * 
+ */
+public class ParachuterComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.PARACHUTE);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.DIAMETER, 20.0);
+               presetspec.put(ComponentPreset.LINE_COUNT, 8);
+               presetspec.put(ComponentPreset.LINE_LENGTH, 12.0);
+               Material m = Material.newMaterial(Material.Type.SURFACE, "testMaterial", 2.0, true);
+               presetspec.put(ComponentPreset.MATERIAL, m);
+               m = Material.newMaterial(Material.Type.LINE, "testLineMaterial", 3, true);
+               presetspec.put(ComponentPreset.LINE_MATERIAL, m);
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               Parachute cr = new Parachute();
+               
+               assertSame(ComponentPreset.Type.PARACHUTE, cr.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               Parachute cr = new Parachute();
+               
+               cr.loadPreset(preset);
+               
+               assertEquals(20.0, cr.getDiameter(), 0.0);
+               assertEquals(8, cr.getLineCount(), 0.0);
+               assertEquals(12.0, cr.getLineLength(), 0.0);
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), cr.getMaterial());
+               assertSame(preset.get(ComponentPreset.LINE_MATERIAL), cr.getLineMaterial());
+       }
+       
+       @Test
+       public void changeDiameterClearsPreset() {
+               Parachute cr = new Parachute();
+               
+               cr.loadPreset(preset);
+               
+               cr.setDiameter(1.0);
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAreaClearsPreset() {
+               Parachute cr = new Parachute();
+               
+               cr.loadPreset(preset);
+               
+               cr.setArea(1.0);
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeLineCountClearsPreset() {
+               Parachute cr = new Parachute();
+               
+               cr.loadPreset(preset);
+               
+               cr.setLineCount(12);
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeLineLengthLeavesPreset() {
+               Parachute cr = new Parachute();
+               
+               cr.loadPreset(preset);
+               
+               cr.setLineLength(24);
+               
+               assertSame(preset, cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               Parachute cr = new Parachute();
+               
+               cr.loadPreset(preset);
+               
+               cr.setMaterial(Material.newMaterial(Material.Type.SURFACE, "new", 1.0, true));
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeLineMaterialLeavesPreset() {
+               Parachute cr = new Parachute();
+               
+               cr.loadPreset(preset);
+               
+               cr.setLineMaterial(Material.newMaterial(Material.Type.LINE, "new", 1.0, true));
+               
+               assertSame(preset, cr.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/PresetAssertHelper.java b/core/test/net/sf/openrocket/preset/PresetAssertHelper.java
new file mode 100644 (file)
index 0000000..84b7c03
--- /dev/null
@@ -0,0 +1,43 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+
+public abstract class PresetAssertHelper {
+
+       public static void assertInvalidPresetException( InvalidComponentPresetException exceptions, TypedKey<?>[] keys, String[] messages ) {
+               if ( keys != null ) {
+                       assertEquals( keys.length, exceptions.getInvalidParameters().size() );
+                       for( TypedKey<?> expectedKey : keys ) {
+                               boolean keyFound = false;
+                               for( TypedKey<?> k : exceptions.getInvalidParameters() ) {
+                                       if ( expectedKey == k ) {
+                                               keyFound = true;
+                                               break;
+                                       }
+                               }
+                               if ( ! keyFound ) {
+                                       fail( "Expected key " + expectedKey + " not in exception");
+                               }
+                       }
+               } else {
+                       assertEquals(0, exceptions.getInvalidParameters().size() );
+               }
+               if ( messages != null ) {
+                       assertEquals( messages.length, exceptions.getErrors().size() );
+                       for( String expectedMessage : messages ) {
+                               boolean stringMatched = false;
+                               for ( String s : exceptions.getErrors() ) {
+                                       if ( s.contains( expectedMessage ) ) {
+                                               stringMatched = true;
+                                               break;
+                                       }
+                               }
+                               if( !stringMatched ) {
+                                       fail( "Expected string \"" + expectedMessage + "\" not reported in errors");
+                               }
+                       }
+               } else {
+                       assertEquals(0, exceptions.getErrors().size() );
+               }
+       }
+}
diff --git a/core/test/net/sf/openrocket/preset/StreamerComponentTests.java b/core/test/net/sf/openrocket/preset/StreamerComponentTests.java
new file mode 100644 (file)
index 0000000..099a8d5
--- /dev/null
@@ -0,0 +1,92 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.Streamer;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to Streamer RocketComponents through
+ * the Streamer.loadFromPreset mechanism.
+ * 
+ * Test Streamer is well defined.
+ * 
+ * Test calling setters on Streamer will clear the ComponentPreset.
+ * 
+ */
+public class StreamerComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.STREAMER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 20.0);
+               presetspec.put(ComponentPreset.WIDTH, 2.0);
+               Material m = Material.newMaterial(Material.Type.SURFACE, "testMaterial", 2.0, true);
+               presetspec.put(ComponentPreset.MATERIAL, m);
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               Streamer cr = new Streamer();
+               
+               assertSame(ComponentPreset.Type.STREAMER, cr.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               Streamer cr = new Streamer();
+               
+               cr.loadPreset(preset);
+               
+               assertEquals(20.0, cr.getStripLength(), 0.0);
+               assertEquals(2.0, cr.getStripWidth(), 0.0);
+               assertEquals(2.0, cr.getLength(), 0.0);
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), cr.getMaterial());
+               assertEquals(80.0, cr.getMass(), 0.05);
+       }
+       
+       @Test
+       public void changeLengthClearsPreset() {
+               Streamer cr = new Streamer();
+               
+               cr.loadPreset(preset);
+               
+               cr.setStripLength(1.0);
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeWidthClearsPreset() {
+               Streamer cr = new Streamer();
+               
+               cr.loadPreset(preset);
+               
+               cr.setStripWidth(1.0);
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               Streamer cr = new Streamer();
+               
+               cr.loadPreset(preset);
+               
+               cr.setMaterial(Material.newMaterial(Material.Type.SURFACE, "new", 1.0, true));
+               
+               assertNull(cr.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/StreamerPresetTests.java b/core/test/net/sf/openrocket/preset/StreamerPresetTests.java
new file mode 100644 (file)
index 0000000..a16fd14
--- /dev/null
@@ -0,0 +1,108 @@
+package net.sf.openrocket.preset;
+
+import net.sf.openrocket.motor.Manufacturer;
+
+import org.junit.Test;
+
+/**
+ * Test construction of STREAMER type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class StreamerPresetTests {
+
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.STREAMER);
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.MANUFACTURER, 
+                                       ComponentPreset.PARTNO, 
+                                       ComponentPreset.LENGTH,
+                                       ComponentPreset.WIDTH
+                       },
+                       new String[] {
+                                       "No Manufacturer specified",
+                                       "No PartNo specified",
+                                       "No Length specified",
+                                       "No Width specified"
+                       }
+                                       );
+               }
+       }
+
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.STREAMER);
+                       presetspec.put( ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.PARTNO, 
+                                       ComponentPreset.LENGTH,
+                                       ComponentPreset.WIDTH
+                       },
+                       new String[] {
+                                       "No PartNo specified",
+                                       "No Length specified",
+                                       "No Width specified"
+                       }
+                                       );
+               }
+       }
+
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.STREAMER);
+                       presetspec.put( ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put( ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.LENGTH,
+                                       ComponentPreset.WIDTH
+                       },
+                       new String[] {
+                                       "No Length specified",
+                                       "No Width specified"
+                       }
+                                       );
+               }
+       }
+
+       @Test
+       public void testWidthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.STREAMER);
+                       presetspec.put( ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put( ComponentPreset.PARTNO, "partno");
+                       presetspec.put( ComponentPreset.LENGTH, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch ( InvalidComponentPresetException ex ) {
+                       PresetAssertHelper.assertInvalidPresetException( ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.WIDTH
+                       },
+                       new String[] {
+                                       "No Width specified"
+                       }
+                                       );
+               }
+       }
+
+}
diff --git a/core/test/net/sf/openrocket/preset/TransitionComponentTests.java b/core/test/net/sf/openrocket/preset/TransitionComponentTests.java
new file mode 100644 (file)
index 0000000..9826613
--- /dev/null
@@ -0,0 +1,210 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to Transition RocketComponents through
+ * the Transition.loadFromPreset mechanism.
+ * 
+ * Test Transition is well defined.
+ * 
+ * Test calling setters on Transition will clear the ComponentPreset.
+ * 
+ */
+public class TransitionComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+               presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.FORE_OUTER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.AFT_SHOULDER_LENGTH, 1.0);
+               presetspec.put(ComponentPreset.AFT_SHOULDER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.FORE_SHOULDER_LENGTH, 1.0);
+               presetspec.put(ComponentPreset.FORE_SHOULDER_DIAMETER, 0.5);
+               presetspec.put(ComponentPreset.FILLED, true);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               Transition tr = new Transition();
+               
+               assertSame(ComponentPreset.Type.TRANSITION, tr.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               assertEquals(2.0, tr.getLength(), 0.0);
+               assertSame(Transition.Shape.CONICAL, tr.getType());
+               assertEquals(1.0, tr.getAftRadius(), 0.0);
+               assertEquals(1.0, tr.getForeShoulderLength(), 0.0);
+               assertEquals(0.25, tr.getForeShoulderRadius(), 0.0);
+               assertEquals(0.25, tr.getForeShoulderThickness(), 0.0);
+               assertEquals(1.0, tr.getAftShoulderLength(), 0.0);
+               assertEquals(0.5, tr.getAftShoulderRadius(), 0.0);
+               assertEquals(0.5, tr.getAftShoulderThickness(), 0.0);
+               
+               assertFalse(tr.isForeRadiusAutomatic());
+               assertFalse(tr.isAftRadiusAutomatic());
+               assertTrue(tr.isFilled());
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), tr.getMaterial());
+               assertEquals(100.0, tr.getMass(), 1.0);
+       }
+       
+       @Test
+       public void changeLengthClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setLength(1.0);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAftRadiusClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setAftRadius(2.0);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAftRadiusAutomaticClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setAftRadiusAutomatic(true);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeForeRadiusClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setForeRadius(2.0);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeForeRadiusAutomaticClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setForeRadiusAutomatic(true);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeForeShoulderRadiusClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setForeShoulderRadius(2.0);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAftShoulderRadiusClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setAftShoulderRadius(2.0);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeAftSholderLengthLeavesPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setAftShoulderLength(2.0);
+               
+               assertSame(preset, tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeThicknessClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setThickness(0.1);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       
+       @Test
+       public void changeFilledClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setFilled(false);
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setMaterial(Material.newMaterial(Material.Type.BULK, "new", 1.0, true));
+               
+               assertNull(tr.getPresetComponent());
+       }
+       
+       @Test
+       public void changeFinishLeavesPreset() {
+               Transition tr = new Transition();
+               
+               tr.loadPreset(preset);
+               
+               tr.setFinish(Finish.POLISHED);
+               
+               assertSame(preset, tr.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/TransitionPresetTests.java b/core/test/net/sf/openrocket/preset/TransitionPresetTests.java
new file mode 100644 (file)
index 0000000..26593dd
--- /dev/null
@@ -0,0 +1,222 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.Transition;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Test;
+
+/**
+ * Test construction of TRANSITION type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class TransitionPresetTests extends BaseTestCase {
+       
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.MANUFACTURER,
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.AFT_OUTER_DIAMETER,
+                                                       ComponentPreset.FORE_OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                                       "No Manufacturer specified",
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "No AftOuterDiameter specified",
+                                                       "No ForeOuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.AFT_OUTER_DIAMETER,
+                                                       ComponentPreset.FORE_OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "No AftOuterDiameter specified",
+                                                       "No ForeOuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.LENGTH,
+                                                       ComponentPreset.AFT_OUTER_DIAMETER,
+                                                       ComponentPreset.FORE_OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                                       "No Length specified",
+                                                       "No AftOuterDiameter specified",
+                                                       "No ForeOuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testAftOuterDiameterRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.AFT_OUTER_DIAMETER,
+                                                       ComponentPreset.FORE_OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                                       "No AftOuterDiameter specified",
+                                                       "No ForeOuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       
+       @Test
+       public void testForeOuterDiameterRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+                       presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.FORE_OUTER_DIAMETER
+                                       },
+                                       new String[] {
+                                       "No ForeOuterDiameter specified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testComputeDensityNoMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+               presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.FORE_OUTER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.FILLED, true);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // constants put into the presetspec above.
+               double volume = /*base area*/Math.PI * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5);
+               
+               volume *= 2.0 /* times height *// 3.0; /* one third */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("TransitionCustom", preset.get(ComponentPreset.MATERIAL).getName());
+               
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.01 * density);
+       }
+       
+       @Test
+       public void testMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+               presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.FORE_OUTER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.FILLED, true);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(2.0, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+               
+       }
+       
+       @Test
+       public void testComputeDensityWithMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TRANSITION);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.SHAPE, Transition.Shape.CONICAL);
+               presetspec.put(ComponentPreset.AFT_OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.FORE_OUTER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.FILLED, true);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // constants put into the presetspec above.
+               double totvolume = /*base area*/Math.PI;
+               
+               totvolume *= 4.0 /* times height *// 3.0; /* one third */
+               
+               double uppervolume = /*fore area*/Math.PI * 0.5 * 0.5;
+               uppervolume *= 2.0 /* times height *// 3.0; /* one third */
+               
+               double volume = totvolume - uppervolume;
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.01 * density);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/TubeCouplerComponentTests.java b/core/test/net/sf/openrocket/preset/TubeCouplerComponentTests.java
new file mode 100644 (file)
index 0000000..829f664
--- /dev/null
@@ -0,0 +1,117 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.rocketcomponent.TubeCoupler;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test application of ComponentPresets to TubeCoupler RocketComponents through
+ * the TubeCoupler.loadFromPreset mechanism.
+ * 
+ * Test TubeCoupler is well defined.
+ * 
+ * Test calling setters on TubeCoupler will clear the ComponentPreset.
+ * 
+ */
+public class TubeCouplerComponentTests extends BaseTestCase {
+       
+       ComponentPreset preset;
+       
+       @Before
+       public void createPreset() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               preset = ComponentPresetFactory.create(presetspec);
+       }
+       
+       @Test
+       public void testComponentType() {
+               TubeCoupler tc = new TubeCoupler();
+               
+               assertSame(ComponentPreset.Type.TUBE_COUPLER, tc.getPresetType());
+       }
+       
+       @Test
+       public void testLoadFromPresetIsSane() {
+               TubeCoupler tc = new TubeCoupler();
+               
+               tc.loadPreset(preset);
+               
+               assertEquals(2.0, tc.getLength(), 0.0);
+               assertEquals(1.0, tc.getOuterRadius(), 0.0);
+               assertEquals(0.5, tc.getInnerRadius(), 0.0);
+               
+               assertFalse(tc.isInnerRadiusAutomatic());
+               assertFalse(tc.isOuterRadiusAutomatic());
+               
+               assertSame(preset.get(ComponentPreset.MATERIAL), tc.getMaterial());
+               assertEquals(100.0, tc.getMass(), 0.05);
+       }
+       
+       @Test
+       public void changeLengthLeavesPreset() {
+               TubeCoupler tc = new TubeCoupler();
+               
+               tc.loadPreset(preset);
+               
+               tc.setLength(1.0);
+               
+               assertSame(preset, tc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeODClearsPreset() {
+               TubeCoupler tc = new TubeCoupler();
+               
+               tc.loadPreset(preset);
+               
+               tc.setOuterRadius(2.0);
+               
+               assertNull(tc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeIDClearsPreset() {
+               TubeCoupler tc = new TubeCoupler();
+               
+               tc.loadPreset(preset);
+               
+               tc.setInnerRadius(0.75);
+               
+               assertNull(tc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeThicknessClearsPreset() {
+               TubeCoupler tc = new TubeCoupler();
+               
+               tc.loadPreset(preset);
+               
+               tc.setThickness(0.1);
+               
+               assertNull(tc.getPresetComponent());
+       }
+       
+       @Test
+       public void changeMaterialClearsPreset() {
+               TubeCoupler tc = new TubeCoupler();
+               
+               tc.loadPreset(preset);
+               
+               tc.setMaterial(Material.newMaterial(Material.Type.BULK, "new", 1.0, true));
+               
+               assertNull(tc.getPresetComponent());
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/TubeCouplerPresetTests.java b/core/test/net/sf/openrocket/preset/TubeCouplerPresetTests.java
new file mode 100644 (file)
index 0000000..7ef16ed
--- /dev/null
@@ -0,0 +1,271 @@
+package net.sf.openrocket.preset;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.motor.Manufacturer;
+
+import org.junit.Test;
+
+/**
+ * Test construction of TUBE_COUPLER type ComponentPresets based on TypedPropertyMap through the
+ * ComponentPresetFactory.create() method.
+ * 
+ * Ensure required properties are populated
+ * 
+ * Ensure any computed values are correctly computed.
+ * 
+ */
+public class TubeCouplerPresetTests {
+       
+       @Test
+       public void testManufacturerRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.MANUFACTURER,
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Manufacturer specified",
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testPartNoRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                                       ComponentPreset.PARTNO,
+                                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No PartNo specified",
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testLengthRequired() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       new TypedKey<?>[] {
+                                       ComponentPreset.LENGTH
+                                       },
+                                       new String[] {
+                                                       "No Length specified",
+                                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyOuterDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyInnerDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.INNER_DIAMETER, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testOnlyThicknessDiameter() {
+               try {
+                       TypedPropertyMap presetspec = new TypedPropertyMap();
+                       presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+                       presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+                       presetspec.put(ComponentPreset.PARTNO, "partno");
+                       presetspec.put(ComponentPreset.LENGTH, 2.0);
+                       presetspec.put(ComponentPreset.THICKNESS, 2.0);
+                       ComponentPresetFactory.create(presetspec);
+               } catch (InvalidComponentPresetException ex) {
+                       PresetAssertHelper.assertInvalidPresetException(ex,
+                                       null,
+                                       new String[] {
+                                       "Preset dimensions underspecified"
+                                       }
+                                       );
+               }
+       }
+       
+       @Test
+       public void testComputeInnerDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(1.0, preset.get(ComponentPreset.INNER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeOuterDiameter() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 0.5);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(2.0, preset.get(ComponentPreset.OUTER_DIAMETER).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThickness() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeThicknessLooses() throws Exception {
+               // If all OUTER_DIAMETER, INNER_DIAMETER and THICKNESS are
+               // specified, THICKNESS is recomputed.
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.THICKNESS, 15.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals(0.5, preset.get(ComponentPreset.THICKNESS).doubleValue(), 0.0);
+       }
+       
+       @Test
+       public void testComputeDensityNoMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("TubeCustom", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+       @Test
+       public void testMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(2.0, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+               
+       }
+       
+       @Test
+       public void testComputeDensityWithMaterial() throws Exception {
+               TypedPropertyMap presetspec = new TypedPropertyMap();
+               presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.TUBE_COUPLER);
+               presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+               presetspec.put(ComponentPreset.PARTNO, "partno");
+               presetspec.put(ComponentPreset.LENGTH, 2.0);
+               presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+               presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+               presetspec.put(ComponentPreset.MASS, 100.0);
+               presetspec.put(ComponentPreset.MATERIAL, Material.newMaterial(Material.Type.BULK, "test", 2.0, true));
+               ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+               
+               // Compute the volume by hand here using a slightly different formula from
+               // the real implementation.  The magic numbers are based on the 
+               // constants put into the presetspec above.
+               double volume = /*outer area*/(Math.PI * 1.0) - /* inner area */(Math.PI * .25);
+               volume *= 2.0; /* times length */
+               
+               double density = 100.0 / volume;
+               
+               assertEquals("test", preset.get(ComponentPreset.MATERIAL).getName());
+               assertEquals(density, preset.get(ComponentPreset.MATERIAL).getDensity(), 0.0005);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/preset/xml/BaseComponentDTOTest.java b/core/test/net/sf/openrocket/preset/xml/BaseComponentDTOTest.java
new file mode 100644 (file)
index 0000000..bbc609d
--- /dev/null
@@ -0,0 +1,72 @@
+package net.sf.openrocket.preset.xml;
+
+import net.sf.openrocket.motor.Manufacturer;
+import net.sf.openrocket.preset.ComponentPreset;
+import net.sf.openrocket.preset.ComponentPresetFactory;
+import net.sf.openrocket.preset.TypedPropertyMap;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.imageio.ImageIO;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+/**
+ */
+public class BaseComponentDTOTest {
+
+
+    @Test
+    public void testImage() throws Exception {
+        TypedPropertyMap presetspec = new TypedPropertyMap();
+        presetspec.put(ComponentPreset.TYPE, ComponentPreset.Type.BODY_TUBE);
+        presetspec.put(ComponentPreset.MANUFACTURER, Manufacturer.getManufacturer("manufacturer"));
+        presetspec.put(ComponentPreset.PARTNO, "partno");
+        presetspec.put(ComponentPreset.LENGTH, 2.0);
+        presetspec.put(ComponentPreset.OUTER_DIAMETER, 2.0);
+        presetspec.put(ComponentPreset.INNER_DIAMETER, 1.0);
+        presetspec.put(ComponentPreset.MASS, 100.0);
+        ComponentPreset preset = ComponentPresetFactory.create(presetspec);
+
+        //Convert the presets to a BodyTubeDTO
+        BodyTubeDTO dto = new BodyTubeDTO(preset);
+
+        //Add an image to the DTO.
+        BufferedImage image = ImageIO.read(this.getClass().getResourceAsStream("/pix/splashscreen.png"));
+        dto.setImage(image);
+
+        JAXBContext binder = JAXBContext.newInstance(OpenRocketComponentDTO.class);
+        Marshaller marshaller = binder.createMarshaller();
+        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+        StringWriter sw = new StringWriter();
+
+        //Serialize the dto to XML
+        marshaller.marshal(dto, sw);
+        String xml = sw.toString();
+
+        //Read the XML back to create the dto again
+        Unmarshaller unmarshaller = binder.createUnmarshaller();
+        BodyTubeDTO redone = (BodyTubeDTO) unmarshaller.unmarshal(new StringReader(xml));
+
+        //Compare the image.
+        Assert.assertArrayEquals(((DataBufferByte) image.getData().getDataBuffer()).getData(),
+                ((DataBufferByte) redone.getImage().getData().getDataBuffer()).getData());
+
+        //Assert the rest of the attributes.
+        Assert.assertEquals(dto.getInsideDiameter(), redone.getInsideDiameter(), 0.00001);
+        Assert.assertEquals(dto.getLength(), redone.getLength(), 0.00001);
+        Assert.assertEquals(dto.getOutsideDiameter(), redone.getOutsideDiameter(), 0.00001);
+        Assert.assertEquals(dto.getDescription(), redone.getDescription());
+        Assert.assertEquals(dto.getManufacturer(), redone.getManufacturer());
+        Assert.assertEquals(dto.getMass(), redone.getMass(), 0.00001);
+        Assert.assertEquals(dto.getPartNo(), redone.getPartNo());
+
+        //Uncomment if you want to write the image to a file to view it.
+//        ImageIO.write(redone.getImage(), "png", new FileOutputStream("redone.png"));
+    }
+}
diff --git a/core/test/net/sf/openrocket/preset/xml/OpenRocketComponentSaverTest.java b/core/test/net/sf/openrocket/preset/xml/OpenRocketComponentSaverTest.java
new file mode 100644 (file)
index 0000000..4325fae
--- /dev/null
@@ -0,0 +1,112 @@
+package net.sf.openrocket.preset.xml;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+* OpenRocketComponentSaver Tester.
+*
+*/
+public class OpenRocketComponentSaverTest {
+
+    @Before
+    public void before() throws Exception {
+    }
+
+    @After
+    public void after() throws Exception {
+    }
+
+    /**
+     *
+     * Method: marshalToOpenRocketComponent(List<Material> theMaterialList, List<ComponentPreset> thePresetList)
+     *
+     */
+    @Test
+    public void testMarshalToOpenRocketComponent() throws Exception {
+        //TODO: Test goes here...
+    }
+
+    /**
+     *
+     * Method: unmarshalFromOpenRocketComponent(Reader is)
+     *
+     */
+    @Test
+    public void testUnmarshalFromOpenRocketComponent() throws Exception {
+        //TODO: Test goes here...
+    }
+
+    /**
+     *
+     * Method: save(OutputStream dest, List<Material> theMaterialList, List<ComponentPreset> thePresetList)
+     *
+     */
+    @Test
+    public void testSave() throws Exception {
+        //TODO: Test goes here...
+    }
+
+
+    /**
+     *
+     * Method: fromOpenRocketComponent(Reader is)
+     *
+     */
+    @Test
+    public void testFromOpenRocketComponent() throws Exception {
+        //TODO: Test goes here...
+/*
+try {
+   Method method = OpenRocketComponentSaver.getClass().getMethod("fromOpenRocketComponent", Reader.class);
+   method.setAccessible(true);
+   method.invoke(<Object>, <Parameters>);
+} catch(NoSuchMethodException e) {
+} catch(IllegalAccessException e) {
+} catch(InvocationTargetException e) {
+}
+*/
+    }
+
+    /**
+     *
+     * Method: toOpenRocketComponentDTO(List<Material> theMaterialList, List<ComponentPreset> thePresetList)
+     *
+     */
+    @Test
+    public void testToOpenRocketComponentDTO() throws Exception {
+        //TODO: Test goes here...
+/*
+try {
+   Method method = OpenRocketComponentSaver.getClass().getMethod("toOpenRocketComponentDTO", List<Material>.class, List<ComponentPreset>.class);
+   method.setAccessible(true);
+   method.invoke(<Object>, <Parameters>);
+} catch(NoSuchMethodException e) {
+} catch(IllegalAccessException e) {
+} catch(InvocationTargetException e) {
+}
+*/
+    }
+
+    /**
+     *
+     * Method: toComponentDTO(ComponentPreset thePreset)
+     *
+     */
+    @Test
+    public void testToComponentDTO() throws Exception {
+        //TODO: Test goes here...
+/*
+try {
+   Method method = OpenRocketComponentSaver.getClass().getMethod("toComponentDTO", ComponentPreset.class);
+   method.setAccessible(true);
+   method.invoke(<Object>, <Parameters>);
+} catch(NoSuchMethodException e) {
+} catch(IllegalAccessException e) {
+} catch(InvocationTargetException e) {
+}
+*/
+    }
+
+}
index fb231dc0497e07d2fdbb634d7363f620fe00a59c..aa3fc486da2467fa2d58b74b2dc863745254f974 100644 (file)
@@ -18,7 +18,7 @@ public class ComponentCompare {
                        "getStageNumber", "getComponentName",
                        // Rocket specific methods:
                        "getModID", "getMassModID", "getAerodynamicModID", "getTreeModID", "getFunctionalModID",
-                       "getMotorConfigurationIDs", "getDefaultConfiguration"
+                       "getMotorConfigurationIDs", "getDefaultConfiguration", "getMotorMounts"
        };
        
        
index 46c8f21d2f7f93ac1e892f7c5fc3a82bcf0bfb3e..647750cccdbe7d1e927c6b246efebbb985dd8bec 100644 (file)
@@ -1,16 +1,19 @@
 package net.sf.openrocket.rocketcomponent;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.awt.Color;
 import java.util.Iterator;
 
 import net.sf.openrocket.gui.util.ColorConversion;
 import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
 
 import org.junit.Test;
 
-public class ComponentCompareTest {
+public class ComponentCompareTest extends BaseTestCase {
 
        @Test
        public void testComponentEquality() {
index abec65ceecd216f1da0179315b22338bdc0b5050..321efbe8cfb08857f1b58f87c46fa1305c58e8af 100644 (file)
@@ -1,8 +1,6 @@
 package net.sf.openrocket.rocketcomponent;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 import java.awt.Color;
 
@@ -20,7 +18,7 @@ import org.junit.Test;
 
 public class FinSetTest extends BaseTestCase {
        
-
+       
        @Test
        public void testFreeformConvert() {
                testFreeformConvert(new TrapezoidFinSet());
@@ -55,14 +53,14 @@ public class FinSetTest extends BaseTestCase {
                fin.setTabShift(0.015);
                fin.setThickness(0.005);
                
-
+               
                converted = FreeformFinSet.convertFinSet((FinSet) fin.copy());
                
                ComponentCompare.assertSimilarity(fin, converted, true);
                
                assertEquals(converted.getComponentName(), converted.getName());
                
-
+               
                // Create test rocket
                Rocket rocket = new Rocket();
                Stage stage = new Stage();
@@ -79,7 +77,7 @@ public class FinSetTest extends BaseTestCase {
                assertTrue(l1.changed);
                assertEquals(ComponentChangeEvent.NONFUNCTIONAL_CHANGE, l1.changetype);
                
-
+               
                // Create copy
                RocketComponent rocketcopy = rocket.copy();
                
diff --git a/core/test/net/sf/openrocket/rocketcomponent/SymmetricComponentVolumeTest.java b/core/test/net/sf/openrocket/rocketcomponent/SymmetricComponentVolumeTest.java
new file mode 100644 (file)
index 0000000..9d554d7
--- /dev/null
@@ -0,0 +1,450 @@
+package net.sf.openrocket.rocketcomponent;
+
+import static org.junit.Assert.assertEquals;
+import net.sf.openrocket.material.Material;
+import net.sf.openrocket.util.Coordinate;
+import net.sf.openrocket.util.BaseTestCase.BaseTestCase;
+
+import org.junit.Test;
+
+public class SymmetricComponentVolumeTest extends BaseTestCase {
+       
+       @Test
+       public void simpleConeFilled() {
+               NoseCone nc = new NoseCone();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(1.0);
+               nc.setFilled(true);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setAftRadius(1.0);
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               double volume = Math.PI / 3.0;
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(0.75, cg.x, epsilonPercent * 0.75);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleConeWithShoulderFilled() {
+               NoseCone nc = new NoseCone();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(1.0);
+               nc.setFilled(true);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setAftRadius(1.0);
+               nc.setAftShoulderRadius(1.0);
+               nc.setAftShoulderLength(1.0);
+               nc.setAftShoulderThickness(1.0);
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               double volume = Math.PI / 3.0;
+               volume += Math.PI;
+               
+               double mass = density * volume;
+               
+               System.out.println(volume + "\t" + mass);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(1.312, cg.x, epsilonPercent * 1.071);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleConeHollow() {
+               NoseCone nc = new NoseCone();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(1.0);
+               nc.setAftRadius(1.0);
+               nc.setThickness(0.5);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               double volume = Math.PI / 3.0; // outer volume
+               
+               // manually projected Thickness of 0.5 on to radius to determine
+               // the innerConeDimen.  Since the outer cone is "square" (height = radius),
+               // we only need to compute this one dimension in order to compute the
+               // volume of the inner cone.
+               double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
+               double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
+               volume -= innerVolume;
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(0.7454, cg.x, epsilonPercent * 0.7454);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleConeWithShoulderHollow() {
+               NoseCone nc = new NoseCone();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(1.0);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setAftRadius(1.0);
+               nc.setThickness(0.5);
+               nc.setAftShoulderRadius(1.0);
+               nc.setAftShoulderLength(1.0);
+               nc.setAftShoulderThickness(0.5);
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               double volume = Math.PI / 3.0; // outer volume
+               
+               // manually projected Thickness of 0.5 on to radius to determine
+               // the innerConeDimen.  Since the outer cone is "square" (height = radius),
+               // we only need to compute this one dimension in order to compute the
+               // volume of the inner cone.
+               double innerConeDimen = 1.0 - Math.sqrt(2.0) / 2.0;
+               double innerVolume = Math.PI / 3.0 * innerConeDimen * innerConeDimen * innerConeDimen;
+               volume -= innerVolume;
+               
+               volume += Math.PI - Math.PI * 0.5 * 0.5;
+               
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(1.2719, cg.x, epsilonPercent * 1.2719);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleTransitionFilled() {
+               Transition nc = new Transition();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(4.0);
+               nc.setFilled(true);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setForeRadius(1.0);
+               nc.setAftRadius(2.0);
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(2.4285, cg.x, epsilonPercent * 2.4285);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleTransitionWithShouldersFilled() {
+               Transition nc = new Transition();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(4.0);
+               nc.setFilled(true);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setForeRadius(1.0);
+               nc.setAftRadius(2.0);
+               nc.setAftShoulderLength(1.0);
+               nc.setAftShoulderRadius(2.0);
+               nc.setAftShoulderThickness(2.0);
+               nc.setForeShoulderLength(1.0);
+               nc.setForeShoulderRadius(1.0);
+               nc.setForeShoulderThickness(1.0);
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               double volume = Math.PI / 3.0 * (2.0 * 2.0 + 2.0 * 1.0 + 1.0 * 1.0) * 4.0;
+               // plus aft shoulder:
+               volume += Math.PI * 1.0 * 2.0 * 2.0;
+               // plus fore shoulder:
+               volume += Math.PI * 1.0 * 1.0 * 1.0;
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(2.8023, cg.x, epsilonPercent * 2.8023);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleTransitionHollow1() {
+               Transition nc = new Transition();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(1.0);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setForeRadius(0.5);
+               nc.setAftRadius(1.0);
+               nc.setThickness(0.5);
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               // Volume of filled transition = 
+               double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
+               
+               // magic 2D cad drawing...
+               //
+               // Since the thickness >= fore radius, the
+               // hollowed out portion of the transition
+               // forms a cone.
+               // the dimensions of this cone were determined
+               // using a 2d cad tool.
+               
+               double innerConeRadius = 0.441;
+               double innerConeLength = 0.882;
+               double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
+               
+               double volume = filledVolume - innerVolume;
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(0.5884, cg.x, epsilonPercent * 0.5884);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleTransitionWithShouldersHollow1() {
+               Transition nc = new Transition();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(1.0);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setForeRadius(0.5);
+               nc.setAftRadius(1.0);
+               nc.setThickness(0.5);
+               nc.setAftShoulderLength(1.0);
+               nc.setAftShoulderRadius(1.0);
+               nc.setAftShoulderThickness(0.5);
+               nc.setForeShoulderLength(1.0);
+               nc.setForeShoulderRadius(0.5);
+               nc.setForeShoulderThickness(0.5); // note this means fore shoulder is filled.
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               // Volume of filled transition = 
+               double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
+               
+               // magic 2D cad drawing...
+               //
+               // Since the thickness >= fore radius, the
+               // hollowed out portion of the transition
+               // forms a cone.
+               // the dimensions of this cone were determined
+               // using a 2d cad tool.
+               
+               double innerConeRadius = 0.441;
+               double innerConeLength = 0.882;
+               double innerVolume = Math.PI / 3.0 * innerConeLength * innerConeRadius * innerConeRadius;
+               
+               double volume = filledVolume - innerVolume;
+               
+               // Now add aft shoulder
+               volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.5 * 0.5;
+               // Now add fore shoulder
+               volume += Math.PI * 1.0 * 0.5 * 0.5;
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(0.8581, cg.x, epsilonPercent * 0.8581);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleTransitionHollow2() {
+               Transition nc = new Transition();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(1.0);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setForeRadius(0.5);
+               nc.setAftRadius(1.0);
+               nc.setThickness(0.25);
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               // Volume of filled transition = 
+               double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
+               
+               // magic 2D cad drawing...
+               //
+               // Since the thickness < fore radius, the
+               // hollowed out portion of the transition
+               // forms a transition.
+               // the dimensions of this transition were determined
+               // using a 2d cad tool.
+               
+               double innerTransitionAftRadius = 0.7205;
+               double innerTransitionForeRadius = 0.2205;
+               double innerVolume = Math.PI / 3.0
+                               * (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
+               
+               double volume = filledVolume - innerVolume;
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(0.56827, cg.x, epsilonPercent * 0.56827);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+       @Test
+       public void simpleTransitionWithShouldersHollow2() {
+               Transition nc = new Transition();
+               
+               final double epsilonPercent = 0.001;
+               final double density = 2.0;
+               
+               nc.setLength(1.0);
+               nc.setType(Transition.Shape.CONICAL);
+               nc.setForeRadius(0.5);
+               nc.setAftRadius(1.0);
+               nc.setThickness(0.25);
+               nc.setAftShoulderLength(1.0);
+               nc.setAftShoulderRadius(1.0);
+               nc.setAftShoulderThickness(0.25);
+               nc.setForeShoulderLength(1.0);
+               nc.setForeShoulderRadius(0.5);
+               nc.setForeShoulderThickness(0.25);
+               
+               nc.setMaterial(Material.newMaterial(Material.Type.BULK, "test", density, true));
+               
+               Coordinate cg = nc.getCG();
+               
+               System.out.println(nc.getComponentVolume() + "\t" + nc.getMass());
+               System.out.println(cg);
+               
+               // Volume of filled transition = 
+               double filledVolume = Math.PI / 3.0 * (1.0 * 1.0 + 1.0 * 0.5 + 0.5 * 0.5) * 1.0;
+               
+               // magic 2D cad drawing...
+               //
+               // Since the thickness < fore radius, the
+               // hollowed out portion of the transition
+               // forms a transition.
+               // the dimensions of this transition were determined
+               // using a 2d cad tool.
+               
+               double innerTransitionAftRadius = 0.7205;
+               double innerTransitionForeRadius = 0.2205;
+               double innerVolume = Math.PI / 3.0
+                               * (innerTransitionAftRadius * innerTransitionAftRadius + innerTransitionAftRadius * innerTransitionForeRadius + innerTransitionForeRadius * innerTransitionForeRadius);
+               
+               double volume = filledVolume - innerVolume;
+               
+               // now add aft shoulder
+               volume += Math.PI * 1.0 * 1.0 * 1.0 - Math.PI * 1.0 * 0.75 * 0.75;
+               // now add fore shoulder
+               volume += Math.PI * 1.0 * 0.5 * 0.5 - Math.PI * 1.0 * 0.25 * 0.25;
+               
+               
+               double mass = density * volume;
+               
+               System.out.println(volume);
+               
+               assertEquals(volume, nc.getComponentVolume(), epsilonPercent * volume);
+               assertEquals(mass, nc.getMass(), epsilonPercent * mass);
+               
+               assertEquals(0.7829, cg.x, epsilonPercent * 0.7829);
+               assertEquals(mass, cg.weight, epsilonPercent * mass);
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/simulation/customexpression/TestExpressions.java b/core/test/net/sf/openrocket/simulation/customexpression/TestExpressions.java
new file mode 100644 (file)
index 0000000..d67bca0
--- /dev/null
@@ -0,0 +1,23 @@
+package net.sf.openrocket.simulation.customexpression;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import net.sf.openrocket.document.OpenRocketDocument;
+import net.sf.openrocket.rocketcomponent.Rocket;
+
+public class TestExpressions {
+
+       @Test
+       public void testExpressions() {
+               // TODO Auto-generated constructor stub
+               
+               OpenRocketDocument doc = new OpenRocketDocument(new Rocket());
+               
+               //CustomExpression exp = new CustomExpression(doc, "Kinetic energy", "Ek", "J", ".5*m*Vt^2");
+               
+               CustomExpression exp = new CustomExpression(doc, "Average mass", "Mavg", "kg", "mean(m[0:t])");
+               System.out.println( exp.getExpressionString() );
+               
+       }
+}
diff --git a/core/test/net/sf/openrocket/unit/FractionalUnitTest.java b/core/test/net/sf/openrocket/unit/FractionalUnitTest.java
new file mode 100644 (file)
index 0000000..093f059
--- /dev/null
@@ -0,0 +1,206 @@
+package net.sf.openrocket.unit;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class FractionalUnitTest {
+
+       private final static Unit testUnit = new FractionalUnit(1, "unit", "unit", 4, 0.5);
+       private final static Unit testUnitApprox = new FractionalUnit(1, "unit", "unit", 16, 0.5, 0.02);
+
+       private final static Unit inchUnit = new FractionalUnit(0.0254, "in/64", "in", 64, 1d/16d);
+       
+       @Test
+       public void testRound() {
+
+               assertEquals(-1d, testUnit.round(-1.125), 0.0); // rounds to -1 since mod is even
+               assertEquals(-1d, testUnit.round(-1.0), 0.0);
+               assertEquals(-1d, testUnit.round(-.875), 0.0); // rounds to -1 since mod is even
+
+               assertEquals(-0.75d, testUnit.round(-.874), 0.0);
+               assertEquals(-0.75d, testUnit.round(-.75), 0.0);
+               assertEquals(-0.75d, testUnit.round(-.626), 0.0);
+
+               assertEquals(-0.5d, testUnit.round(-.625), 0.0); // rounds to -.5 since mod is even
+               assertEquals(-0.5d, testUnit.round(-.5), 0.0);
+               assertEquals(-0.5d, testUnit.round(-.375), 0.0); // rounds to -.5 since mod is even
+
+               assertEquals(-0.25d, testUnit.round(-.374), 0.0);
+               assertEquals(-0.25d, testUnit.round(-.25), 0.0);
+               assertEquals(-0.25d, testUnit.round(-.126), 0.0);
+
+               assertEquals(0d, testUnit.round(-.125), 0.0);
+               assertEquals(0d, testUnit.round(0), 0.0);
+               assertEquals(0d, testUnit.round(.125), 0.0);
+
+               assertEquals(0.25d, testUnit.round(.126), 0.0);
+               assertEquals(0.25d, testUnit.round(.25), 0.0);
+               assertEquals(0.25d, testUnit.round(.374), 0.0);
+
+               assertEquals(0.5d, testUnit.round(.375), 0.0); // rounds to .5 since mod is even
+               assertEquals(0.5d, testUnit.round(.5), 0.0);
+               assertEquals(0.5d, testUnit.round(.625), 0.0); // rounds to .5 since mod is even
+
+               assertEquals(0.75d, testUnit.round(.626), 0.0);
+               assertEquals(0.75d, testUnit.round(.75), 0.0);
+               assertEquals(0.75d, testUnit.round(.874), 0.0);
+
+               assertEquals(1d, testUnit.round(.875), 0.0); // rounds to 1 since mod is even
+               assertEquals(1d, testUnit.round(1.0), 0.0);
+               assertEquals(1d, testUnit.round(1.125), 0.0); // rounds to 1 since mod is even
+
+       }
+
+       @Test
+       public void testIncrement() {
+
+               assertEquals( -1d, testUnit.getNextValue(-1.2), 0.0);
+               assertEquals( -1d, testUnit.getNextValue(-1.4), 0.0);
+
+               assertEquals( -0.5d, testUnit.getNextValue(-0.7), 0.0);
+               assertEquals( -0.5d, testUnit.getNextValue(-0.9), 0.0);
+               assertEquals( -0.5d, testUnit.getNextValue(-1.0), 0.0);
+
+               assertEquals( 0.0d, testUnit.getNextValue(-0.05), 0.0 );
+               assertEquals( 0.0d, testUnit.getNextValue(-0.062), 0.0 );
+               assertEquals( 0.0d, testUnit.getNextValue(-0.07), 0.0 );
+               assertEquals( 0.0d, testUnit.getNextValue(-0.11), 0.0 );
+
+               assertEquals( 0.5d, testUnit.getNextValue(0), 0.0 );
+               assertEquals( 0.5d, testUnit.getNextValue(0.01), 0.0 );
+               assertEquals( 0.5d, testUnit.getNextValue(0.062), 0.0 );
+               assertEquals( 0.5d, testUnit.getNextValue(0.0625), 0.0);
+
+               assertEquals( 1d, testUnit.getNextValue(0.51), 0.0);
+               assertEquals( 1d, testUnit.getNextValue(0.7), 0.0);
+       }
+
+       @Test
+       public void testDecrement() {
+
+               assertEquals( -1.5d, testUnit.getPreviousValue(-1.2), 0.0);
+               assertEquals( -1.5d, testUnit.getPreviousValue(-1.4), 0.0);
+               assertEquals( -1.5d, testUnit.getPreviousValue(-1.0), 0.0);
+
+               assertEquals( -1d, testUnit.getPreviousValue(-0.7), 0.0);
+               assertEquals( -1d, testUnit.getPreviousValue(-0.9), 0.0);
+
+               assertEquals( -0.5d, testUnit.getPreviousValue(-0.01), 0.0 );
+               assertEquals( -0.5d, testUnit.getPreviousValue(-0.05), 0.0 );
+               assertEquals( -0.5d, testUnit.getPreviousValue(-0.062), 0.0 );
+               assertEquals( -0.5d, testUnit.getPreviousValue(-0.07), 0.0 );
+               assertEquals( -0.5d, testUnit.getPreviousValue(0), 0.0 );
+
+               assertEquals( 0.0d, testUnit.getPreviousValue(0.49), 0.0 );
+               assertEquals( 0.0d, testUnit.getPreviousValue(0.262), 0.0 );
+               assertEquals( 0.0d, testUnit.getPreviousValue(0.51), 0.0);
+
+               assertEquals( 0.5d, testUnit.getPreviousValue(0.7), 0.0);
+
+               assertEquals( 1.0d, testUnit.getPreviousValue(1.2), 0.0);
+       }
+
+       @Test
+       public void testToStringDefaultPrecision() {
+
+               // default epsilon is 0.025
+               assertEquals("-1.2", testUnit.toString(-1.2)); 
+               assertEquals("-1 \u00B9\u2044\u2084", testUnit.toString(-1.225));
+               assertEquals("-1 \u00B9\u2044\u2084", testUnit.toString(-1.227));
+               assertEquals("-1 \u00B9\u2044\u2084", testUnit.toString(-1.25));
+               assertEquals("-1 \u00B9\u2044\u2084", testUnit.toString(-1.25));
+               assertEquals("-1 \u00B9\u2044\u2084", testUnit.toString(-1.275));
+               assertEquals("-1.3", testUnit.toString(-1.3));
+
+               assertEquals("-0.2", testUnit.toString(-.2));
+               assertEquals("-\u00B9\u2044\u2084", testUnit.toString(-.225));
+               assertEquals("-\u00B9\u2044\u2084", testUnit.toString(-.25));
+               assertEquals("-\u00B9\u2044\u2084", testUnit.toString(-.274));
+               //assertEquals("-1/4", testUnit.toString(-.275)); // this has roundoff error which pushes it over epsilon
+               assertEquals("-0.3", testUnit.toString(-.3));
+
+               assertEquals("-0.1", testUnit.toString(-.1));
+               assertEquals("0", testUnit.toString(-0.024));
+               assertEquals("0", testUnit.toString(0));
+               assertEquals("0", testUnit.toString(.024));
+               assertEquals("0.1", testUnit.toString(.1));
+
+               assertEquals("0.2", testUnit.toString(.2));
+               assertEquals("\u00B9\u2044\u2084", testUnit.toString(.225));
+               assertEquals("\u00B9\u2044\u2084", testUnit.toString(.25));
+               assertEquals("\u00B9\u2044\u2084", testUnit.toString(.274));
+               assertEquals("0.3", testUnit.toString(.3));
+
+               assertEquals("1.2", testUnit.toString(1.2));
+               assertEquals("1 \u00B9\u2044\u2084", testUnit.toString(1.225));
+               assertEquals("1 \u00B9\u2044\u2084", testUnit.toString(1.25));
+               assertEquals("1 \u00B9\u2044\u2084", testUnit.toString(1.275));
+               assertEquals("1.3", testUnit.toString(1.3));
+
+       }
+
+       @Test
+       public void testToStringWithPrecision() {
+
+               // epsilon is .02
+               assertEquals("-1 \u00B3\u2044\u2081\u2086", testUnitApprox.toString(-1.2));
+               assertEquals("-1.225", testUnitApprox.toString(-1.225));
+               assertEquals("-1 \u00B9\u2044\u2084", testUnitApprox.toString(-1.25));
+               assertEquals("-1.275", testUnitApprox.toString(-1.275));
+               assertEquals("-1 \u2075\u2044\u2081\u2086", testUnitApprox.toString(-1.3));
+
+               assertEquals("-\u00B3\u2044\u2081\u2086", testUnitApprox.toString(-.2));
+               assertEquals("-0.225", testUnitApprox.toString(-.225));
+               assertEquals("-\u00B9\u2044\u2084", testUnitApprox.toString(-.25));
+               assertEquals("-0.275", testUnitApprox.toString(-.275));
+               assertEquals("-\u2075\u2044\u2081\u2086", testUnitApprox.toString(-.3));
+
+               assertEquals("-0.1", testUnitApprox.toString(-.1));
+               assertEquals("-0.024", testUnitApprox.toString(-0.024));
+               assertEquals("0", testUnitApprox.toString(0));
+               assertEquals("0.024", testUnitApprox.toString(.024));
+               assertEquals("0.1", testUnitApprox.toString(.1));
+
+               assertEquals("\u00B3\u2044\u2081\u2086", testUnitApprox.toString(.2));
+               assertEquals("0.225", testUnitApprox.toString(.225));
+               assertEquals("\u00B9\u2044\u2084", testUnitApprox.toString(.25));
+               assertEquals("0.275", testUnitApprox.toString(.275));
+               assertEquals("\u2075\u2044\u2081\u2086", testUnitApprox.toString(.3));
+
+               assertEquals("1 \u00B3\u2044\u2081\u2086", testUnitApprox.toString(1.2));
+               assertEquals("1.225", testUnitApprox.toString(1.225));
+               assertEquals("1 \u00B9\u2044\u2084", testUnitApprox.toString(1.25));
+               assertEquals("1.275", testUnitApprox.toString(1.275));
+               assertEquals("1 \u2075\u2044\u2081\u2086", testUnitApprox.toString(1.3));
+
+       }
+       
+       @Test
+       public void testInchToString() {
+               
+               // Just some random test points.
+               assertEquals( "\u00B9\u2044\u2086\u2084", inchUnit.toString( 1d/64d*0.0254));
+               
+               assertEquals( "-\u2075\u2044\u2086\u2084", inchUnit.toString( -5d/64d*0.0254));
+               
+               assertEquals( "4 \u00B9\u2044\u2082", inchUnit.toString( 9d/2d*0.0254));
+               
+               assertEquals( "0.002", inchUnit.toString( 0.002*0.0254));
+               
+               // default body tube length:
+               double length = 8d * 0.025;
+               
+               assertEquals( "7 \u2077\u2044\u2088", inchUnit.toString( length) );
+               
+               // had problems with roundoff in decrement.
+               
+               double v = inchUnit.toUnit(length);
+               for ( int i = 0; i< 15; i++ ) {
+                       assertTrue( v > inchUnit.getPreviousValue(v) );
+                       v = inchUnit.getPreviousValue(v);
+               }
+               
+       }
+
+}
diff --git a/core/test/net/sf/openrocket/unit/UnitToStringTest.java b/core/test/net/sf/openrocket/unit/UnitToStringTest.java
new file mode 100644 (file)
index 0000000..6b96a5f
--- /dev/null
@@ -0,0 +1,170 @@
+package net.sf.openrocket.unit;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class UnitToStringTest {
+
+       @Test
+       public void testPositiveToString() {
+               // very small positive numbers ( < 0.0005) are returned as "0"
+               assertEquals("0",Unit.NOUNIT2.toString(0.00040));
+               assertEquals("0",Unit.NOUNIT2.toString(0.00050)); // check boundary of change in format
+
+               // positive number < 0.095 use 3 digit decimal format
+               assertEquals("0.001",Unit.NOUNIT2.toString(0.00051));  // check boundary of change in format
+               assertEquals("0.001",Unit.NOUNIT2.toString(0.00060));
+               
+               // rounding at third digit.
+               assertEquals("0.001",Unit.NOUNIT2.toString(0.0014));
+               assertEquals("0.002",Unit.NOUNIT2.toString(0.0015));  // round to even
+               assertEquals("0.002",Unit.NOUNIT2.toString(0.0016));
+               assertEquals("0.002",Unit.NOUNIT2.toString(0.0024));
+               assertEquals("0.002",Unit.NOUNIT2.toString(0.0025)); // round to even
+               assertEquals("0.003",Unit.NOUNIT2.toString(0.0026));
+               assertEquals("0.009",Unit.NOUNIT2.toString(0.0094));
+
+               assertEquals("0.01",Unit.NOUNIT2.toString(0.0095));  // no trailing zeros after rounding
+
+               assertEquals("0.011",Unit.NOUNIT2.toString(0.0114));
+               assertEquals("0.012",Unit.NOUNIT2.toString(0.0115)); // round to even
+               assertEquals("0.012",Unit.NOUNIT2.toString(0.0119));
+               assertEquals("0.012",Unit.NOUNIT2.toString(0.0124));
+               assertEquals("0.012",Unit.NOUNIT2.toString(0.0125)); // round to even
+               assertEquals("0.013",Unit.NOUNIT2.toString(0.0129));
+
+               assertEquals("0.095",Unit.NOUNIT2.toString(0.0949)); // boundary check
+               
+               // positive numbers < 100 
+               assertEquals("0.1",Unit.NOUNIT2.toString(0.095)); // boundary check
+               
+               assertEquals("0.11",Unit.NOUNIT2.toString(0.111));
+               assertEquals("0.12",Unit.NOUNIT2.toString(0.115)); // round to even
+               assertEquals("0.12",Unit.NOUNIT2.toString(0.117));
+               assertEquals("0.12",Unit.NOUNIT2.toString(0.121));
+               assertEquals("0.12",Unit.NOUNIT2.toString(0.125)); // round to even
+               assertEquals("0.13",Unit.NOUNIT2.toString(0.127));
+
+               assertEquals("1.11",Unit.NOUNIT2.toString(1.113));
+               assertEquals("1.12",Unit.NOUNIT2.toString(1.115)); // round to even
+               assertEquals("1.12",Unit.NOUNIT2.toString(1.117));
+               assertEquals("1.12",Unit.NOUNIT2.toString(1.123));
+               assertEquals("1.12",Unit.NOUNIT2.toString(1.125)); // round to even
+               assertEquals("1.13",Unit.NOUNIT2.toString(1.127));
+
+               assertEquals("12.3",Unit.NOUNIT2.toString(12.320));
+               assertEquals("12.4",Unit.NOUNIT2.toString(12.350)); // round to even
+               assertEquals("12.4",Unit.NOUNIT2.toString(12.355));
+               assertEquals("12.4",Unit.NOUNIT2.toString(12.420));
+               assertEquals("12.4",Unit.NOUNIT2.toString(12.450)); // round to even
+               assertEquals("12.5",Unit.NOUNIT2.toString(12.455));
+
+               // positive numbers <= 1E6
+               assertEquals("123",Unit.NOUNIT2.toString(123.20));
+               assertEquals("124",Unit.NOUNIT2.toString(123.50)); // round to even
+               assertEquals("124",Unit.NOUNIT2.toString(123.55));
+               assertEquals("124",Unit.NOUNIT2.toString(124.20));
+               assertEquals("124",Unit.NOUNIT2.toString(124.50)); // round to even
+               assertEquals("125",Unit.NOUNIT2.toString(124.55));
+               
+               assertEquals("1234",Unit.NOUNIT2.toString(1234.2));
+               assertEquals("1234",Unit.NOUNIT2.toString(1234.5)); // round to even
+               assertEquals("1235",Unit.NOUNIT2.toString(1234.6));
+               assertEquals("1235",Unit.NOUNIT2.toString(1235.2));
+               assertEquals("1236",Unit.NOUNIT2.toString(1235.5)); // round to even
+               assertEquals("1236",Unit.NOUNIT2.toString(1235.6));
+
+               assertEquals("123457",Unit.NOUNIT2.toString(123456.789));
+
+               assertEquals("1000000",Unit.NOUNIT2.toString(1000000)); // boundary check
+               
+               // positive numbers > 1E6
+               assertEquals("1.23E6",Unit.NOUNIT2.toString(1234567.89));
+               assertEquals("1.23E7",Unit.NOUNIT2.toString(12345678.9));
+               
+               
+       }
+       
+       @Test
+       public void testNegativeToString() {
+               // very small negative numbers ( < 0.0005) are returned as "0"
+               assertEquals("0",Unit.NOUNIT2.toString(-0.00040));
+               assertEquals("0",Unit.NOUNIT2.toString(-0.00050)); // check boundary of change in format
+
+               // negative number < 0.095 use 3 digit decimal format
+               assertEquals("-0.001",Unit.NOUNIT2.toString(-0.00051));  // check boundary of change in format
+               assertEquals("-0.001",Unit.NOUNIT2.toString(-0.00060));
+               
+               // rounding at third digit.
+               assertEquals("-0.001",Unit.NOUNIT2.toString(-0.0014));
+               assertEquals("-0.002",Unit.NOUNIT2.toString(-0.0015));  // round to even
+               assertEquals("-0.002",Unit.NOUNIT2.toString(-0.0016));
+               assertEquals("-0.002",Unit.NOUNIT2.toString(-0.0024));
+               assertEquals("-0.002",Unit.NOUNIT2.toString(-0.0025)); // round to even
+               assertEquals("-0.003",Unit.NOUNIT2.toString(-0.0026));
+               assertEquals("-0.009",Unit.NOUNIT2.toString(-0.0094));
+
+               assertEquals("-0.01",Unit.NOUNIT2.toString(-0.0095));  // no trailing zeros after rounding
+
+               assertEquals("-0.011",Unit.NOUNIT2.toString(-0.0114));
+               assertEquals("-0.012",Unit.NOUNIT2.toString(-0.0115)); // round to even
+               assertEquals("-0.012",Unit.NOUNIT2.toString(-0.0119));
+               assertEquals("-0.012",Unit.NOUNIT2.toString(-0.0124));
+               assertEquals("-0.012",Unit.NOUNIT2.toString(-0.0125)); // round to even
+               assertEquals("-0.013",Unit.NOUNIT2.toString(-0.0129));
+
+               assertEquals("-0.095",Unit.NOUNIT2.toString(-0.0949)); // boundary check
+               
+               // negative numbers < 100 
+               assertEquals("-0.1",Unit.NOUNIT2.toString(-0.095)); // boundary check
+               
+               assertEquals("-0.11",Unit.NOUNIT2.toString(-0.111));
+               assertEquals("-0.12",Unit.NOUNIT2.toString(-0.115)); // round to even
+               assertEquals("-0.12",Unit.NOUNIT2.toString(-0.117));
+               assertEquals("-0.12",Unit.NOUNIT2.toString(-0.121));
+               assertEquals("-0.12",Unit.NOUNIT2.toString(-0.125)); // round to even
+               assertEquals("-0.13",Unit.NOUNIT2.toString(-0.127));
+
+               assertEquals("-1.11",Unit.NOUNIT2.toString(-1.113));
+               assertEquals("-1.12",Unit.NOUNIT2.toString(-1.115)); // round to even
+               assertEquals("-1.12",Unit.NOUNIT2.toString(-1.117));
+               assertEquals("-1.12",Unit.NOUNIT2.toString(-1.123));
+               assertEquals("-1.12",Unit.NOUNIT2.toString(-1.125)); // round to even
+               assertEquals("-1.13",Unit.NOUNIT2.toString(-1.127));
+
+               assertEquals("-12.3",Unit.NOUNIT2.toString(-12.320));
+               assertEquals("-12.4",Unit.NOUNIT2.toString(-12.350)); // round to even
+               assertEquals("-12.4",Unit.NOUNIT2.toString(-12.355));
+               assertEquals("-12.4",Unit.NOUNIT2.toString(-12.420));
+               assertEquals("-12.4",Unit.NOUNIT2.toString(-12.450)); // round to even
+               assertEquals("-12.5",Unit.NOUNIT2.toString(-12.455));
+
+               // negative numbers <= 1E6
+               assertEquals("-123",Unit.NOUNIT2.toString(-123.20));
+               assertEquals("-124",Unit.NOUNIT2.toString(-123.50)); // round to even
+               assertEquals("-124",Unit.NOUNIT2.toString(-123.55));
+               assertEquals("-124",Unit.NOUNIT2.toString(-124.20));
+               assertEquals("-124",Unit.NOUNIT2.toString(-124.50)); // round to even
+               assertEquals("-125",Unit.NOUNIT2.toString(-124.55));
+               
+               assertEquals("-1234",Unit.NOUNIT2.toString(-1234.2));
+               assertEquals("-1234",Unit.NOUNIT2.toString(-1234.5)); // round to even
+               assertEquals("-1235",Unit.NOUNIT2.toString(-1234.6));
+               assertEquals("-1235",Unit.NOUNIT2.toString(-1235.2));
+               assertEquals("-1236",Unit.NOUNIT2.toString(-1235.5)); // round to even
+               assertEquals("-1236",Unit.NOUNIT2.toString(-1235.6));
+
+               assertEquals("-123457",Unit.NOUNIT2.toString(-123456.789));
+
+               assertEquals("-1000000",Unit.NOUNIT2.toString(-1000000)); // boundary check
+               
+               // negative numbers > 1E6
+               assertEquals("-1.23E6",Unit.NOUNIT2.toString(-1234567.89));
+               assertEquals("-1.23E7",Unit.NOUNIT2.toString(-12345678.9));
+               
+               
+       }
+       
+       
+}
diff --git a/core/test/net/sf/openrocket/util/ArrayUtilsTest.java b/core/test/net/sf/openrocket/util/ArrayUtilsTest.java
new file mode 100644 (file)
index 0000000..ee8b5e9
--- /dev/null
@@ -0,0 +1,126 @@
+package net.sf.openrocket.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+public class ArrayUtilsTest {
+
+       @Test(expected=NullPointerException.class)
+       public void testCopyOfRange_NullArg() {
+               ArrayUtils.copyOfRange( (Byte[]) null, 0 , 14);
+       }
+
+       @Test(expected=ArrayIndexOutOfBoundsException.class)
+       public void testCopyOfRange_StartTooBig() {
+               Integer[] original = new Integer[5];
+               ArrayUtils.copyOfRange( original, 8 , 14);
+       }
+
+       @Test(expected=ArrayIndexOutOfBoundsException.class)
+       public void testCopyOfRange_StartTooSmall() {
+               Integer[] original = new Integer[5];
+               ArrayUtils.copyOfRange( original, -1 , 14);
+       }
+
+       @Test(expected=IllegalArgumentException.class)
+       public void testCopyOfRange_IllegalRange() {
+               Integer[] original = new Integer[5];
+               ArrayUtils.copyOfRange( original, 5, 0 );
+       }
+
+       @Test
+       public void testCopyOfRange() {
+               Integer[] original = new Integer[5];
+               for ( int i =0; i < 5; i++ ) {
+                       original[i] = i;
+               }
+               Integer[] copy = ArrayUtils.copyOfRange( original, 0, 0 );
+               assertEquals( 0, copy.length );
+
+               copy = ArrayUtils.copyOfRange( original, 2, 2 );
+               assertEquals( 0, copy.length );
+
+               copy = ArrayUtils.copyOfRange( original, 0, 2 );
+               assertEquals( 2, copy.length );
+               for( int i =0; i< 2; i++ ) {
+                       assertEquals( original[i], copy[i] );
+               }
+
+               copy = ArrayUtils.copyOfRange( original, 2, 5 );
+               assertEquals( 3, copy.length );
+               for( int i =0; i< 3; i++ ) {
+                       assertEquals( original[i+2], copy[i] );
+               }
+
+               copy = ArrayUtils.copyOfRange( original, 2, 15 );
+               assertEquals( 13, copy.length );
+               for( int i =0; i< 3; i++ ) {
+                       assertEquals( original[i+2], copy[i] );
+               }
+               for ( int i=3; i< 13; i++ ) {
+                       assertNull(copy[i]);
+               }
+
+       }
+
+       @Test
+       public void testCopyOfRange_ZeroSize() {
+               Integer[] original = new Integer[0];
+
+               Integer[] copy = ArrayUtils.copyOfRange( original, 0, 0 );
+               assertEquals( 0, copy.length );
+
+               copy = ArrayUtils.copyOfRange( original, 0, 2 );
+               assertEquals( 2, copy.length );
+               for( int i =0; i< 2; i++ ) {
+                       assertEquals( null, copy[i] );
+               }
+
+       }
+
+       @Test
+       public void testRante0() {
+               double[] ary = ArrayUtils.range(0., 0., 1.0);
+               assertEquals(1, ary.length);
+               assertEquals( 0.0, ary[0], 0.0 );
+       }
+
+       @Test
+       public void testRange1() {
+               double[] ary = ArrayUtils.range(0.0, 0.5, 1.0);
+               assertEquals(1, ary.length);
+               assertEquals( 0.0, ary[0], 0.0 );
+       }
+
+       @Test
+       public void testRange2() {
+               double[] ary = ArrayUtils.range(0.0, 1.0, 0.5);
+               assertEquals(3, ary.length);
+               assertEquals( 0.0, ary[0], 0.0 );
+               assertEquals( 0.5, ary[1], 0.0 );
+               assertEquals( 1.0, ary[2], 0.0 );
+       }
+       
+       @Test
+       public void testRange3() {
+               double [] ary = ArrayUtils.range(0.0, 1.0, 0.4 );
+               assertEquals(3, ary.length);
+               assertEquals( 0.0, ary[0], 0.0 );
+               assertEquals( 0.4, ary[1], 0.0 );
+               assertEquals( 0.8, ary[2], 0.0 );
+       }
+
+       @Test
+       public void testRange4() {
+               double[] ary = ArrayUtils.range(0.0,10.0, 0.5);
+               assertEquals( 21, ary.length );
+               int i =0;
+               for( double d = 0.0; d < 10.2; d+=0.5){
+                       assertEquals(d,ary[i++],0.0);
+               }
+               assertEquals( i, ary.length );
+       }
+       
+}
diff --git a/core/test/net/sf/openrocket/util/Base64Test.java b/core/test/net/sf/openrocket/util/Base64Test.java
new file mode 100644 (file)
index 0000000..edf1300
--- /dev/null
@@ -0,0 +1,42 @@
+package net.sf.openrocket.util;
+
+import java.util.Arrays;
+import java.util.Random;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class Base64Test {
+
+       @Test
+       public void oldMainTest() throws Exception {
+
+               // TODO - this test case should probably be less random and more targeted to
+               // special cases such as:
+               // null input
+               // empty input
+               // decoding bad string
+               
+               Random rnd = new Random();
+
+               for (int round=0; round < 1000; round++) {
+                       int n = rnd.nextInt(1000);
+                       n = 100000;
+
+                       byte[] array = new byte[n];
+                       rnd.nextBytes(array);
+
+                       String encoded = Base64.encode(array);
+
+                       byte[] decoded = null;
+                       decoded = Base64.decode(encoded);
+
+                       if (!Arrays.equals(array, decoded)) {
+                               fail("Data differs!  n="+n);
+                       }
+                       System.out.println("n="+n+" ok!");
+
+               }
+       }
+}
\ No newline at end of file
diff --git a/core/test/net/sf/openrocket/util/ExpressionParserTest.java b/core/test/net/sf/openrocket/util/ExpressionParserTest.java
new file mode 100644 (file)
index 0000000..efbabe9
--- /dev/null
@@ -0,0 +1,94 @@
+package net.sf.openrocket.util;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+public class ExpressionParserTest {
+       
+       private static final double EPS = 1e-10;
+       
+       private ExpressionParser parser = new ExpressionParser();
+       
+       @Test
+       public void testPlainNumber() throws InvalidExpressionException {
+               assertEquals(1.0, parser.parse("1"), EPS);
+               assertEquals(1.0, parser.parse("\t 1 "), EPS);
+               assertEquals(0.9, parser.parse(".9"), EPS);
+               assertEquals(1.0, parser.parse("1."), EPS);
+               assertEquals(1.2, parser.parse("1.2"), EPS);
+               assertEquals(1.2, parser.parse("01.200"), EPS);
+       }
+       
+       @Test
+       public void testNegativeNumber() throws InvalidExpressionException {
+               assertEquals(-1.0, parser.parse("-1"), EPS);
+               assertEquals(-15.0, parser.parse("-15"), EPS);
+               assertEquals(-0.9, parser.parse("-.9"), EPS);
+               assertEquals(-1.0, parser.parse("-1."), EPS);
+               assertEquals(-1.2, parser.parse("-1.2"), EPS);
+               assertEquals(-1.2, parser.parse("-01.200"), EPS);
+       }
+       
+       
+       @Test
+       public void testDecimalComma() throws InvalidExpressionException {
+               assertEquals(1.0, parser.parse("1,"), EPS);
+               assertEquals(1.2, parser.parse("1,2"), EPS);
+               assertEquals(1.2, parser.parse("01,200"), EPS);
+               assertEquals(0.9, parser.parse(",9"), EPS);
+       }
+       
+       
+       @Test
+       public void testSimpleExpression() throws InvalidExpressionException {
+               assertEquals(3.0, parser.parse("1+2"), EPS);
+               assertEquals(6.0, parser.parse("1+2.5*2"), EPS);
+               assertEquals(7.0, parser.parse("(1+2.5) * 2"), EPS);
+               assertEquals(1.0 + 2.0 / 3.0, parser.parse("1+2/3"), EPS);
+       }
+       
+       @Test
+       public void testFraction() throws InvalidExpressionException {
+               assertEquals(1.5, parser.parse("1 1/2"), EPS);
+               assertEquals(11 + 11.0 / 22.0, parser.parse("11 11/22"), EPS);
+               assertEquals(-11 - 11.0 / 22.0, parser.parse("-11 11/22"), EPS);
+               assertEquals(1.5, parser.parse("  1    1 / 2"), EPS);
+               assertEquals(11 + 11.0 / 22.0, parser.parse("  11    11 / 22"), EPS);
+               assertEquals(2.0 + 3.0 / 7.0, parser.parse("1 + 1 3/7"), EPS);
+               assertEquals(2.0 + 3.0 / 7.0, parser.parse("1 + 1 3/7"), EPS);
+               assertEquals(3.0, parser.parse("1 1/2* 2"), EPS);
+               assertEquals(3.0, parser.parse("1 1/2* 2"), EPS);
+       }
+       
+       @Test
+       public void testCharConversion() throws InvalidExpressionException {
+               assertEquals(1 + 1.0 / 9.0, parser.parse("1 \u2081 \u2044 \u2089"), EPS);
+       }
+       
+       @Test
+       public void testInvalidExpression() {
+               expectInvalid("1+");
+               expectInvalid("1+2/");
+               expectInvalid("1 2");
+               expectInvalid("12 2.5");
+               expectInvalid("1 2.5/4");
+               expectInvalid("11 22.55/44");
+               expectInvalid("1 2/4.1");
+               expectInvalid("11 22/44.11");
+               expectInvalid("1.2 3/4");
+               expectInvalid("12.23 34/45");
+               
+               expectInvalid("1. 2");
+               expectInvalid("1 .2");
+       }
+       
+       private void expectInvalid(String exp) {
+               try {
+                       double value = parser.parse(exp);
+                       fail("Expression '" + exp + "' evaluated to " + value + ", expected failure");
+               } catch (InvalidExpressionException e) {
+                       // expected
+               }
+       }
+}
diff --git a/core/test/net/sf/openrocket/util/LinearInterpolatorTest.java b/core/test/net/sf/openrocket/util/LinearInterpolatorTest.java
new file mode 100644 (file)
index 0000000..600f82b
--- /dev/null
@@ -0,0 +1,32 @@
+package net.sf.openrocket.util;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+public class LinearInterpolatorTest {
+
+       @Test
+       public void oldMainTest() {
+               LinearInterpolator interpolator = new LinearInterpolator(
+                               new double[] {1, 1.5, 2, 4, 5},
+                               new double[] {0, 1,   0, 2, 2}
+               );
+               
+               double[] answer = new double[] {
+                               /* x=0 */ 0.00, 0.00, 0.00,     0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00,
+                               /* x=1 */ 0.00, 0.20, 0.40, 0.60, 0.80, 1.00, 0.80, 0.60, 0.40, 0.20,
+                               /* x=2 */ 0.00, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90,
+                               /* x=3 */ 1.00, 1.10, 1.20, 1.30, 1.40, 1.50, 1.60, 1.70, 1.80, 1.90,
+                               /* x=4 */ 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00,
+                               /* x=5 */ 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00, 2.00,
+                               /* x=6 */ 2.00
+               };
+               
+               double x = 0;
+               for (int i=0; i < answer.length; i++) {
+                       assertEquals( "Answer wrong for x = " + x , answer[i], interpolator.getValue(x), 0.01 );
+                       x+= 0.1;
+               }
+
+       }
+}
index f11ba89c3797d98ffe590853929b4e2412bfef80..6b9c1e1ad7841dd883da808e1ddfb6d2b0dcd773 100644 (file)
@@ -13,6 +13,23 @@ public class MathUtilTest {
        
        public static final double EPS = 0.00000000001;
        
+       /*
+       @Test 
+       public void rangeTest() {
+               double[] a;
+               
+               a = MathUtil.range(0, 10, 2);
+               assertEquals(0, a[0], 0);
+               assertEquals(10, a[5], 0);
+               assertEquals(6, a.length, 0);
+               
+               a = MathUtil.range(1, 2, 2);
+               assertEquals(1, a[0], 0);
+               assertEquals(1, a.length, 0);
+               
+       }
+       */
+       
        @Test
        public void miscMathTest() {
                
diff --git a/core/test/net/sf/openrocket/util/PolyInterpolatorTest.java b/core/test/net/sf/openrocket/util/PolyInterpolatorTest.java
new file mode 100644 (file)
index 0000000..cb9201f
--- /dev/null
@@ -0,0 +1,212 @@
+package net.sf.openrocket.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class PolyInterpolatorTest {
+
+       @Test
+       public void oldMainTest() {
+               {
+                       PolyInterpolator p0 = new PolyInterpolator(
+                                       new double[] {0.6, 1.1},
+                                       new double[] {0.6, 1.1}
+                                       );
+                       double[] r0 = p0.interpolator(1.5, 1.6, 2, -3);
+                       double[] answer0 = new double[] {
+                                       /* x=0.60*/  1.4999999999999987, 
+                                       /* x=0.61*/  1.5199143999999984, 
+                                       /* x=0.62*/  1.5396351999999984, 
+                                       /* x=0.63*/  1.5591287999999988, 
+                                       /* x=0.64*/  1.578361599999998, 
+                                       /* x=0.65*/  1.597299999999998, 
+                                       /* x=0.66*/  1.6159103999999977, 
+                                       /* x=0.67*/  1.6341591999999976, 
+                                       /* x=0.68*/  1.6520127999999976, 
+                                       /* x=0.69*/  1.669437599999997, 
+                                       /* x=0.70*/  1.6863999999999977, 
+                                       /* x=0.71*/  1.702866399999997, 
+                                       /* x=0.72*/  1.7188031999999964, 
+                                       /* x=0.73*/  1.7341767999999966, 
+                                       /* x=0.74*/  1.7489535999999957, 
+                                       /* x=0.75*/  1.7630999999999966, 
+                                       /* x=0.76*/  1.7765823999999952, 
+                                       /* x=0.77*/  1.7893671999999965, 
+                                       /* x=0.78*/  1.8014207999999958, 
+                                       /* x=0.79*/  1.8127095999999945, 
+                                       /* x=0.80*/  1.8231999999999942, 
+                                       /* x=0.81*/  1.8328583999999952, 
+                                       /* x=0.82*/  1.841651199999994, 
+                                       /* x=0.83*/  1.849544799999994, 
+                                       /* x=0.84*/  1.856505599999993, 
+                                       /* x=0.85*/  1.8624999999999927, 
+                                       /* x=0.86*/  1.8674943999999924, 
+                                       /* x=0.87*/  1.8714551999999918, 
+                                       /* x=0.88*/  1.8743487999999924, 
+                                       /* x=0.89*/  1.876141599999992, 
+                                       /* x=0.90*/  1.8767999999999914, 
+                                       /* x=0.91*/  1.8762903999999914, 
+                                       /* x=0.92*/  1.8745791999999906, 
+                                       /* x=0.93*/  1.8716327999999898, 
+                                       /* x=0.94*/  1.8674175999999907, 
+                                       /* x=0.95*/  1.8618999999999888, 
+                                       /* x=0.96*/  1.8550463999999902, 
+                                       /* x=0.97*/  1.8468231999999887, 
+                                       /* x=0.98*/  1.8371967999999885, 
+                                       /* x=0.99*/  1.826133599999988, 
+                                       /* x=1.00*/  1.8135999999999868, 
+                                       /* x=1.01*/  1.7995623999999868, 
+                                       /* x=1.02*/  1.783987199999987, 
+                                       /* x=1.03*/  1.7668407999999873, 
+                                       /* x=1.04*/  1.748089599999986, 
+                                       /* x=1.05*/  1.7276999999999854, 
+                                       /* x=1.06*/  1.7056383999999847, 
+                                       /* x=1.07*/  1.6818711999999838, 
+                                       /* x=1.08*/  1.6563647999999844, 
+                                       /* x=1.09*/  1.629085599999983, 
+                                       /* x=1.10*/  1.5999999999999837
+                       };
+                       double x=0.6;
+                       for (int i=0; i<answer0.length; i++) {
+                               assertEquals("r0 different at x=" + x, PolyInterpolator.eval(x, r0), answer0[i],0.00001);
+                               x+=0.01;
+                       }
+               }
+
+               {
+                       PolyInterpolator p1 = new PolyInterpolator(
+                                       new double[] {0.6, 1.1},
+                                       new double[] {0.6, 1.1},
+                                       new double[] {0.6}
+                                       );
+                       double[] r1 = p1.interpolator(1.5, 1.6, 2, -3, 0);
+                       double[] answer1 = new double[] {
+                                       /* x=0.60*/  1.4999999999999907, 
+                                       /* x=0.61*/  1.5199912319999909, 
+                                       /* x=0.62*/  1.5399301119999906, 
+                                       /* x=0.63*/  1.5597649919999914, 
+                                       /* x=0.64*/  1.5794449919999898, 
+                                       /* x=0.65*/  1.5989199999999888, 
+                                       /* x=0.66*/  1.6181406719999905, 
+                                       /* x=0.67*/  1.6370584319999903, 
+                                       /* x=0.68*/  1.655625471999989, 
+                                       /* x=0.69*/  1.6737947519999874, 
+                                       /* x=0.70*/  1.691519999999989, 
+                                       /* x=0.71*/  1.7087557119999883, 
+                                       /* x=0.72*/  1.7254571519999873, 
+                                       /* x=0.73*/  1.741580351999988, 
+                                       /* x=0.74*/  1.7570821119999884, 
+                                       /* x=0.75*/  1.7719199999999875, 
+                                       /* x=0.76*/  1.7860523519999871, 
+                                       /* x=0.77*/  1.7994382719999862, 
+                                       /* x=0.78*/  1.8120376319999876, 
+                                       /* x=0.79*/  1.8238110719999838, 
+                                       /* x=0.80*/  1.8347199999999855, 
+                                       /* x=0.81*/  1.8447265919999851, 
+                                       /* x=0.82*/  1.8537937919999865, 
+                                       /* x=0.83*/  1.861885311999986, 
+                                       /* x=0.84*/  1.8689656319999832, 
+                                       /* x=0.85*/  1.8749999999999836, 
+                                       /* x=0.86*/  1.8799544319999804, 
+                                       /* x=0.87*/  1.8837957119999817, 
+                                       /* x=0.88*/  1.8864913919999804, 
+                                       /* x=0.89*/  1.8880097919999814, 
+                                       /* x=0.90*/  1.8883199999999807, 
+                                       /* x=0.91*/  1.8873918719999794, 
+                                       /* x=0.92*/  1.88519603199998, 
+                                       /* x=0.93*/  1.8817038719999788, 
+                                       /* x=0.94*/  1.8768875519999786, 
+                                       /* x=0.95*/  1.8707199999999764, 
+                                       /* x=0.96*/  1.8631749119999794, 
+                                       /* x=0.97*/  1.8542267519999784, 
+                                       /* x=0.98*/  1.8438507519999745, 
+                                       /* x=0.99*/  1.832022911999974, 
+                                       /* x=1.00*/  1.8187199999999768, 
+                                       /* x=1.01*/  1.8039195519999738, 
+                                       /* x=1.02*/  1.7875998719999755, 
+                                       /* x=1.03*/  1.7697400319999765, 
+                                       /* x=1.04*/  1.7503198719999729, 
+                                       /* x=1.05*/  1.7293199999999675, 
+                                       /* x=1.06*/  1.7067217919999687, 
+                                       /* x=1.07*/  1.6825073919999713, 
+                                       /* x=1.08*/  1.656659711999966, 
+                                       /* x=1.09*/  1.629162431999962, 
+                                       /* x=1.10*/  1.5999999999999686
+                       };
+                       double x=0.6;
+                       for (int i=0; i<answer1.length; i++) {
+                               assertEquals("r1 different at x=" + x, PolyInterpolator.eval(x, r1), answer1[i],0.00001);
+                               x+=0.01;
+                       }
+               }
+               {
+                       PolyInterpolator p2 = new PolyInterpolator(
+                                       new double[] {0.6, 1.1},
+                                       new double[] {0.6, 1.1},
+                                       new double[] {0.6, 1.1}
+                                       );
+                       double[] r2 = p2.interpolator(1.5, 1.6, 2, -3, 0, 0);
+                       double[] answer2 = new double[] {
+                                       /* x=0.60*/  1.5000000000000844, 
+                                       /* x=0.61*/  1.520007366720093, 
+                                       /* x=0.62*/  1.5400539750400783, 
+                                       /* x=0.63*/  1.5601657929600794, 
+                                       /* x=0.64*/  1.58035504128011, 
+                                       /* x=0.65*/  1.6006210000000962, 
+                                       /* x=0.66*/  1.620950814720107, 
+                                       /* x=0.67*/  1.641320303040109, 
+                                       /* x=0.68*/  1.6616947609601311, 
+                                       /* x=0.69*/  1.682029769280133, 
+                                       /* x=0.70*/  1.7022720000001055, 
+                                       /* x=0.71*/  1.7223600227201015, 
+                                       /* x=0.72*/  1.7422251110400993, 
+                                       /* x=0.73*/  1.7617920489601087, 
+                                       /* x=0.74*/  1.7809799372800814, 
+                                       /* x=0.75*/  1.7997030000000898, 
+                                       /* x=0.76*/  1.8178713907201, 
+                                       /* x=0.77*/  1.8353919990401195, 
+                                       /* x=0.78*/  1.85216925696011, 
+                                       /* x=0.79*/  1.8681059452800994, 
+                                       /* x=0.80*/  1.8831040000000847, 
+                                       /* x=0.81*/  1.897065318720074, 
+                                       /* x=0.82*/  1.9098925670401137, 
+                                       /* x=0.83*/  1.921489984960104, 
+                                       /* x=0.84*/  1.931764193280106, 
+                                       /* x=0.85*/  1.940625000000086, 
+                                       /* x=0.86*/  1.9479862067200955, 
+                                       /* x=0.87*/  1.9537664150401213, 
+                                       /* x=0.88*/  1.9578898329600989, 
+                                       /* x=0.89*/  1.9602870812801143, 
+                                       /* x=0.90*/  1.960896000000119, 
+                                       /* x=0.91*/  1.9596624547200818, 
+                                       /* x=0.92*/  1.9565411430400914, 
+                                       /* x=0.93*/  1.9514964009601528, 
+                                       /* x=0.94*/  1.9445030092801048, 
+                                       /* x=0.95*/  1.9355470000001276, 
+                                       /* x=0.96*/  1.92462646272012, 
+                                       /* x=0.97*/  1.9117523510400858, 
+                                       /* x=0.98*/  1.8969492889601298, 
+                                       /* x=0.99*/  1.8802563772801548, 
+                                       /* x=1.00*/  1.86172800000017, 
+                                       /* x=1.01*/  1.8414346307201441, 
+                                       /* x=1.02*/  1.8194636390400944, 
+                                       /* x=1.03*/  1.7959200969601596, 
+                                       /* x=1.04*/  1.7709275852801198, 
+                                       /* x=1.05*/  1.7446290000001738, 
+                                       /* x=1.06*/  1.7171873587201247, 
+                                       /* x=1.07*/  1.6887866070401714, 
+                                       /* x=1.08*/  1.659632424960222, 
+                                       /* x=1.09*/  1.6299530332800884, 
+                                       /* x=1.10*/  1.6000000000001648
+                       };
+
+                       double x=0.6;
+                       for (int i=0; i<answer2.length; i++) {
+                               assertEquals("r2 different at x=" + x, PolyInterpolator.eval(x, r2), answer2[i],0.00001);
+                               x+=0.01;
+                       }
+
+               }
+       }
+}
diff --git a/core/test/net/sf/openrocket/util/QuaternionTest.java b/core/test/net/sf/openrocket/util/QuaternionTest.java
new file mode 100644 (file)
index 0000000..26a2dc2
--- /dev/null
@@ -0,0 +1,48 @@
+package net.sf.openrocket.util;
+
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+
+public class QuaternionTest {
+
+       @Test
+       public void oldMainTest() {
+
+               // This is normalized already
+               Quaternion q = new Quaternion(0.237188, 0.570190, -0.514542, 0.594872);
+               assertEquals( 1.0, q.norm(), 0.01);
+
+               q.normalize();
+               assertEquals( 0.237188, q.getW(), 0.00001);
+               assertEquals( 0.570190, q.getX(), 0.00001);
+               assertEquals( -0.514542, q.getY(), 0.00001);
+               assertEquals( 0.594872, q.getZ(), 0.00001);
+               assertEquals( 1.0, q.norm(), 0.01);
+
+               Coordinate c = new Coordinate(148578428.914, 8126778.954, -607.741);
+
+               Coordinate r = q.rotate(c);
+
+               System.out.println("Rotated: " + q.rotate(c));
+
+               assertEquals( -42312599.537, r.x, 0.001);
+               assertEquals( -48162747.551, r.y, 0.001);
+               assertEquals( 134281904.197, r.z, 0.001);
+
+               c = new Coordinate(0,1,0);
+               Coordinate rot = new Coordinate(Math.PI/4,0,0);
+
+               System.out.println("Before: "+c);
+               c = Quaternion.rotation(rot).invRotate(c);
+               System.out.println("After: "+c);
+               
+               assertEquals( 0.0, c.x, 0.001);
+               assertEquals( 0.707, c.y, 0.001);
+               assertEquals( -0.707, c.z, 0.001);
+
+
+       }
+
+
+}
diff --git a/core/test/net/sf/openrocket/util/SimpleStackTest.java b/core/test/net/sf/openrocket/util/SimpleStackTest.java
new file mode 100644 (file)
index 0000000..16cd312
--- /dev/null
@@ -0,0 +1,43 @@
+package net.sf.openrocket.util;
+
+import java.util.NoSuchElementException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import org.junit.Test;
+
+public class SimpleStackTest {
+
+       @Test(expected=NoSuchElementException.class)
+       public void testEmptyStack() {
+               SimpleStack<Integer> s = new SimpleStack<Integer>();
+               
+               assertNull(s.peek());
+               
+               s.pop();
+       }
+       
+       @Test
+       public void testPushAndPop() {
+               
+               SimpleStack<Integer> s = new SimpleStack<Integer>();
+               
+               for( int i = 0; i< 10; i++ ) {
+                       s.push(i);
+                       assertEquals(i+1, s.size());
+               }
+       
+               for( int i=9; i>= 0; i-- ) {
+                       assertEquals( i, s.peek().intValue() );
+                       Integer val = s.pop();
+                       assertEquals( i, val.intValue() );
+                       assertEquals( i, s.size() );
+               }
+               
+               assertNull( s.peek() );
+               assertEquals( 0, s.size() );
+               
+       }
+       
+}
index 8ac8319d0aa6b998702aa0cd98fa13dd022f9d64..4c040fbbe32f8e61e3e1bac1eb9c04bedcf09ced 100644 (file)
@@ -2,13 +2,36 @@ package net.sf.openrocket.util;
 
 import static java.lang.Math.PI;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertArrayEquals;
 
+import java.nio.charset.Charset;
 import java.util.Random;
 
 import org.junit.Test;
 
 public class TextUtilTest {
        
+       @Test
+       public void testConvertStringToBytes() {
+               
+               Charset us_ascii = Charset.forName("US-ASCII");
+               
+               byte[] ZIP_SIGNATURE_CORRECT = "PK".getBytes(us_ascii);
+               byte[] ZIP_SIGNATURE_TEST = TextUtil.convertStringToBytes( "PK", us_ascii);
+               
+               assertArrayEquals( ZIP_SIGNATURE_CORRECT, ZIP_SIGNATURE_TEST );
+               
+               byte[] OPENROCKET_SIGNATURE_CORRECT = "<openrocket".getBytes(us_ascii);
+               byte[] OPENROCKET_SIGNATURE_TEST = TextUtil.convertStringToBytes( "<openrocket", us_ascii);
+
+               assertArrayEquals( OPENROCKET_SIGNATURE_CORRECT, OPENROCKET_SIGNATURE_TEST);
+               
+               byte[] ROCKSIM_SIGNATURE_CORRECT = "<RockSimDoc".getBytes(us_ascii);
+               byte[] ROCKSIM_SIGNATURE_TEST = TextUtil.convertStringToBytes( "<RockSimDoc", us_ascii);
+               
+               assertArrayEquals( ROCKSIM_SIGNATURE_CORRECT, ROCKSIM_SIGNATURE_TEST );
+       }
+       
        @Test
        public void testHexString() {
                assertEquals("", TextUtil.hexString(new byte[0]));
diff --git a/core/test/net/sf/openrocket/util/TransformationTest.java b/core/test/net/sf/openrocket/util/TransformationTest.java
new file mode 100644 (file)
index 0000000..cb63b3f
--- /dev/null
@@ -0,0 +1,81 @@
+package net.sf.openrocket.util;
+
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+
+public class TransformationTest {
+       @Test
+       public void oldMainTest() {
+               Transformation t;
+
+               t = new Transformation();
+               {
+                       Coordinate a = t.transform( new Coordinate(1,0,0) );
+                       assertEquals( new Coordinate(1,0,0), a );
+                       a = t.transform( new Coordinate(0,1,0) );
+                       assertEquals( new Coordinate(0,1,0), a );
+                       a = t.transform( new Coordinate(0,0,1) );
+                       assertEquals( new Coordinate(0,0,1), a );
+               }
+
+               t = new Transformation(1,2,3);
+               {
+                       Coordinate a = t.transform( new Coordinate(1,0,0) );
+                       assertEquals( new Coordinate(2,2,3), a );
+                       a = t.transform( new Coordinate(0,1,0) );
+                       assertEquals( new Coordinate(1,3,3), a );
+                       a = t.transform( new Coordinate(0,0,1) );
+                       assertEquals( new Coordinate(1,2,4), a );
+               }
+               
+               
+               t = new Transformation(new Coordinate(2,3,4));
+               {
+                       Coordinate a = t.transform( new Coordinate(1,0,0) );
+                       assertEquals( new Coordinate(3,3,4), a );
+                       a = t.transform( new Coordinate(0,1,0) );
+                       assertEquals( new Coordinate(2,4,4), a );
+                       a = t.transform( new Coordinate(0,0,1) );
+                       assertEquals( new Coordinate(2,3,5), a );
+               }
+
+               t = Transformation.rotate_y(0.01);
+               {
+                       Coordinate a = t.transform( new Coordinate(1,0,0) );
+                       // we need to test individual coordinates due to error.
+                       assertEquals( 1, a.x, .001);
+                       assertEquals( 0, a.y, .001);
+                       assertEquals( -.01, a.z, .001);
+                       a = t.transform( new Coordinate(0,1,0) );
+                       assertEquals( new Coordinate(0,1,0), a );
+                       a = t.transform( new Coordinate(0,0,1) );
+                       // we need to test individual coordinates due to error.
+                       assertEquals( .01, a.x, .001);
+                       assertEquals( 0, a.y, .001);
+                       assertEquals( 1, a.z, .001);
+               }
+
+               t = new Transformation(-1,0,0);
+               t = t.applyTransformation(Transformation.rotate_y(0.01));
+               t = t.applyTransformation(new Transformation(1,0,0));
+               {
+                       Coordinate a = t.transform( new Coordinate(1,0,0) );
+                       // we need to test individual coordinates due to error.
+                       assertEquals( 1, a.x, .001);
+                       assertEquals( 0, a.y, .001);
+                       assertEquals( -.02, a.z, .001);
+                       a = t.transform( new Coordinate(0,1,0) );
+                       assertEquals( 0, a.x, .001);
+                       assertEquals( 1, a.y, .001);
+                       assertEquals( -.01, a.z, .001);
+                       a = t.transform( new Coordinate(0,0,1) );
+                       // we need to test individual coordinates due to error.
+                       assertEquals( .01, a.x, .001);
+                       assertEquals( 0, a.y, .001);
+                       assertEquals( .99, a.z, .001);
+               }
+       }
+
+
+}
index 7275e6e1ace6aefb0fe85a28bcadb5df29a0663d..83b20e5cfb78d7e04e5e8432d4a158ba0e479d62 100644 (file)
@@ -80,19 +80,30 @@ header("Content-type: text/plain");
 $version = $_GET["version"];
 $updates = "";
 
-$unstable = "12.03";
+$unstable = "12.09";
 $stable = "1.0.0";
 
-if (preg_match("/^1\.1\.9$/", $version)) {
+if (preg_match("/^12.03$/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
+    "5: Fractional inch unit\n" .
+    "4: Printing centering rings\n" .
+    "4: Translations to Czech and Polish\n" .
+    "";
+} else if (preg_match("/^1\.1\.9$/", $version)) {
+  $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "5: Configurable stage separation\n" .
-    "5: Guided tours\n" .
     "4: Freeform fin import from images\n" .
     "4: Translations to Italian and Russian\n" .
     "";
 } else if (preg_match("/^1\.1\.8$/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "6: Additional template printing\n" .
     "5: Geodetic computations\n" .
@@ -115,6 +126,8 @@ if (preg_match("/^1\.1\.9$/", $version)) {
     "";
 } else if (preg_match("/^1\.1\.6$/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "8: Automatic rocket design optimization\n" .
     "6: Additional template printing\n" .
@@ -122,6 +135,8 @@ if (preg_match("/^1\.1\.9$/", $version)) {
     "";
 } else if (preg_match("/^1\.1\.5$/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "8: Automatic rocket design optimization\n" .
     "6: Initial localization support\n" .
@@ -132,6 +147,8 @@ if (preg_match("/^1\.1\.9$/", $version)) {
     "";
 } else if (preg_match("/^1\.1\.4$/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "8: Automatic rocket design optimization\n" .
     "6: Initial localization support\n" .
@@ -140,6 +157,8 @@ if (preg_match("/^1\.1\.9$/", $version)) {
     "";
 } else if (preg_match("/^1\.1\.3$/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "8: Automatic rocket design optimization\n" .
     "7: Initial printing support\n" .
@@ -149,6 +168,8 @@ if (preg_match("/^1\.1\.9$/", $version)) {
     "";
 } else if (preg_match("/^1\.1\.[12]$/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "8: Automatic rocket design optimization\n" .
     "6: Initial printing support\n" .
@@ -159,6 +180,8 @@ if (preg_match("/^1\.1\.9$/", $version)) {
     "";
 } else if (preg_match("/^1\.1\.0$/", $version)) {
   $updates = "Version: " . $unstable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "8: Automatic rocket design optimization\n" .
     "6: Initial printing support\n" .
@@ -170,12 +193,16 @@ if (preg_match("/^1\.1\.9$/", $version)) {
     "";
 } else if (preg_match("/^0\.9\.6/", $version)) {
   $updates = "Version: " . $stable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "6: Hundreds of new thrustcurves\n" .
     "5: Bug fixes\n" .
     "";
 } else if (preg_match("/^0\.9\.[45]/", $version)) {
   $updates = "Version: " . $stable . "\n" .
+    "10: 3D design view\n" .
+    "9: Component presets\n" .
     "8: Writing RKT files\n" .
     "7: Hundreds of new thrustcurves\n" .
     "6: Aerodynamic computation updates\n" .
index 4418d3c5b52b8dfbc5f40b3ec5ce15555d882fd4..a99f29d2bcbd022e1da71d48aa315844d4b00018 100644 (file)
   <div class="content">
 <div class="news">
       <h2>Recent news:</h2>
+  <p><span class="date">16.9.2012:</span> Version 12.09 is
+   <a href="download.html">released</a>!</p>
+  <p>This version contains a huge number of new features by many contributors:</p>
+  <ul>
+    <li>3D rocket design view</li>
+    <li>Component Presets</li>
+    <li>Custom expressions in simulations</li>
+    <li>Printing for centering ring and clustered centering ring components</li>
+    <li>Support simple arthmatic in dimension entry</li>
+    <li>Support deploying recovery device at stage separation</li>
+    <li>Support for fractional inches (1/64) for unit length</li>
+    <li>Added preference for windspeed units separately</li>
+    <li>Added "most recently used files" in File Menu</li>
+    <li>Improved printed accurracy in fin marking guide</li>
+    <li>Calibration rulers added to printed templates</li>
+    <li>Translations in Czech and Polish, numerous updates</li>
+  </ul>
   <p><span class="date">10.3.2012:</span> Version 12.03 for desktop
     and Android is <a href="download.html">released</a>!</p>
   <p>In this release the version numbering scheme has been changed.
     events, guided help tours and displaying the computed motor
     designation class.  The application has also been translated to
     Italian by Mauro Biasutti and Russian by the Sky Dart Team.</p>
-  <p><span class="date">24.11.2011:</span> Version 1.1.9 is
-    <a href="download.html">released</a>!</p>
-  <p>For this version Richard Graham has implemented geodetic
-    computation methods, which take into account the curvature of the
-    Earth and the coriolis effect.  The computation method is selected
-    by the <em>Geodetic calculations</em> option in the simulation
-    options.  It's not <em>(yet)</em> a full spherical computation model, but
-    should be accurate enough for almost all sub-orbital needs.</p>
-  <p>Doug Pedrick has also enhanced the printing system with the
-    ability to print fin positioning guides, transition templates and
-    nose cone profiles.  Other smaller enhancements and bug fixes are
-    also included.</p>
-  <p><span class="date">25.8.2011:</span> Version 1.1.8 is
-    <a href="download.html">released</a>!</p>
-  <p>This release contains bug fixes to the optimization methods.
-    It also contains a workaround to a JRE bug that prevents running
-    OpenRocket on some builds of Java 7.</p>
-  <p>The web pages have also been somewhat updated and Boris du Reau has
-    created <a href="http://openrocket.trans.free.fr/">a separate site</a>
-    for coordinating the localization efforts for OpenRocket.</p>
 </div>
     <div class="contentholder">
       <h2>Ready packages</h2>
         <a href="http://sourceforge.net/donate/index.php?group_id=260357"><img src="project-support.jpg" width="88" height="32" alt="Support This Project" /></a>
       </div>
         <div class="downloadbox">
-    <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/12.03/OpenRocket-12.03.jar/download">
+    <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/12.09/OpenRocket-12.09.jar/download">
       <strong>Download now!</strong>
-      <span>OpenRocket-12.03.jar</span>
+      <span>OpenRocket-12.09.jar</span>
     </a>
     <span class="alternative">
-      <a href="https://sourceforge.net/projects/openrocket/files/openrocket/12.03/ReleaseNotes/view">Release notes</a> |
-            <a href="https://sourceforge.net/projects/openrocket/files/openrocket/12.03/OpenRocket-12.03-src.zip/download">Source code</a>
+      <a href="https://sourceforge.net/projects/openrocket/files/openrocket/12.09/ReleaseNotes/view">Release notes</a> |
+            <a href="https://sourceforge.net/projects/openrocket/files/openrocket/12.09/OpenRocket-12.09-src.zip/download">Source code</a>
     </span>
   </div>
       <p>OpenRocket can be started in most graphical environments (including
        Windows) by double-clicking the package icon.  No installation is
        required.</p>
       <p>From the command line OpenRocket can be started by
-      <span class="command">java -jar OpenRocket-12.03.jar</span></p>
+      <span class="command">java -jar OpenRocket-12.09.jar</span></p>
       <h3>Android version</h3>
       <p>The Android version allows opening OpenRocket files, viewing
         simulations and motors.  Later versions will allow running
index c42a1b1bf99319f3eae2ea39eb37827203973571..f2bfdce5c9e1365c397304899016cfb05df80fe1 100644 (file)
     <h2>Introduction</h2>
     <div class="rightpane">
         <div class="downloadbox">
-    <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/12.03/OpenRocket-12.03.jar/download">
+    <a class="main" href="https://sourceforge.net/projects/openrocket/files/openrocket/12.09/OpenRocket-12.09.jar/download">
       <strong>Download now!</strong>
-      <span>OpenRocket-12.03.jar</span>
+      <span>OpenRocket-12.09.jar</span>
     </a>
     <span class="alternative">
-      <a href="https://sourceforge.net/projects/openrocket/files/openrocket/12.03/ReleaseNotes/view">Release notes</a> |
+      <a href="https://sourceforge.net/projects/openrocket/files/openrocket/12.09/ReleaseNotes/view">Release notes</a> |
             <a href="download.html">Other versions</a>
     </span>
   </div>
     <div class="clear"></div>
 <div class="news">
       <h2>News</h2>
+  <p><span class="date">16.9.2012:</span> Version 12.09 is
+   <a href="download.html">released</a>!</p>
+  <p>This version contains a huge number of new features by many contributors:</p>
+  <ul>
+    <li>3D rocket design view</li>
+    <li>Component Presets</li>
+    <li>Custom expressions in simulations</li>
+    <li>Printing for centering ring and clustered centering ring components</li>
+    <li>Support simple arthmatic in dimension entry</li>
+    <li>Support deploying recovery device at stage separation</li>
+    <li>Support for fractional inches (1/64) for unit length</li>
+    <li>Added preference for windspeed units separately</li>
+    <li>Added "most recently used files" in File Menu</li>
+    <li>Improved printed accurracy in fin marking guide</li>
+    <li>Calibration rulers added to printed templates</li>
+    <li>Translations in Czech and Polish, numerous updates</li>
+  </ul>
   <p><span class="date">10.3.2012:</span> Version 12.03 for desktop
     and Android is <a href="download.html">released</a>!</p>
   <p>In this release the version numbering scheme has been changed.
index 336b8b5f723f6a96df0a37f7cdd41d0e7ea61adc..aed535f127305ff863feeb6498a39592b319cacd 100644 (file)
@@ -62,7 +62,7 @@
         <ol>
           <li>Go to <em>Settings</em> &rarr; <em>Applications</em> and
             check <em>Unknown sources</em>.</li>
-         <li>Download <a href="https://sourceforge.net/projects/openrocket/files/openrocket/${version}/OpenRocket-Android-${version}.apk/download">OpenRocket-Android-<use version>.apk</a>
+         <li>Download <a href="https://sourceforge.net/projects/openrocket/files/openrocket/${androidversion}/OpenRocket-Android-${androidversion}.apk/download">OpenRocket-Android-<use androidversion>.apk</a>
            on your device and accept installation.</li>
 
         </ol>
index d2aedaa14115d9afb26c1dfe561057a7c440d842..5e6d4bccb16afb79451b4c454459848a76bfacf3 100644 (file)
@@ -1,4 +1,5 @@
-<set version="12.03">
+<set version="12.09">
+<set androidversion="12.03">
 
 <def name="downloadbox">
   <div class="downloadbox">
index be4153e21ef800766931d54604d289cd0b364511..538c9136d4dfd7ed1bb7117926551ef7796210d1 100644 (file)
@@ -9,6 +9,27 @@
 
   <!--- Remember to move the position of "onlyrecent" below! --->
 
+  <p><span class="date">16.9.2012:</span> Version 12.09 is
+   <a href="download.html">released</a>!</p>
+
+  <p>This version contains a huge number of new features by many contributors:</p>
+
+  <ul>
+    <li>3D rocket design view</li>
+    <li>Component Presets</li>
+    <li>Custom expressions in simulations</li>
+    <li>Printing for centering ring and clustered centering ring components</li>
+    <li>Support simple arthmatic in dimension entry</li>
+    <li>Support deploying recovery device at stage separation</li>
+    <li>Support for fractional inches (1/64) for unit length</li>
+    <li>Added preference for windspeed units separately</li>
+    <li>Added "most recently used files" in File Menu</li>
+    <li>Improved printed accurracy in fin marking guide</li>
+    <li>Calibration rulers added to printed templates</li>
+    <li>Translations in Czech and Polish, numerous updates</li>
+  </ul>
+
+
   <p><span class="date">10.3.2012:</span> Version 12.03 for desktop
     and Android is <a href="download.html">released</a>!</p>
 
     designation class.  The application has also been translated to
     Italian by Mauro Biasutti and Russian by the Sky Dart Team.</p>
 
+
+  <if not onlyrecent><!--- Older items not shown on download page:  --->
+
+
   <p><span class="date">24.11.2011:</span> Version 1.1.9 is 
     <a href="download.html">released</a>!</p>
 
@@ -56,9 +81,6 @@
     for coordinating the localization efforts for OpenRocket.</p>
   
 
-  <if not onlyrecent><!--- Older items not shown on download page:  --->
-
-
   <p><span class="date">12.8.2011:</span> Version 1.1.7 is 
     <a href="download.html">released</a>!</p>