/* * 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.jecelyin.widget; import android.app.LocalActivityManager; import android.content.Context; import android.graphics.Color; import android.graphics.Rect; import android.text.SpannableString; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.HorizontalScrollView; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import com.jecelyin.editor.JecEditor; import com.jecelyin.editor.R; import com.jecelyin.widget.TabWidget.OnMenuClickListener; import jecelyin.android.compat.JecOnTextChangedListener; import jecelyin.android.compat.TextViewBase; import java.util.ArrayList; /** * Container for a tabbed window view. This object holds two children: a set of * tab labels that the user clicks to select a specific tab, and a FrameLayout * object that displays the contents of that page. The individual elements are * typically controlled using this container object, rather than setting values * on the child elements themselves. * * <p> * See the <a href="{@docRoot} * resources/tutorials/views/hello-tabwidget.html">Tab Layout tutorial</a>. * </p> */ public class TabHost extends LinearLayout { private TabWidget mTabWidget; private LinearLayout mTabContent; private JecEditor mJecEditor; private ArrayList<TextViewBase> mTabSpecs = new ArrayList<TextViewBase>(); /** * This field should be made private, so it is hidden from the SDK. {@hide * } */ protected int mCurrentTab = -1; private TextViewBase mCurrentEditText = null; /** * This field should be made private, so it is hidden from the SDK. {@hide * } */ protected LocalActivityManager mLocalActivityManager = null; private OnTabChangeListener mOnTabChangeListener; private HorizontalScrollView mScroller; private OnTabCloseListener mOnTabCloseListener; private JecOnTextChangedListener mOnTextChangedListener = null; //是否自动创建tab public static boolean autoNewTab = true; public void setOnTextChangedListener(JecOnTextChangedListener l) { mOnTextChangedListener = l; } public TabHost(Context context) { super(context); // initTabHost(); } public TabHost(Context context, AttributeSet attrs) { super(context, attrs); // initTabHost(); } public void initTabHost(JecEditor parent) { setFocusableInTouchMode(true); setDescendantFocusability(FOCUS_AFTER_DESCENDANTS); mJecEditor = parent; mTabContent = (LinearLayout) mJecEditor.findViewById(R.id.editorBodyLinearLayout); mCurrentTab = -1; mCurrentEditText = null; mTabWidget = (TabWidget) this.findViewById(R.id.tabWidgets); mTabWidget.setOnMenuClickListener(mOnMenuClickListener); mScroller = (HorizontalScrollView) this.findViewById(R.id.tabScroller); ImageButton mNewTabButton = (ImageButton) this.findViewById(R.id.add_new_tab_btn); mNewTabButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { addTab(""); } }); } private TextView getTabTitleView() { if(mCurrentTab < 0) return null; View mView = mTabWidget.getChildTabViewAt(mCurrentTab); if(mView == null) return null; return (TextView)mView.findViewById(R.id.title); } public void setTitle(String title) { TextView mTitleView = getTabTitleView(); if(mTitleView == null) return; mTitleView.setText(title); mTabSpecs.get(mCurrentTab).setTitle(title); } /** * Add a tab. * * @param tabSpec * Specifies how to create the indicator and content. */ public void addTab(String path) { if(mTabSpecs.size() > 0) { int index=0; for(TextViewBase et : mTabSpecs) { if("".equals(et.getPath()) && et.getText().length() == 0) {//空白文档,没有内容时,则不打开新文件 setCurrentTab(index); return; } else if(!"".equals(path) && path.equals(et.getPath())) { //已经打开了 setCurrentTab(index); return; } index++; } } View tabIndicator = createIndicatorView(); mTabWidget.addView(tabIndicator); mTabWidget.setTabSelectionListener(new TabWidget.OnTabSelectionChanged() { //选中标签时的事件 public void onTabSelectionChanged(int tabIndex) { if(tabIndex != mCurrentTab) { setCurrentTab(tabIndex); if(mOnTabChangeListener != null) mOnTabChangeListener.onTabChanged(tabIndex); } else { //关闭当前标签 if(mOnTabCloseListener != null) { mOnTabCloseListener.onTabClose(TabWidget.MENU_ACTION_CLOSE_ONE, tabIndex, tabIndex); } } } }); TextViewBase jet = createEditText(); mTabSpecs.add(jet); mTabContent.addView(jet); setCurrentTab(mTabSpecs.size() - 1); setTitle(getResources().getString(R.string.new_filename)); } public int closeTab(int tabId) { if(tabId >= mTabSpecs.size()) return -1; TextViewBase edittxt = mTabSpecs.get(tabId); mTabWidget.removeViewAt(tabId); mTabContent.removeView(edittxt); mTabSpecs.remove(tabId); edittxt=null; if(tabId == 0) { if(mTabWidget.getTabCount() == 0) { mCurrentTab = -1; if(autoNewTab) addTab(""); } else { mCurrentTab = -1; setCurrentTab(0); } } else { setCurrentTab(--tabId); } System.gc(); return mCurrentTab; } public void setTabStatus(boolean ischanged) { TextView mTitleView = getTabTitleView(); if(mTitleView == null) return; CharSequence text = (CharSequence) mTitleView.getText(); if(!ischanged) { mTitleView.setText(text.toString()); return; } SpannableString span = new SpannableString(text); ForegroundColorSpan fcs = new ForegroundColorSpan(Color.RED); span.setSpan(fcs, 0, text.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE); mTitleView.setText(span); } private TextViewBase createEditText() { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); View tabIndicator = inflater.inflate(R.layout.edit_text, mTabContent, false); TextViewBase mEditText = (TextViewBase) tabIndicator.findViewById(R.id.text_content); mEditText.addJecOnTextChangedListener(new JecOnTextChangedListener() { @Override public void onTextChanged(TextViewBase mEditText) { if(mOnTextChangedListener != null) mOnTextChangedListener.onTextChanged(mEditText); setTabStatus(mEditText.isTextChanged()); } }); mJecEditor.registerForContextMenu(mEditText); return mEditText; } private View createIndicatorView() { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); View tabIndicator = inflater.inflate(R.layout.tab_indicators, mTabWidget, false); //TextView tv = (TextView) tabIndicator.findViewById(R.id.title); return tabIndicator;// .findViewById(R.id.tab_indicator_layout); } public TextViewBase getCurrentEditText() { return mCurrentEditText; } public void setCurrentTab(int index) { if(index < 0 || index >= mTabSpecs.size()) { return; } if(index == mCurrentTab) { return; } // notify old tab content if(mCurrentTab != -1 && mCurrentTab < mTabSpecs.size()) { mTabSpecs.get(mCurrentTab).hide(); } mCurrentTab = index; // tab content mCurrentEditText = mTabSpecs.get(index); mCurrentEditText.show(); if(mOnTabChangeListener != null) mOnTabChangeListener.onTabChanged(mCurrentTab); //切换到最前 scrollToSelected(); // Call the tab widget's focusCurrentTab(), instead of just // selecting the tab. //mTabWidget.focusCurrentTab(mCurrentTab); /*if(!mTabWidget.hasFocus()) { // if the tab widget didn't take focus (likely because we're in // touch mode) // give the current tab content view a shot // 不能使用,避免输入法弹出来 // mCurrentEditText.requestFocus(); }*/ // mTabContent.requestFocus(View.FOCUS_FORWARD); // invokeOnTabChangeListener(); } /** * Register a callback to be invoked when the selected state of any of the * items in this list changes * * @param l * The callback that will run */ public void setOnTabChangedListener(OnTabChangeListener l) { mOnTabChangeListener = l; } /** * 标签关闭前要触发的事件 */ public interface OnTabCloseListener { /** * 安全地关闭标签 * @param action * @param startIndex 触发动作时的标签位置 * @param curIndex 当前标签位置 */ public void onTabClose(int action, int startIndex, int curIndex); } public void setOnTabCloseListener(OnTabCloseListener l) { mOnTabCloseListener = l; } /** * Interface definition for a callback to be invoked when tab changed */ public interface OnTabChangeListener { void onTabChanged(int tabId); } private void scrollToSelected() { mScroller.post(new Runnable() { @Override public void run() { if(mCurrentTab < 0) { return; } View tab = mTabWidget.getChildTabViewAt(mCurrentTab); Rect tabRect = new Rect(); tab.getGlobalVisibleRect(tabRect); Rect scrollerRect = new Rect(); mScroller.getGlobalVisibleRect(scrollerRect); int width = tab.getWidth(); int leftMargin = ((LinearLayout.LayoutParams)tab.getLayoutParams()).leftMargin; int left = width * mCurrentTab + leftMargin * mCurrentTab; left -= (int)(width*0.8F); int top = mScroller.getHeight() + mScroller.getPaddingTop(); mScroller.setSmoothScrollingEnabled(true); //move current tab to center mScroller.smoothScrollTo(left, top); mTabWidget.focusCurrentTab(mCurrentTab); } }); } public int getTabCount() { return mTabWidget.getTabCount(); } public void setAutoNewTab(boolean newtab) { autoNewTab = newtab; } public void iterCloseTab(int action, int index, int count) { //int count = mTabWidget.getTabCount(); int start = action==TabWidget.MENU_ACTION_CLOSE_RIGHT ? index+1 : 0; while(--count >= start) { if(action == TabWidget.MENU_ACTION_CLOSE_OTHER && count==index) continue; if(mOnTabCloseListener != null) { mOnTabCloseListener.onTabClose(action, index, count); } break; } /*if(autoNewTab && mTabWidget.getTabCount() < 1) { addTab(""); }*/ } private OnMenuClickListener mOnMenuClickListener = new OnMenuClickListener() { @Override public void onMenuClick(int action, int index) { autoNewTab = true; iterCloseTab(action, index, mTabWidget.getTabCount()); } }; public ArrayList<String> getAllPath() { ArrayList<String> ret = new ArrayList<String>(); for(TextViewBase jec :mTabSpecs) { ret.add(jec.getPath()); } return ret; } public boolean isChanged(String path) { for(TextViewBase jec :mTabSpecs) { if(jec.getPath().equals(path)) return jec.isTextChanged(); } return false; } }